merged branch overloading-for-macros

This commit is contained in:
Zahary Karadjov
2012-03-19 12:06:38 +02:00
39 changed files with 366 additions and 218 deletions

View File

@@ -227,6 +227,9 @@ type
sfInnerProc, # proc is an inner proc
sfThread, # proc will run as a thread
# 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
sfMerge, # proc can be merged with itself
sfDeadCodeElim, # dead code elimination for the module is turned on
@@ -602,7 +605,8 @@ type
# the poor naming choices in the standard library.
const
OverloadableSyms* = {skProc, skMethod, skIterator, skConverter, skModule}
OverloadableSyms* = {skProc, skMethod, skIterator, skConverter,
skModule, skTemplate, skMacro}
GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody,
tyGenericParam}

View File

@@ -567,6 +567,19 @@ proc StrTableRawInsert(data: var TSymSeq, n: PSym) =
assert(data[h] == nil)
data[h] = n
proc SymTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
assert prevSym.name.h == newSym.name.h
var h: THash = prevSym.name.h and high(data)
while data[h] != nil:
if data[h] == prevSym:
data[h] = newSym
return
h = nextTry(h, high(data))
assert false
proc SymTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
SymTabReplaceRaw(t.data, prevSym, newSym)
proc StrTableEnlarge(t: var TStrTable) =
var n: TSymSeq
newSeq(n, len(t.data) * growthFactor)

View File

@@ -10,7 +10,8 @@
proc leftAppearsOnRightSide(le, ri: PNode): bool =
if le != nil:
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.} =
result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags

View File

@@ -164,7 +164,7 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
result = nil
if result != nil and result.kind == skStub: loadStub(result)
proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case n.kind
of nkIdent, nkAccQuoted:
var ident = considerAcc(n)
@@ -174,7 +174,7 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
dec(o.stackPtr)
if o.stackPtr < 0: break
result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], ident)
of nkSym:
of nkSym:
result = n.sym
o.mode = oimDone
of nkDotExpr:
@@ -204,6 +204,13 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
Incl(o.inSymChoice, result.id)
else: nil
if result != nil and result.kind == skStub: loadStub(result)
proc lastOverloadScope*(o: TOverloadIter): int =
case o.mode
of oimNoQualifier: result = o.stackPtr
of oimSelfModule: result = ModuleTablePos
of oimOtherModule: result = ImportTablePos
else: result = -1
proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case o.mode

View File

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

View File

@@ -10,11 +10,11 @@
# This module implements the semantic checking pass.
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,
magicsys, parser, nversion, semdata, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest,
semthreads, intsets, transf, evals, idgen, aliases
magicsys, parser, nversion, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
suggest, semthreads, intsets, transf, evals, idgen, aliases
proc semPass*(): TPass
# implementation
@@ -75,17 +75,20 @@ proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
include semtempl
proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil:
GlobalError(n.info, errConstExprExpected)
return nil
proc evalTypedExpr(c: PContext, e: PNode): PNode =
result = getConstExpr(c.module, e)
if result == nil:
result = evalConstExpr(c.module, e)
if result == nil or result.kind == nkEmpty:
GlobalError(n.info, errConstExprExpected)
if result == nil or result.kind == nkEmpty:
GlobalError(e.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 =
result = semConstExpr(c, n)

View File

@@ -8,6 +8,7 @@
#
## This module implements semantic checking for calls.
# included from sem.nim
proc sameMethodDispatcher(a, b: PSym): bool =
result = false
@@ -17,70 +18,78 @@ proc sameMethodDispatcher(a, b: PSym): bool =
if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym:
result = true
proc semDirectCallWithBinding(c: PContext, n, f: PNode, filter: TSymKinds,
initialBinding: PNode): PNode =
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:
proc resolveOverloads(c: PContext, n, orig: PNode,
filter: TSymKinds): TCandidate =
var initialBinding: PNode
var f = n.sons[0]
if f.kind == nkBracketExpr:
# fill in the bindings:
initialBinding = f
f = f.sons[0]
else:
else:
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)
var symScope = o.lastOverloadScope
if sym == nil: return
initCandidate(best, sym, initialBinding, symScope)
initCandidate(alt, sym, initialBinding, symScope)
while sym != nil:
if sym.kind in filter:
initCandidate(z, sym, initialBinding, o.lastOverloadScope)
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 =
LocalError(n.info, errCannotInstantiateX, renderTree(n))
result = n

