diff --git a/compiler/semdata.nim b/compiler/semdata.nim index b25f72f2d9..91a1ebf86a 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -47,7 +47,7 @@ type efLValue, efWantIterator, efInTypeof, efWantStmt, efAllowStmt, efDetermineType, efAllowDestructor, efWantValue, efOperand, efNoSemCheck, - efNoProcvarCheck, efFromHlo + efNoProcvarCheck, efNoEvaluateGeneric, efInCall, efFromHlo TExprFlags* = set[TExprFlag] TTypeAttachedOp* = enum diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 7135dcf346..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.. 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) @@ -1193,7 +1238,9 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result.add(x[0]) return checkMinSonsLen(n, 2) - n.sons[0] = semExprWithType(c, n.sons[0], {efNoProcvarCheck}) + # make sure we don't evaluate generic macros/templates + n.sons[0] = semExprWithType(c, n.sons[0], + {efNoProcvarCheck, efNoEvaluateGeneric}) let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef}) case arr.kind of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString, @@ -1236,12 +1283,30 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = let s = if n.sons[0].kind == nkSym: n.sons[0].sym elif n[0].kind in nkSymChoices: n.sons[0][0].sym else: nil - if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}: - # type parameters: partial generic specialization - n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s) - result = explicitGenericInstantiation(c, n, s) - elif s != nil and s.kind == skType: - result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) + if s != nil: + case s.kind + of skProc, skMethod, skConverter, skIterator: + # type parameters: partial generic specialization + n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s) + result = explicitGenericInstantiation(c, n, s) + of skMacro, skTemplate: + if efInCall in flags: + # We are processing macroOrTmpl[] in macroOrTmpl[](...) call. + # Return as is, so it can be transformed into complete macro or + # template call in semIndirectOp caller. + result = n + else: + # We are processing macroOrTmpl[] not in call. Transform it to the + # macro or template call with generic arguments here. + n.kind = nkCall + case s.kind + of skMacro: result = semMacroExpr(c, n, n, s, flags) + of skTemplate: result = semTemplateExpr(c, n, s, flags) + else: discard + of skType: + result = symNodeFromType(c, semTypeNode(c, n, nil), n.info) + else: + c.p.bracketExpr = n.sons[0] else: c.p.bracketExpr = n.sons[0] diff --git a/tests/generics/tgenerictmpl2.nim b/tests/generics/tgenerictmpl2.nim new file mode 100644 index 0000000000..0ecaf9ded0 --- /dev/null +++ b/tests/generics/tgenerictmpl2.nim @@ -0,0 +1,31 @@ +discard """ + output: '''1 +1 +1 +1 +999 +999 +999 +2''' +""" + +# test if we can pass explicit generic arguments to generic templates +# based on bug report #3496 + +proc tproc[T](t: T = 999) = echo t +template ttmpl[T](t: T = 999) = echo t + +tproc(1) +tproc[int](1) +ttmpl(1) +ttmpl[int](1) #<- crash case #1 + +tproc[int]() +discard tproc[int] +ttmpl[int]() #<- crash case #2 +ttmpl[int] #<- crash case #3 + +# but still allow normal use of [] on non-generic templates + +template tarr: expr = [1, 2, 3, 4] +echo tarr[1]