bootstraps fine with overloadable templates

This commit is contained in:
Zahary Karadjov 2011-12-15 18:39:44 +02:00
commit e5bd3b5b97
14 changed files with 230 additions and 143 deletions

View file

@ -225,6 +225,9 @@ type
sfInnerProc, # proc is an inner proc sfInnerProc, # proc is an inner proc
sfThread, # proc will run as a thread sfThread, # proc will run as a thread
# variable is a thread variable # variable is a thread variable
sfInline # forced-inline procs
sfImmediate, # macro or template is immediately expanded without
# considering any possible overloads
sfCompileTime, # proc can be evaluated at compile time sfCompileTime, # proc can be evaluated at compile time
sfMerge, # proc can be merged with itself sfMerge, # proc can be merged with itself
sfDeadCodeElim, # dead code elimination for the module is turned on sfDeadCodeElim, # dead code elimination for the module is turned on
@ -570,7 +573,8 @@ type
# the poor naming choices in the standard library. # the poor naming choices in the standard library.
const const
OverloadableSyms* = {skProc, skMethod, skIterator, skConverter, skModule} OverloadableSyms* = {skProc, skMethod, skIterator, skConverter,
skModule, skTemplate, skMacro}
GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody, GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody,
tyGenericParam} tyGenericParam}
@ -918,6 +922,12 @@ proc delSon(father: PNode, idx: int) =
for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1] for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
setlen(father.sons, length - 1) setlen(father.sons, length - 1)
proc hasSons*(n: PNode): bool {.inline.} =
result = n.kind notin { nkCharLit..nkInt64Lit,
nkFloatLit..nkFloat64Lit,
nkStrLit..nkTripleStrLit,
nkSym, nkIdent }
proc copyNode(src: PNode): PNode = proc copyNode(src: PNode): PNode =
# does not copy its sons! # does not copy its sons!
if src == nil: if src == nil:
@ -949,6 +959,18 @@ proc shallowCopy*(src: PNode): PNode =
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
else: newSeq(result.sons, sonsLen(src)) else: newSeq(result.sons, sonsLen(src))
proc copySons*(src: PNode): Pnode =
# copies a node and its immediate sons
if src == nil: return nil
assert src.hasSons
result = newNode(src.kind)
result.info = src.info
result.typ = src.typ
result.flags = src.flags * PersistentNodeFlags
newSeq(result.sons, src.len)
for i in countup(0, src.len - 1):
result.sons[i] = src.sons[i]
proc copyTree(src: PNode): PNode = proc copyTree(src: PNode): PNode =
# copy a whole syntax tree; performs deep copying # copy a whole syntax tree; performs deep copying
if src == nil: if src == nil:

View file

@ -10,7 +10,8 @@
proc leftAppearsOnRightSide(le, ri: PNode): bool = proc leftAppearsOnRightSide(le, ri: PNode): bool =
if le != nil: if le != nil:
for i in 1 .. <ri.len: for i in 1 .. <ri.len:
if le.isPartOf(ri[i]) != arNo: return true let r = ri[i]
if isPartOf(le, r) != arNo: return true
proc hasNoInit(call: PNode): bool {.inline.} = proc hasNoInit(call: PNode): bool {.inline.} =
result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags

View file

@ -26,8 +26,9 @@ const
wNoStackFrame, wError, wDiscardable, wNoInit} wNoStackFrame, wError, wDiscardable, wNoInit}
converterPragmas* = procPragmas converterPragmas* = procPragmas
methodPragmas* = procPragmas methodPragmas* = procPragmas
macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, templatePragmas* = {wImmediate}
wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern, macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
wImportcpp, wImportobjc, wError, wDiscardable} wImportcpp, wImportobjc, wError, wDiscardable}
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect, iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
@ -450,6 +451,9 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
of wImportCompilerProc: of wImportCompilerProc:
processImportCompilerProc(sym, getOptionalStr(c, it, sym.name.s)) processImportCompilerProc(sym, getOptionalStr(c, it, sym.name.s))
of wExtern: setExternName(sym, expectStrLit(c, it)) of wExtern: setExternName(sym, expectStrLit(c, it))
of wImmediate:
if sym.kind notin {skTemplate, skMacro}: invalidPragma(it)
incl(sym.flags, sfImmediate)
of wImportCpp: of wImportCpp:
processImportCpp(sym, getOptionalStr(c, it, sym.name.s)) processImportCpp(sym, getOptionalStr(c, it, sym.name.s))
of wImportObjC: of wImportObjC:

