Merge branch 'patch/fix-3496-generic-tmpl-args' of https://github.com/nanoant/Nim into nanoant-patch/fix-3496-generic-tmpl-args

This commit is contained in:
Andreas Rumpf
2016-05-29 23:58:25 +02:00
3 changed files with 88 additions and 5 deletions

View File

@@ -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

View File

@@ -732,10 +732,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..<n.len:
sons.add n.sons[i]
# Generic template arguments from bracket expression:
for i in 1..<n.sons[0].len:
sons.add n.sons[0].sons[i]
n.sons = sons
# FIXME: Shouldn't we check sfImmediate and call semDirectOp?
# However passing to semDirectOp doesn't work here.
case s.kind
of skMacro: result = semMacroExpr(c, n, n, s, flags)
of skTemplate: result = semTemplateExpr(c, n, s, flags)
else: discard
return
let nOrig = n.copyTree
semOpAux(c, n)
var t: PType = nil
@@ -965,8 +989,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)
@@ -1193,7 +1229,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,
@@ -1240,6 +1278,20 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
# 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 in {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
elif s != nil and s.kind == skType:
result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
else:

View File

@@ -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]