From 47e45dee7e9157212995c5769b93713f5a4dd14b Mon Sep 17 00:00:00 2001 From: Adam Strzelecki Date: Thu, 29 Oct 2015 22:10:09 +0100 Subject: [PATCH 1/2] fixes #3496 The problem comes from the fact that macroOrTmpl[...] is transformed by semSubscript which is trying to evaluate macroOrTmpl identifier in place. This is okay for non-generic macros or templates, but wrong for generic ones, that do not have a chance to receive their generic arguments explicitly specified in brackets. Solution: 1. macroOrTmpl[...] where macroOrTmpl is non-generic macro or template, then macroOrTmpl is evaluated before applying brackets. (as before) 2. macroOrTmpl[...] where macroOrTmpl is generic macro or template, then if: a. It comes from macroOrTmpl[...](...) call expr (efInCall), then macroOrTmpl is turned into a symbol (efNoEvaluate) rather than evaluating it in place, then whole bracket expr is returned to semIndirectOp which transforms it to proper generic macro or template call with explicit generic arguments. b. macroOrTmpl[...] does not come from call expr, as above macroOrTmpl is transformed to symbol, then it is transformed into proper generic macro or template call with explicit generic arguments and no normal arguments. --- compiler/semdata.nim | 2 +- compiler/semexprs.nim | 60 +++++++++++++++++++++++++++++--- tests/generics/tgenerictmpl2.nim | 31 +++++++++++++++++ 3 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 tests/generics/tgenerictmpl2.nim diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 9b2f2e2ce7..d350f7bea0 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -46,7 +46,7 @@ type efLValue, efWantIterator, efInTypeof, efWantStmt, efAllowStmt, efDetermineType, efAllowDestructor, efWantValue, efOperand, efNoSemCheck, - efNoProcvarCheck + efNoProcvarCheck, efNoEvaluateGeneric, efInCall TExprFlags* = set[TExprFlag] TTypeAttachedOp* = enum diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f1016595a0..7b3697f8d2 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -102,8 +102,20 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = else: result = newSymNode(s, n.info) else: result = newSymNode(s, n.info) - of skMacro: result = semMacroExpr(c, n, n, s, flags) - of skTemplate: result = semTemplateExpr(c, n, s, flags) + of skMacro: + if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len>0: + markUsed(n.info, s) + styleCheckUse(n.info, s) + result = newSymNode(s, n.info) + else: + result = semMacroExpr(c, n, n, s, flags) + of skTemplate: + if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len>0: + markUsed(n.info, s) + styleCheckUse(n.info, s) + result = newSymNode(s, n.info) + else: + result = semTemplateExpr(c, n, s, flags) of skParam: markUsed(n.info, s) styleCheckUse(n.info, s) @@ -806,10 +818,34 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i]) return semExpr(c, result, flags) else: - n.sons[0] = semExpr(c, n.sons[0]) + n.sons[0] = semExpr(c, n.sons[0], {efInCall}) let t = n.sons[0].typ if t != nil and t.kind == tyVar: n.sons[0] = newDeref(n.sons[0]) + elif n.sons[0].kind == nkBracketExpr: + checkMinSonsLen(n.sons[0], 2) + # We received untransformed bracket expression coming from macroOrTmpl[]. + # Transform it to macro or template call, where first come normal + # arguments, next come generic template arguments. + if n.sons[0].sons[0].kind == nkSym: + let s = n.sons[0].sons[0].sym + if s.kind in {skMacro, skTemplate}: + var sons = newSeq[PNode]() + sons.add n.sons[0].sons[0] + # Normal arguments: + for i in 1.. Date: Mon, 30 May 2016 00:59:02 +0200 Subject: [PATCH 2/2] refactorings --- compiler/semexprs.nim | 97 ++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 4fcedced53..57fb3ceed1 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -717,6 +717,34 @@ proc resolveIndirectCall(c: PContext; n, nOrig: PNode; initCandidate(c, result, t) matches(c, n, nOrig, result) +proc bracketedMacro(n: PNode): PSym = + if n.len >= 1 and n[0].kind == nkSym: + result = n[0].sym + if result.kind notin {skMacro, skTemplate}: + result = nil + +proc semBracketedMacro(c: PContext; outer, inner: PNode; s: PSym; + flags: TExprFlags): PNode = + # We received untransformed bracket expression coming from macroOrTmpl[]. + # Transform it to macro or template call, where first come normal + # arguments, next come generic template arguments. + var sons = newSeq[PNode]() + sons.add inner.sons[0] + # Normal arguments: + for i in 1..