View file

@ -10,11 +10,11 @@
# This module implements the semantic checking pass. # This module implements the semantic checking pass.
import import
strutils, hashes, lists, options, lexer, ast, astalgo, trees, treetab, ast, strutils, hashes, lists, options, lexer, astalgo, trees, treetab,
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math, wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
magicsys, parser, nversion, semdata, nimsets, semfold, importer, magicsys, parser, nversion, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest, procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
semthreads, intsets, transf, evals, idgen, aliases suggest, semthreads, intsets, transf, evals, idgen, aliases
proc semPass*(): TPass proc semPass*(): TPass
# implementation # implementation
@ -75,16 +75,12 @@ proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
include semtempl include semtempl
proc semConstExpr(c: PContext, n: PNode): PNode = proc evalTypedExpr(c: PContext, e: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil:
GlobalError(n.info, errConstExprExpected)
return nil
result = getConstExpr(c.module, e) result = getConstExpr(c.module, e)
if result == nil: if result == nil:
result = evalConstExpr(c.module, e) result = evalConstExpr(c.module, e)
if result == nil or result.kind == nkEmpty: if result == nil or result.kind == nkEmpty:
GlobalError(n.info, errConstExprExpected) GlobalError(e.info, errConstExprExpected)
when false: when false:
result = semExprWithType(c, n) result = semExprWithType(c, n)
if result == nil: if result == nil:
@ -93,6 +89,13 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
result = getConstExpr(c.module, result) result = getConstExpr(c.module, result)
if result == nil: GlobalError(n.info, errConstExprExpected) if result == nil: GlobalError(n.info, errConstExprExpected)
proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil:
GlobalError(n.info, errConstExprExpected)
return nil
result = evalTypedExpr(c, e)
proc semAndEvalConstExpr(c: PContext, n: PNode): PNode = proc semAndEvalConstExpr(c: PContext, n: PNode): PNode =
result = semConstExpr(c, n) result = semConstExpr(c, n)

View file

@ -8,6 +8,7 @@
# #
## This module implements semantic checking for calls. ## This module implements semantic checking for calls.
# included from sem.nim
proc sameMethodDispatcher(a, b: PSym): bool = proc sameMethodDispatcher(a, b: PSym): bool =
result = false result = false
@ -17,60 +18,8 @@ proc sameMethodDispatcher(a, b: PSym): bool =
if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym: if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym:
result = true result = true
proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds, proc resolveOverloads(c: PContext, n, orig: PNode,
initialBinding: PNode): PNode = filter: TSymKinds): TCandidate =
var
o: TOverloadIter
x, y, z: TCandidate
#Message(n.info, warnUser, renderTree(n))
var sym = initOverloadIter(o, c, f)
result = nil
if sym == nil: return
initCandidate(x, sym, initialBinding)
initCandidate(y, sym, initialBinding)
while sym != nil:
if sym.kind in filter:
initCandidate(z, sym, initialBinding)
z.calleeSym = sym
matches(c, n, z)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind == skIterator: inc(z.exactMatches, 200)
case x.state
of csEmpty, csNoMatch: x = z
of csMatch:
var cmp = cmpCandidates(x, z)
if cmp < 0: x = z # z is better than x
elif cmp == 0: y = z # z is as good as x
else: nil
sym = nextOverloadIter(o, c, f)
if x.state == csEmpty:
# no overloaded proc found
# do not generate an error yet; the semantic checking will check for
# an overloaded () operator
elif y.state == csMatch and cmpCandidates(x, y) == 0 and
not sameMethodDispatcher(x.calleeSym, y.calleeSym):
if x.state != csMatch:
InternalError(n.info, "x.state is not csMatch")
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
getProcHeader(x.calleeSym), getProcHeader(y.calleeSym),
x.calleeSym.Name.s])
else:
# only one valid interpretation found:
markUsed(n, x.calleeSym)
if x.calleeSym.ast == nil:
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
if x.calleeSym.ast.sons[genericParamsPos].kind != nkEmpty:
# a generic proc!
x.calleeSym = generateInstance(c, x.calleeSym, x.bindings, n.info)
x.callee = x.calleeSym.typ
result = x.call
result.sons[0] = newSymNode(x.calleeSym)
result.typ = x.callee.sons[0]
proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
# process the bindings once:
var initialBinding: PNode var initialBinding: PNode
var f = n.sons[0] var f = n.sons[0]
if f.kind == nkBracketExpr: if f.kind == nkBracketExpr:
@ -79,7 +28,66 @@ proc semDirectCall(c: PContext, n: PNode, filter: TSymKinds): PNode =
f = f.sons[0] f = f.sons[0]
else: else:
initialBinding = nil initialBinding = nil
result = semDirectCallWithBinding(c, n, f, filter, initialBinding)
var
o: TOverloadIter
alt, z: TCandidate
template best: expr = result
#Message(n.info, warnUser, renderTree(n))
var sym = initOverloadIter(o, c, f)
if sym == nil: return
initCandidate(best, sym, initialBinding)
initCandidate(alt, sym, initialBinding)
while sym != nil:
if sym.kind in filter:
initCandidate(z, sym, initialBinding)
z.calleeSym = sym
matches(c, n, orig, z)
if z.state == csMatch:
# little hack so that iterators are preferred over everything else:
if sym.kind == skIterator: inc(z.exactMatches, 200)
case best.state
of csEmpty, csNoMatch: best = z
of csMatch:
var cmp = cmpCandidates(best, z)
if cmp < 0: best = z # x is better than the best so far
elif cmp == 0: alt = z # x is as good as the best so far
else: nil
sym = nextOverloadIter(o, c, f)
if best.state == csEmpty:
# no overloaded proc found
# do not generate an error yet; the semantic checking will check for
# an overloaded () operator
elif alt.state == csMatch and cmpCandidates(best, alt) == 0 and
not sameMethodDispatcher(best.calleeSym, alt.calleeSym):
if best.state != csMatch:
InternalError(n.info, "x.state is not csMatch")
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
best.calleeSym.Name.s])
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
assert x.state == csMatch
var finalCallee = x.calleeSym
markUsed(n, finalCallee)
if finalCallee.ast == nil:
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
# a generic proc!
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
result = x.call
result.sons[0] = newSymNode(finalCallee)
result.typ = finalCallee.typ.sons[0]
proc semOverloadedCall(c: PContext, n, nOrig: PNode,
filter: TSymKinds): PNode =
var r = resolveOverloads(c, n, nOrig, filter)
if r.state == csMatch: result = semResolvedCall(c, n, r)
proc explicitGenericInstError(n: PNode): PNode = proc explicitGenericInstError(n: PNode): PNode =
LocalError(n.info, errCannotInstantiateX, renderTree(n)) LocalError(n.info, errCannotInstantiateX, renderTree(n))