View File

@@ -73,7 +73,7 @@ type
userPragmas*: TStrTable
evalContext*: PEvalContext
slurpedFiles*: seq[string]
var
gGenericsCache: PGenericsCache # save for modularity

View File

@@ -8,6 +8,7 @@
#
# this module does the semantic checking for expressions
# included from sem.nim
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
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")
result = semExpr(c, s.ast)
of skType:
if efAllowType notin flags: GlobalError(n.info, errATypeHasNoValue)
if efAllowType notin flags:
GlobalError(n.info, errATypeHasNoValue)
markUsed(n, s)
result = newSymNode(s, n.info)
else:
@@ -245,17 +247,17 @@ proc semIs(c: PContext, n: PNode): PNode =
else:
GlobalError(n.info, errXExpectsTwoArguments, "is")
proc semOpAux(c: PContext, n: PNode) =
for i in countup(1, sonsLen(n) - 1):
proc semOpAux(c: PContext, n: PNode) =
for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkExprEqExpr and sonsLen(a) == 2:
var info = 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
else:
n.sons[i] = semExprWithType(c, a)
else:
n.sons[i] = semExprWithType(c, a, {efAllowType})
proc overloadedCallOpr(c: PContext, n: PNode): PNode =
# quick check if there is *any* () operator overloaded:
var par = getIdent("()")
@@ -514,25 +516,32 @@ proc semStaticExpr(c: PContext, n: PNode): PNode =
if result.isNil:
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
flags: TExprFlags): PNode =
proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
flags: TExprFlags): PNode =
if efWantIterator in flags:
result = semDirectCall(c, n, {skIterator})
result = semOverloadedCall(c, n, nOrig, {skIterator})
elif efInTypeOf in flags:
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
result = semDirectCall(c, n, {skIterator, skProc, skMethod, skConverter})
result = semOverloadedCall(c, n, nOrig, {skIterator, skProc, skMethod, skConverter, skMacro, skTemplate})
else:
result = semDirectCall(c, n, {skProc, skMethod, skConverter})
result = semOverloadedCall(c, n, nOrig, {skProc, skMethod, skConverter, skMacro, skTemplate})
if result != nil:
if result.sons[0].kind != nkSym:
InternalError("semDirectCallAnalyseEffects")
var callee = result.sons[0].sym
if (callee.kind == skIterator) and (callee.id == c.p.owner.id):
GlobalError(n.info, errRecursiveDependencyX, callee.name.s)
if sfNoSideEffect notin callee.flags:
if {sfImportc, sfSideEffect} * callee.flags != {}:
incl(c.p.owner.flags, sfSideEffect)
let callee = result.sons[0].sym
case callee.kind
of skMacro, skTemplate: nil
else:
if (callee.kind == skIterator) and (callee.id == c.p.owner.id):
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, nOrig: PNode,
flags: TExprFlags): PNode =
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = nil
var prc = n.sons[0]
@@ -548,13 +557,14 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
return semExpr(c, result, flags)
else:
n.sons[0] = semExpr(c, n.sons[0])
let nOrig = n.copyTree
semOpAux(c, n)
var t: PType = nil
if (n.sons[0].typ != nil): t = skipTypes(n.sons[0].typ, abstractInst)
if (t != nil) and (t.kind == tyProc):
var m: TCandidate
initCandidate(m, t)
matches(c, n, m)
matches(c, n, nOrig, m)
if m.state != csMatch:
var msg = msgKindToString(errTypeMismatch)
for i in countup(1, sonsLen(n) - 1):
@@ -575,7 +585,8 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# the old ``prc`` (which is likely an nkIdent) has to be restored:
if result == nil:
n.sons[0] = prc
result = semDirectCallAnalyseEffects(c, n, flags)
nOrig.sons[0] = prc
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result == nil:
GlobalError(n.info, errExprXCannotBeCalled,
renderTree(n, {renderNoComments}))
@@ -587,15 +598,21 @@ proc semIndirectOp(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!
let nOrig = n.copyTree
semOpAux(c, n)
result = semDirectCallAnalyseEffects(c, n, flags)
if result == nil:
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
if result == nil:
result = overloadedCallOpr(c, n)
if result == nil: GlobalError(n.Info, errGenerated, getNotFoundError(c, n))
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
if result.sons[0].sym.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags)
let callee = result.sons[0].sym
case callee.kind
of skMacro: result = semMacroExpr(c, nOrig, callee)
of skTemplate: result = semTemplateExpr(c, nOrig, callee)
else:
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags)
result = evalAtCompileTime(c, result)
proc buildStringify(c: PContext, arg: PNode): PNode =
@@ -734,7 +751,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.typ = ty
markUsed(n, f)
return
elif efAllowType notin flags:
elif efAllowType notin flags:
GlobalError(n.sons[0].info, errATypeHasNoValue)
return
# reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
@@ -852,16 +869,16 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# overloaded [] operator:
result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]"))
proc propertyWriteAccess(c: PContext, n, a: PNode): PNode =
proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
var id = considerAcc(a[1])
result = newNodeI(nkCall, n.info)
addSon(result, newIdentNode(getIdent(id.s & '='), n.info))
let setterId = newIdentNode(getIdent(id.s & '='), n.info)
# a[0] is already checked for semantics, that does ``builtinFieldAccess``
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
# nodes?
addSon(result, a[0])
addSon(result, semExpr(c, n[1]))
result = semDirectCallAnalyseEffects(c, result, {})
let aOrig = nOrig[0]
result = newNode(nkCall, n.info, sons = @[setterId, a[0], semExpr(c, n[1])])
let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]])
result = semDirectCallAnalyseEffects(c, result, orig, {})
if result != nil:
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
@@ -898,9 +915,10 @@ proc semAsgn(c: PContext, n: PNode): PNode =
of nkDotExpr:
# r.f = x
# --> `f=` (r, x)
let nOrig = n.copyTree
a = builtinFieldAccess(c, a, {efLValue})
if a == nil:
return propertyWriteAccess(c, n, n[0])
return propertyWriteAccess(c, n, nOrig, a)
of nkBracketExpr:
# a[i] = x
# --> `[]=`(a, i, x)
@@ -1275,8 +1293,16 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
var s = qualifiedLookup(c, n.sons[0], {checkUndeclared})
if s != nil:
case s.kind
of skMacro: result = semMacroExpr(c, n, s)
of skTemplate: result = semTemplateExpr(c, n, s)
of skMacro:
if false and sfImmediate notin s.flags: # XXX not yet enabled
result = semDirectOp(c, n, flags)
else:
result = semMacroExpr(c, n, s)
of skTemplate:
if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
result = semTemplateExpr(c, n, s)
of skType:
# XXX think about this more (``set`` procs)
if n.len == 2:

