diff options
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 13 | ||||
-rwxr-xr-x | compiler/astalgo.nim | 13 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 3 | ||||
-rwxr-xr-x | compiler/lookups.nim | 11 | ||||
-rwxr-xr-x | compiler/pragmas.nim | 8 | ||||
-rwxr-xr-x | compiler/sem.nim | 27 | ||||
-rwxr-xr-x | compiler/semcall.nim | 107 | ||||
-rwxr-xr-x | compiler/semdata.nim | 2 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 100 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 3 | ||||
-rwxr-xr-x | compiler/semtempl.nim | 24 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 1 | ||||
-rwxr-xr-x | compiler/sigmatch.nim | 61 | ||||
-rwxr-xr-x | compiler/suggest.nim | 16 | ||||
-rwxr-xr-x | compiler/wordrecg.nim | 4 |
15 files changed, 238 insertions, 155 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 6b2681f2a..a1b69bed8 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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} @@ -790,6 +794,13 @@ proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode = result = newNode(kind) result.info = info +proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[], + typ: PType = nil): PNode = + result = newNode(kind) + result.info = info + result.typ = typ + result.sons = sons + proc newNodeIT(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = result = newNode(kind) result.info = info diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 7128102a8..9da0d3a20 100755 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -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) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index fef1b055d..072b2f9fb 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -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 diff --git a/compiler/lookups.nim b/compiler/lookups.nim index ff078c82d..ee77b3633 100755 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -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 diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 99570aa12..1ceacfc1c 100755 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -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: diff --git a/compiler/sem.nim b/compiler/sem.nim index 1c1b4351d..7d296dbfc 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index c92eff319..f0c9f42b0 100755 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -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 = +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: + initialBinding = nil + var o: TOverloadIter - x, y, z: TCandidate + alt, z: TCandidate + + template best: expr = result #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) + 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) + while sym != nil: + if sym.kind in filter: + initCandidate(z, sym, initialBinding, o.lastOverloadScope) z.calleeSym = sym - matches(c, n, z) - if z.state == csMatch: + 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 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 + 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 x.state == csEmpty: + + if best.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") + 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(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 f = n.sons[0] - if f.kind == nkBracketExpr: - # fill in the bindings: - initialBinding = f - f = f.sons[0] - else: - initialBinding = nil - result = semDirectCallWithBinding(c, n, f, filter, initialBinding) + 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 diff --git a/compiler/semdata.nim b/compiler/semdata.nim index f47139e18..49ab20290 100755 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -73,7 +73,7 @@ type userPragmas*: TStrTable evalContext*: PEvalContext slurpedFiles*: seq[string] - + var gGenericsCache: PGenericsCache # save for modularity diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d423acc17..d3b30e24b 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 5b4639f26..e5f10ece1 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 770a3ae8e..2600d80cb 100755 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -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) + diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index cec3a9f7e..b8f703a51 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index c21dc3c6e..ca65c670f 100755 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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 diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 5074cb2c4..ff1f9607f 100755 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -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)) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 2d8f25db6..a29f3e762 100755 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -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", |