View file

@ -8,6 +8,7 @@
# #
# this module does the semantic checking for expressions # this module does the semantic checking for expressions
# included from sem.nim
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode = proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
markUsed(n, s) markUsed(n, s)
@ -103,7 +104,8 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
if s.ast == nil: InternalError(n.info, "no default for") if s.ast == nil: InternalError(n.info, "no default for")
result = semExpr(c, s.ast) result = semExpr(c, s.ast)
of skType: of skType:
if efAllowType notin flags: GlobalError(n.info, errATypeHasNoValue) if efAllowType notin flags:
GlobalError(n.info, errATypeHasNoValue)
markUsed(n, s) markUsed(n, s)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
else: else:
@ -245,16 +247,30 @@ proc semIs(c: PContext, n: PNode): PNode =
else: else:
GlobalError(n.info, errXExpectsTwoArguments, "is") GlobalError(n.info, errXExpectsTwoArguments, "is")
proc semOpAux2(c: PContext, n: PNode): PNode =
result = n.shallowCopy
result.sons[0] = n.sons[0]
for i in countup(1, n.len - 1):
let a = n.sons[i]
if a.kind == nkExprEqExpr and a.len == 2:
var arg = a.shallowCopy
arg.sons[0] = newIdentNode(considerAcc(a.sons[0]), a.sons[0].info)
arg.sons[1] = semExprWithType(c, a.sons[1])
arg.typ = a.sons[1].typ
result.sons[i] = arg
else:
result.sons[i] = semExprWithType(c, a)
proc semOpAux(c: PContext, n: PNode) = proc semOpAux(c: PContext, n: PNode) =
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2: if a.kind == nkExprEqExpr and sonsLen(a) == 2:
var info = a.sons[0].info var info = a.sons[0].info
a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info) a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info)
a.sons[1] = semExprWithType(c, a.sons[1]) a.sons[1] = semExprWithType(c, a.sons[1], {efAllowType})
a.typ = a.sons[1].typ a.typ = a.sons[1].typ
else: else:
n.sons[i] = semExprWithType(c, a) n.sons[i] = semExprWithType(c, a, {efAllowType})
proc overloadedCallOpr(c: PContext, n: PNode): PNode = proc overloadedCallOpr(c: PContext, n: PNode): PNode =
# quick check if there is *any* () operator overloaded: # quick check if there is *any* () operator overloaded:
@ -475,24 +491,31 @@ proc expectStringArg(c: PContext, n: PNode, i: int): PNode =
include semmagic include semmagic
proc semDirectCallAnalyseEffects(c: PContext, n: PNode, proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, orig: PNode,
flags: TExprFlags): PNode = flags: TExprFlags): PNode =
if efWantIterator in flags: if efWantIterator in flags:
result = semDirectCall(c, n, {skIterator}) result = semOverloadedCall(c, n, orig, {skIterator})
elif efInTypeOf in flags: elif efInTypeOf in flags:
# for ``type(countup(1,3))``, see ``tests/ttoseq``. # for ``type(countup(1,3))``, see ``tests/ttoseq``.
result = semDirectCall(c, n, {skIterator, skProc, skMethod, skConverter}) result = semOverloadedCall(c, n, orig, {skIterator, skProc, skMethod, skConverter, skMacro, skTemplate})
else: else:
result = semDirectCall(c, n, {skProc, skMethod, skConverter}) result = semOverloadedCall(c, n, orig, {skProc, skMethod, skConverter, skMacro, skTemplate})
if result != nil: if result != nil:
if result.sons[0].kind != nkSym: if result.sons[0].kind != nkSym:
InternalError("semDirectCallAnalyseEffects") InternalError("semDirectCallAnalyseEffects")
var callee = result.sons[0].sym let callee = result.sons[0].sym
if (callee.kind == skIterator) and (callee.id == c.p.owner.id): case callee.kind
GlobalError(n.info, errRecursiveDependencyX, callee.name.s) of skMacro, skTemplate: nil
if sfNoSideEffect notin callee.flags: else:
if {sfImportc, sfSideEffect} * callee.flags != {}: if (callee.kind == skIterator) and (callee.id == c.p.owner.id):
incl(c.p.owner.flags, sfSideEffect) GlobalError(n.info, errRecursiveDependencyX, callee.name.s)
if sfNoSideEffect notin callee.flags:
if {sfImportc, sfSideEffect} * callee.flags != {}:
incl(c.p.owner.flags, sfSideEffect)
proc semDirectCallAnalyseEffects(c: PContext, n: PNode, orig: PNode,
flags: TExprFlags): PNode =
result = semOverloadedCallAnalyseEffects(c, n, orig, flags)
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = nil result = nil
@ -509,13 +532,14 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
return semExpr(c, result, flags) return semExpr(c, result, flags)
else: else:
n.sons[0] = semExpr(c, n.sons[0]) n.sons[0] = semExpr(c, n.sons[0])
let orig = n.copySons
semOpAux(c, n) semOpAux(c, n)
var t: PType = nil var t: PType = nil
if (n.sons[0].typ != nil): t = skipTypes(n.sons[0].typ, abstractInst) if (n.sons[0].typ != nil): t = skipTypes(n.sons[0].typ, abstractInst)
if (t != nil) and (t.kind == tyProc): if (t != nil) and (t.kind == tyProc):
var m: TCandidate var m: TCandidate
initCandidate(m, t) initCandidate(m, t)
matches(c, n, m) matches(c, n, orig, m)
if m.state != csMatch: if m.state != csMatch:
var msg = msgKindToString(errTypeMismatch) var msg = msgKindToString(errTypeMismatch)
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
@ -536,7 +560,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# the old ``prc`` (which is likely an nkIdent) has to be restored: # the old ``prc`` (which is likely an nkIdent) has to be restored:
if result == nil: if result == nil:
n.sons[0] = prc n.sons[0] = prc
result = semDirectCallAnalyseEffects(c, n, flags) result = semOverloadedCallAnalyseEffects(c, n, orig, flags)
if result == nil: if result == nil:
GlobalError(n.info, errExprXCannotBeCalled, GlobalError(n.info, errExprXCannotBeCalled,
renderTree(n, {renderNoComments})) renderTree(n, {renderNoComments}))
@ -547,15 +571,21 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# this seems to be a hotspot in the compiler! # this seems to be a hotspot in the compiler!
let nOrig = n.copySons
semOpAux(c, n) semOpAux(c, n)
result = semDirectCallAnalyseEffects(c, n, flags) result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result == nil: if result == nil:
result = overloadedCallOpr(c, n) result = overloadedCallOpr(c, n)
if result == nil: GlobalError(n.Info, errGenerated, getNotFoundError(c, n)) if result == nil: GlobalError(n.Info, errGenerated, getNotFoundError(c, n))
fixAbstractType(c, result) let callee = result.sons[0].sym
analyseIfAddressTakenInCall(c, result) case callee.kind
if result.sons[0].sym.magic != mNone: of skMacro: result = semMacroExpr(c, nOrig, callee)
result = magicsAfterOverloadResolution(c, result, flags) of skTemplate: result = semTemplateExpr(c, nOrig, callee)
else:
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags)
proc buildStringify(c: PContext, arg: PNode): PNode = proc buildStringify(c: PContext, arg: PNode): PNode =
if arg.typ != nil and skipTypes(arg.typ, abstractInst).kind == tyString: if arg.typ != nil and skipTypes(arg.typ, abstractInst).kind == tyString:
@ -820,7 +850,11 @@ proc propertyWriteAccess(c: PContext, n, a: PNode): PNode =
# nodes? # nodes?
addSon(result, a[0]) addSon(result, a[0])
addSon(result, semExpr(c, n[1])) addSon(result, semExpr(c, n[1]))
result = semDirectCallAnalyseEffects(c, result, {}) # XXX: @@ Revisit this
var orig = newNodeI(nkCall, n.info)
orig.addSon(a[0])
orig.addSon(n[1])
result = semDirectCallAnalyseEffects(c, result, result, {})
if result != nil: if result != nil:
fixAbstractType(c, result) fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result) analyseIfAddressTakenInCall(c, result)
@ -1234,8 +1268,18 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
var s = qualifiedLookup(c, n.sons[0], {checkUndeclared}) var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
if s != nil: if s != nil:
case s.kind case s.kind
of skMacro: result = semMacroExpr(c, n, s) of skMacro:
of skTemplate: result = semTemplateExpr(c, n, s) echo c.filename
if c.filename.endsWith("hello.nim") and sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
result = semMacroExpr(c, n, s)
of skTemplate:
var hello = c.filename.endsWith("hello.nim")
if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
result = semTemplateExpr(c, n, s)
of skType: of skType:
# XXX think about this more (``set`` procs) # XXX think about this more (``set`` procs)
if n.len == 2: if n.len == 2:

