The compiler is not catching this case because of the middleman that is the 
generic alias type (which is probably an easy fix, though a bit arbitrary). 
This works:
    
    
    import strutils
    
    template typeOrSeqType(U: type): type = U or seq[U]
    
    proc f[T](x: typeOrSeqType(proc(y: string): T)) =
        discard
    
    let p = proc(y: string): int {.closure.} = parseInt(y)
    
    f(p)
    
    
    Run

Otherwise though, in these cases where it's hard for the compiler to 
understand, it's possible to write small macros, usually templates are enough 
but this is one of the cases where the AST substitution is bottom-up and it's 
uglier.
    
    
    import macros, strutils
    
    type TypeOrSeqType[U] {.used.} = U | seq[U] # this definition does not 
change anything, TypeOrSeqType just needs to be defined to compile
    
    macro expandTypeOrSeqType(pr) =
      proc process(n: NimNode): NimNode =
        result = n
        for i in 1 ..< n[3].len:
          let paramType = n[3][i][^2]
          if paramType.kind == nnkBracketExpr and 
paramType[0].eqIdent("TypeOrSeqType"):
            let (a, b) = (copy(n), copy(n))
            a[3][i][^2] = paramType[1]
            b[3][i][^2] = newTree(nnkBracketExpr, ident"seq", paramType[1])
            return newStmtList(process(a), process(b))
      
      result = process(pr)
    
    proc f[T](x: TypeOrSeqType[proc(y: string): T]) {.expandTypeOrSeqType.} =
        discard
    
    let p = proc(y: string): int = parseInt(y)
    
    f(p)
    
    proc foo(a: TypeOrSeqType[int], b: TypeOrSeqType[string]) 
{.expandTypeOrSeqType.} = discard
    
    foo(3, "abc")
    foo(@[3], "abc")
    foo(3, @["abc"])
    foo(@[3], @["abc"])
    
    
    Run

Reply via email to