View File

@@ -8,6 +8,7 @@
#
## this module does the semantic checking of statements
# included from sem.nim
proc semCommand(c: PContext, n: PNode): PNode =
result = semExprNoType(c, n)
@@ -690,8 +691,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
n.sons[genericParamsPos] = gp
# check for semantics again:
semParamList(c, n.sons[ParamsPos], nil, s)
# XXX: obsoleted - happens in semParamList
# addParams(c, s.typ.n)
else:
s.typ = newTypeS(tyProc, c)
addSon(s.typ, nil)

View File

@@ -7,6 +7,8 @@
# distribution, for details about the copyright.
#
# included from sem.nim
proc isExpr(n: PNode): bool =
# returns true if ``n`` looks like an expression
case n.kind
@@ -54,11 +56,6 @@ proc evalTemplateArgs(c: PContext, n: PNode, s: PSym): PNode =
else: arg = copyTree(s.typ.n.sons[i].sym.ast)
if arg == nil or arg.kind == nkEmpty:
LocalError(n.info, errWrongNumberOfArguments)
elif not (s.typ.sons[i].kind in {tyTypeDesc, tyStmt, tyExpr}):
# concrete type means semantic checking for argument:
# XXX This is horrible! Better make semantic checking use some kind
# of fixpoint iteration ...
arg = fitNode(c, s.typ.sons[i], semExprWithType(c, arg))
addSon(result, arg)
proc evalTemplate*(c: PContext, n: PNode, sym: PSym): PNode =
@@ -167,9 +164,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# check parameter list:
pushOwner(s)
openScope(c.tab)
n.sons[namePos] = newSymNode(s) # check that no pragmas exist:
if n.sons[pragmasPos].kind != nkEmpty:
LocalError(n.info, errNoPragmasAllowedForX, "template")
n.sons[namePos] = newSymNode(s)
if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, s, n.sons[pragmasPos], templatePragmas)
# check that no generic parameters exist:
if n.sons[genericParamsPos].kind != nkEmpty:
LocalError(n.info, errNoGenericParamsAllowedForX, "template")
@@ -185,8 +182,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# use ``stmt`` as implicit result type
s.typ.sons[0] = newTypeS(tyStmt, c)
s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
# XXX: obsoleted - happens in semParamList #
# addParams(c, s.typ.n) # resolve parameters:
var toBind = initIntSet()
n.sons[bodyPos] = resolveTemplateParams(c, n.sons[bodyPos], false, toBind)
if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}:
@@ -198,5 +193,10 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
result = n
if n.sons[bodyPos].kind == nkEmpty:
LocalError(n.info, errImplOfXexpected, s.name.s)
# add identifier of template as a last step to not allow recursive templates:
addInterfaceDecl(c, s)
let curScope = c.tab.tos - 1
var proto = SearchForProc(c, s, curScope)
if proto == nil:
addInterfaceOverloadableSymAt(c, s, curScope)
else:
SymTabReplace(c.tab.stack[curScope], proto, s)