View file

@ -169,7 +169,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
openScope(c.tab) openScope(c.tab)
n.sons[namePos] = newSymNode(s) # check that no pragmas exist: n.sons[namePos] = newSymNode(s) # check that no pragmas exist:
if n.sons[pragmasPos].kind != nkEmpty: if n.sons[pragmasPos].kind != nkEmpty:
LocalError(n.info, errNoPragmasAllowedForX, "template") pragma(c, s, n.sons[pragmasPos], templatePragmas)
# check that no generic parameters exist: # check that no generic parameters exist:
if n.sons[genericParamsPos].kind != nkEmpty: if n.sons[genericParamsPos].kind != nkEmpty:
LocalError(n.info, errNoGenericParamsAllowedForX, "template") LocalError(n.info, errNoGenericParamsAllowedForX, "template")

View file

@ -8,6 +8,7 @@
# #
# this module does the semantic checking of type declarations # this module does the semantic checking of type declarations
# included from sem.nim
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType = proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
if prev == nil: if prev == nil:

View file

@ -17,6 +17,7 @@ import
type type
TCandidateState* = enum TCandidateState* = enum
csEmpty, csMatch, csNoMatch csEmpty, csMatch, csNoMatch
TCandidate* {.final.} = object TCandidate* {.final.} = object
exactMatches*: int exactMatches*: int
subtypeMatches: int subtypeMatches: int
@ -102,9 +103,9 @@ proc writeMatches(c: TCandidate) =
Writeln(stdout, "generic matches: " & $c.genericMatches) Writeln(stdout, "generic matches: " & $c.genericMatches)
proc getNotFoundError*(c: PContext, n: PNode): string = proc getNotFoundError*(c: PContext, n: PNode): string =
# Gives a detailed error message; this is separated from semDirectCall, # Gives a detailed error message; this is separated from semOverloadedCall,
# as semDirectCall is already pretty slow (and we need this information only # as semOverlodedCall is already pretty slow (and we need this information
# in case of an error). # only in case of an error).
result = msgKindToString(errTypeMismatch) result = msgKindToString(errTypeMismatch)
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
#debug(n.sons[i].typ) #debug(n.sons[i].typ)
@ -507,7 +508,10 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
return return
proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType, proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
arg: PNode): PNode = arg, argOrig: PNode): PNode =
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate} and
f.kind in {tyExpr, tyStmt, tyTypeDesc}:
return argOrig
var r = typeRel(m.bindings, f, a) var r = typeRel(m.bindings, f, a)
case r case r
of isConvertible: of isConvertible:
@ -547,9 +551,9 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
result = userConvMatch(c, m, base(f), a, arg) result = userConvMatch(c, m, base(f), a, arg)
proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType, proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
arg: PNode): PNode = arg, argOrig: PNode): PNode =
if arg == nil or arg.kind != nkSymChoice: if arg == nil or arg.kind != nkSymChoice:
result = ParamTypesMatchAux(c, m, f, a, arg) result = ParamTypesMatchAux(c, m, f, a, arg, argOrig)
else: else:
# CAUTION: The order depends on the used hashing scheme. Thus it is # CAUTION: The order depends on the used hashing scheme. Thus it is
# incorrect to simply use the first fitting match. However, to implement # incorrect to simply use the first fitting match. However, to implement
@ -591,29 +595,29 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
else: else:
# only one valid interpretation found: # only one valid interpretation found:
markUsed(arg, arg.sons[best].sym) markUsed(arg, arg.sons[best].sym)
result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best]) result = ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best], argOrig)
proc IndexTypesMatch*(c: PContext, f, a: PType, arg: PNode): PNode = proc IndexTypesMatch*(c: PContext, f, a: PType, arg: PNode): PNode =
var m: TCandidate var m: TCandidate
initCandidate(m, f) initCandidate(m, f)
result = paramTypesMatch(c, m, f, a, arg) result = paramTypesMatch(c, m, f, a, arg, nil)
proc ConvertTo*(c: PContext, f: PType, n: PNode): PNode = proc ConvertTo*(c: PContext, f: PType, n: PNode): PNode =
var m: TCandidate var m: TCandidate
initCandidate(m, f) initCandidate(m, f)
result = paramTypesMatch(c, m, f, n.typ, n) result = paramTypesMatch(c, m, f, n.typ, n, nil)
proc argtypeMatches*(c: PContext, f, a: PType): bool = proc argtypeMatches*(c: PContext, f, a: PType): bool =
var m: TCandidate var m: TCandidate
initCandidate(m, f) initCandidate(m, f)
result = paramTypesMatch(c, m, f, a, ast.emptyNode) != nil result = paramTypesMatch(c, m, f, a, ast.emptyNode, nil) != nil
proc setSon(father: PNode, at: int, son: PNode) = proc setSon(father: PNode, at: int, son: PNode) =
if sonsLen(father) <= at: setlen(father.sons, at + 1) if sonsLen(father) <= at: setlen(father.sons, at + 1)
father.sons[at] = son father.sons[at] = son
proc matchesAux*(c: PContext, n: PNode, m: var TCandidate, proc matchesAux*(c: PContext, n, nOrig: PNode,
marker: var TIntSet) = m: var TCandidate, marker: var TIntSet) =
var f = 1 # iterates over formal parameters var f = 1 # iterates over formal parameters
var a = 1 # iterates over the actual given arguments var a = 1 # iterates over the actual given arguments
m.state = csMatch # until proven otherwise m.state = csMatch # until proven otherwise
@ -623,7 +627,7 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
addSon(m.call, copyTree(n.sons[0])) addSon(m.call, copyTree(n.sons[0]))
var container: PNode = nil # constructed container var container: PNode = nil # constructed container
var formal: PSym = nil var formal: PSym = nil
while a < sonsLen(n): while a < n.len:
if n.sons[a].kind == nkExprEqExpr: if n.sons[a].kind == nkExprEqExpr:
# named param # named param
# check if m.callee has such a param: # check if m.callee has such a param:
@ -642,8 +646,8 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
m.state = csNoMatch m.state = csNoMatch
return return
m.baseTypeMatch = false m.baseTypeMatch = false
var arg = ParamTypesMatch(c, m, formal.typ, var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a].typ, n.sons[a].sons[1]) n.sons[a].sons[1], nOrig.sons[a].sons[1])
if arg == nil: if arg == nil:
m.state = csNoMatch m.state = csNoMatch
return return
@ -668,7 +672,8 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
addSon(m.call, copyTree(n.sons[a])) addSon(m.call, copyTree(n.sons[a]))
elif formal != nil: elif formal != nil:
m.baseTypeMatch = false m.baseTypeMatch = false
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, n.sons[a]) var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a])
if (arg != nil) and m.baseTypeMatch and (container != nil): if (arg != nil) and m.baseTypeMatch and (container != nil):
addSon(container, arg) addSon(container, arg)
else: else:
@ -687,7 +692,8 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
m.state = csNoMatch m.state = csNoMatch
return return
m.baseTypeMatch = false m.baseTypeMatch = false
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, n.sons[a]) var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a])
if arg == nil: if arg == nil:
m.state = csNoMatch m.state = csNoMatch
return return
@ -703,14 +709,14 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
inc(a) inc(a)
inc(f) inc(f)
proc partialMatch*(c: PContext, n: PNode, m: var TCandidate) = proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
# for 'suggest' support: # for 'suggest' support:
var marker = initIntSet() var marker = initIntSet()
matchesAux(c, n, m, marker) matchesAux(c, n, nOrig, m, marker)
proc matches*(c: PContext, n: PNode, m: var TCandidate) = proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
var marker = initIntSet() var marker = initIntSet()
matchesAux(c, n, m, marker) matchesAux(c, n, nOrig, m, marker)
if m.state == csNoMatch: return if m.state == csNoMatch: return
# check that every formal parameter got a value: # check that every formal parameter got a value:
var f = 1 var f = 1

