diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 4a3be00278..2d3cf562b0 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1977,7 +1977,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of skParam: if sym.loc.r == nil or sym.loc.t == nil: #echo "FAILED FOR PRCO ", p.prc.name.s - internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id) + #debug p.prc.typ.n + #echo renderTree(p.prc.ast, {renderIds}) + internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id) putLocIntoDest(p, d, sym.loc) else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol") of nkNilLit: diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 78cc691c06..946be68f82 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -29,7 +29,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = of nkSym: var s = templ.sym if s.owner.id == c.owner.id: - if s.kind == skParam: + if s.kind == skParam and sfGenSym notin s.flags: let x = actual.sons[s.position] if x.kind == nkArgList: for y in items(x): result.add(y) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 623f9b6339..bb82db292a 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -35,6 +35,7 @@ type inTryStmt*: int # whether we are in a try statement; works also # in standalone ``except`` and ``finally`` next*: PProcCon # used for stacking procedure contexts + wasForwarded*: bool # whether the current proc has a separate header TInstantiationPair* = object genericSym*: PSym diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f9889eee19..a3ae0263dd 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -109,9 +109,16 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = # if a proc accesses a global variable, it is not side effect free: if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect) - elif s.kind == skParam and s.typ.kind == tyStatic and s.typ.n != nil: - # XXX see the hack in sigmatch.nim ... - return s.typ.n + elif s.kind == skParam: + if s.typ.kind == tyStatic and s.typ.n != nil: + # XXX see the hack in sigmatch.nim ... + return s.typ.n + elif sfGenSym in s.flags and c.p.wasForwarded: + # gensym'ed parameters that nevertheless have been forward declared + # need a special fixup: + let realParam = c.p.owner.typ.n[s.position+1] + internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam + return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info) result = newSymNode(s, n.info) # We cannot check for access to outer vars for example because it's still # not sure the symbol really ends up being used: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 44f14afd8c..3b90337e50 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -982,7 +982,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # process parameters: if n.sons[paramsPos].kind != nkEmpty: semParamList(c, n.sons[paramsPos], gp, s) - if sonsLen(gp) > 0: + if sonsLen(gp) > 0: if n.sons[genericParamsPos].kind == nkEmpty: # we have a list of implicit type parameters: n.sons[genericParamsPos] = gp @@ -1049,6 +1049,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics: if not usePseudoGenerics: paramsTypeCheck(c, s.typ) pushProcCon(c, s) + c.p.wasForwarded = proto != nil maybeAddResult(c, s, n) if sfImportc notin s.flags: # no semantic checking for importc: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 81e4f24635..e2c46d3ab1 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -127,7 +127,7 @@ proc getIdentNode(c: var TemplCtx, n: PNode): PNode = proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} = result = n.kind == nkSym and n.sym.kind == skParam and - n.sym.owner == c.owner + n.sym.owner == c.owner and sfGenSym notin n.sym.flags proc semTemplBody(c: var TemplCtx, n: PNode): PNode @@ -246,8 +246,8 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode = n.sons[i] = semTemplBody(c, n.sons[i]) closeScope(c) -proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind) = - for i in countup(0, sonsLen(n) - 1): +proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) = + for i in countup(start, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a) @@ -348,6 +348,10 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1]) of nkVarSection: semTemplSomeDecl(c, n, skVar) of nkLetSection: semTemplSomeDecl(c, n, skLet) + of nkFormalParams: + checkMinSonsLen(n, 1) + n.sons[0] = semTemplBody(c, n.sons[0]) + semTemplSomeDecl(c, n, skParam, 1) of nkConstSection: for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] @@ -485,6 +489,11 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = # process parameters: if n.sons[paramsPos].kind != nkEmpty: semParamList(c, n.sons[paramsPos], gp, s) + # a template's parameters are not gensym'ed even if that was originally the + # case as we determine whether it's a template parameter in the template + # body by the absense of the skGenSym flag: + for i in 1 .. s.typ.n.len-1: + s.typ.n.sons[i].sym.flags.excl sfGenSym if sonsLen(gp) > 0: if n.sons[genericParamsPos].kind == nkEmpty: # we have a list of implicit type parameters: diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim new file mode 100644 index 0000000000..4178812af6 --- /dev/null +++ b/tests/template/tparams_gensymed.nim @@ -0,0 +1,14 @@ + +# bug #1915 + +import macros + +# Test that parameters are properly gensym'ed finally: + +template genNodeKind(kind, name: expr): stmt = + proc name*(children: varargs[PNimrodNode]): PNimrodNode {.compiletime.}= + result = newNimNode(kind) + for c in children: + result.add(c) + +genNodeKind(nnkNone, None) diff --git a/todo.txt b/todo.txt index b2d8b034ed..0209012b40 100644 --- a/todo.txt +++ b/todo.txt @@ -3,6 +3,9 @@ version 0.10 - The bitwise 'not' operator will be renamed to 'bnot' to prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs! +- parameter lists without type end up in 'experimental' +- iterators always require a return type +- revert tuple behaviour - c2nim depends on the compiler - make nimble part of the distribution