View File

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

View File

@@ -17,6 +17,7 @@ import
type
TCandidateState* = enum
csEmpty, csMatch, csNoMatch
TCandidate* {.final.} = object
exactMatches*: int
subtypeMatches: int
@@ -26,6 +27,7 @@ type
state*: TCandidateState
callee*: PType # may not be nil!
calleeSym*: PSym # may be nil
calleeScope: int # may be -1 for unknown scope
call*: PNode # modified call
bindings*: TIdTable # maps types to types
baseTypeMatch: bool # needed for conversions from T to openarray[T]
@@ -35,7 +37,7 @@ type
isNone, isConvertible, isIntConv, isSubtype,
isGeneric,
isEqual
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
c.exactMatches = 0
c.subtypeMatches = 0
@@ -59,9 +61,10 @@ proc put(t: var TIdTable, key, val: PType) {.inline.} =
IdentEq(val.sym.name, "TTable"):
assert false
proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode) =
proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode, calleeScope = -1) =
initCandidateAux(c, callee.typ)
c.calleeSym = callee
c.calleeScope = calleeScope
initIdTable(c.bindings)
if binding != nil:
var typeParams = callee.ast[genericParamsPos]
@@ -93,6 +96,9 @@ proc cmpCandidates*(a, b: TCandidate): int =
result = a.intConvMatches - b.intConvMatches
if result != 0: return
result = a.convMatches - b.convMatches
if result != 0: return
if (a.calleeScope != -1) and (b.calleeScope != -1):
result = a.calleeScope - b.calleeScope
proc writeMatches(c: TCandidate) =
Writeln(stdout, "exact matches: " & $c.exactMatches)
@@ -101,10 +107,10 @@ proc writeMatches(c: TCandidate) =
Writeln(stdout, "intconv matches: " & $c.intConvMatches)
Writeln(stdout, "generic matches: " & $c.genericMatches)
proc getNotFoundError*(c: PContext, n: PNode): string =
# Gives a detailed error message; this is separated from semDirectCall,
# as semDirectCall is already pretty slow (and we need this information only
# in case of an error).
proc getNotFoundError*(c: PContext, n: PNode): string =
# Gives a detailed error message; this is separated from semOverloadedCall,
# as semOverlodedCall is already pretty slow (and we need this information
# only in case of an error).
result = msgKindToString(errTypeMismatch)
for i in countup(1, sonsLen(n) - 1):
#debug(n.sons[i].typ)
@@ -507,7 +513,10 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
return
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)
case r
of isConvertible:
@@ -547,9 +556,9 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
result = userConvMatch(c, m, base(f), a, arg)
proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
arg: PNode): PNode =
arg, argOrig: PNode): PNode =
if arg == nil or arg.kind != nkSymChoice:
result = ParamTypesMatchAux(c, m, f, a, arg)
result = ParamTypesMatchAux(c, m, f, a, arg, argOrig)
else:
# CAUTION: The order depends on the used hashing scheme. Thus it is
# incorrect to simply use the first fitting match. However, to implement
@@ -591,29 +600,29 @@ proc ParamTypesMatch(c: PContext, m: var TCandidate, f, a: PType,
else:
# only one valid interpretation found:
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 =
var m: TCandidate
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 =
var m: TCandidate
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 =
var m: TCandidate
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) =
if sonsLen(father) <= at: setlen(father.sons, at + 1)
father.sons[at] = son
proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
marker: var TIntSet) =
proc matchesAux*(c: PContext, n, nOrig: PNode,
m: var TCandidate, marker: var TIntSet) =
var f = 1 # iterates over formal parameters
var a = 1 # iterates over the actual given arguments
m.state = csMatch # until proven otherwise
@@ -623,7 +632,7 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
addSon(m.call, copyTree(n.sons[0]))
var container: PNode = nil # constructed container
var formal: PSym = nil
while a < sonsLen(n):
while a < n.len:
if n.sons[a].kind == nkExprEqExpr:
# named param
# check if m.callee has such a param:
@@ -642,8 +651,8 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
m.state = csNoMatch
return
m.baseTypeMatch = false
var arg = ParamTypesMatch(c, m, formal.typ,
n.sons[a].typ, n.sons[a].sons[1])
var arg = ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
n.sons[a].sons[1], nOrig.sons[a].sons[1])
if arg == nil:
m.state = csNoMatch
return
@@ -666,9 +675,10 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
copyTree(n.sons[a]), m, c))
else:
addSon(m.call, copyTree(n.sons[a]))
elif formal != nil:
elif formal != nil:
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):
addSon(container, arg)
else:
@@ -687,7 +697,8 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
m.state = csNoMatch
return
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:
m.state = csNoMatch
return
@@ -703,14 +714,14 @@ proc matchesAux*(c: PContext, n: PNode, m: var TCandidate,
inc(a)
inc(f)
proc partialMatch*(c: PContext, n: PNode, m: var TCandidate) =
proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
# for 'suggest' support:
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()
matchesAux(c, n, m, marker)
matchesAux(c, n, nOrig, m, marker)
if m.state == csNoMatch: return
# check that every formal parameter got a value:
var f = 1

View File

@@ -46,7 +46,7 @@ proc suggestField(s: PSym) =
if filterSym(s):
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 it in items(c.tab.stack[i]):
if cond:
@@ -79,20 +79,18 @@ proc nameFits(c: PContext, s: PSym, n: PNode): bool =
else: return false
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
of skProc, skIterator, skMethod:
of OverloadableSyms:
var m: TCandidate
initCandidate(m, candidate, nil)
sigmatch.partialMatch(c, n, m)
sigmatch.partialMatch(c, n, nOrig, m)
result = m.state != csNoMatch
of skTemplate, skMacro:
result = true
else:
result = false
proc suggestCall(c: PContext, n: PNode) =
wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n),
proc suggestCall(c: PContext, n, nOrig: PNode) =
wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n, nOrig),
sectionContext)
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])
if x.kind == nkEmpty or x.typ == nil: break
addSon(a, x)
suggestCall(c, a)
suggestCall(c, a, n)
if optDef in gGlobalOptions:
var n = findClosestSym(fuzzySemCheck(c, node))

View File

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