View file

@ -46,7 +46,7 @@ proc suggestField(s: PSym) =
if filterSym(s): if filterSym(s):
OutWriteln(SymToStr(s, isLocal=true, sectionSuggest)) OutWriteln(SymToStr(s, isLocal=true, sectionSuggest))
template wholeSymTab(cond, section: expr) = template wholeSymTab(cond, section: expr) {.immediate.} =
for i in countdown(c.tab.tos-1, 0): for i in countdown(c.tab.tos-1, 0):
for it in items(c.tab.stack[i]): for it in items(c.tab.stack[i]):
if cond: if cond:
@ -79,20 +79,18 @@ proc nameFits(c: PContext, s: PSym, n: PNode): bool =
else: return false else: return false
result = opr.id == s.name.id result = opr.id == s.name.id
proc argsFit(c: PContext, candidate: PSym, n: PNode): bool = proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
case candidate.kind case candidate.kind
of skProc, skIterator, skMethod: of OverloadableSyms:
var m: TCandidate var m: TCandidate
initCandidate(m, candidate, nil) initCandidate(m, candidate, nil)
sigmatch.partialMatch(c, n, m) sigmatch.partialMatch(c, n, nOrig, m)
result = m.state != csNoMatch result = m.state != csNoMatch
of skTemplate, skMacro:
result = true
else: else:
result = false result = false
proc suggestCall(c: PContext, n: PNode) = proc suggestCall(c: PContext, n, nOrig: PNode) =
wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n), wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n, nOrig),
sectionContext) sectionContext)
proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
@ -227,7 +225,7 @@ proc suggestExpr*(c: PContext, node: PNode) =
var x = safeSemExpr(c, n.sons[i]) var x = safeSemExpr(c, n.sons[i])
if x.kind == nkEmpty or x.typ == nil: break if x.kind == nkEmpty or x.typ == nil: break
addSon(a, x) addSon(a, x)
suggestCall(c, a) suggestCall(c, a, n)
if optDef in gGlobalOptions: if optDef in gGlobalOptions:
var n = findClosestSym(fuzzySemCheck(c, node)) var n = findClosestSym(fuzzySemCheck(c, node))

View file

@ -36,7 +36,7 @@ type
wColon, wColonColon, wEquals, wDot, wDotDot, wColon, wColonColon, wEquals, wDot, wDotDot,
wStar, wMinus, wStar, wMinus,
wMagic, wThread, wFinal, wProfiler, wObjChecks, wMagic, wThread, wFinal, wProfiler, wObjChecks,
wImportCpp, wImportObjC, wImmediate, wImportCpp, wImportObjC,
wImportCompilerProc, wImportCompilerProc,
wImportc, wExportc, wExtern, wIncompleteStruct, wImportc, wExportc, wExtern, wIncompleteStruct,
wAlign, wNodecl, wPure, wVolatile, wRegister, wSideeffect, wHeader, wAlign, wNodecl, wPure, wVolatile, wRegister, wSideeffect, wHeader,
@ -83,7 +83,7 @@ const
"*", "-", "*", "-",
"magic", "thread", "final", "profiler", "objchecks", "magic", "thread", "final", "profiler", "objchecks",
"importcpp", "importobjc", "immediate", "importcpp", "importobjc",
"importcompilerproc", "importc", "exportc", "extern", "incompletestruct", "importcompilerproc", "importc", "exportc", "extern", "incompletestruct",
"align", "nodecl", "pure", "volatile", "register", "sideeffect", "align", "nodecl", "pure", "volatile", "register", "sideeffect",
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib", "header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",

View file

@ -251,7 +251,7 @@ when defined(endb):
dbgAborting: bool # whether the debugger wants to abort dbgAborting: bool # whether the debugger wants to abort
proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} = proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
template processSignal(s, action: expr) = template processSignal(s, action: expr) {.immediate.} =
if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n") if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
elif s == SIGSEGV: elif s == SIGSEGV:
action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n") action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")

View file

@ -170,7 +170,7 @@ when traceGC:
cfprintf(cstdout, "Allocations: %ld; ZCT freed: %ld; CYC freed: %ld\n", cfprintf(cstdout, "Allocations: %ld; ZCT freed: %ld; CYC freed: %ld\n",
e, z, y) e, z, y)
template gcTrace(cell, state: expr): stmt = template gcTrace(cell, state: expr): stmt {.immediate.} =
when traceGC: traceCell(cell, state) when traceGC: traceCell(cell, state)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------