diff options
Diffstat (limited to 'compiler')
31 files changed, 349 insertions, 254 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 04f62d66f..7fef34a27 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1366,7 +1366,7 @@ proc updateCachedModule(m: BModule) = cf.flags = {CfileFlag.Cached} addFileToCompile(cf) -proc myClose(b: PPassContext, n: PNode): PNode = +proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = result = n if b == nil or passes.skipCodegen(n): return var m = BModule(b) @@ -1378,7 +1378,7 @@ proc myClose(b: PPassContext, n: PNode): PNode = if sfMainModule in m.module.flags: incl m.flags, objHasKidsValid - var disp = generateMethodDispatchers() + var disp = generateMethodDispatchers(graph) for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym) genMainProc(m) diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index eda80be30..1d7f5a6e1 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -11,7 +11,7 @@ import intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys, - sempass2, strutils + sempass2, strutils, modulegraphs proc genConv(n: PNode, d: PType, downcast: bool): PNode = var dest = skipTypes(d, abstractPtrs) @@ -35,19 +35,24 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode = else: result = n +proc getDispatcher*(s: PSym): PSym = + ## can return nil if is has no dispatcher. + let dispn = lastSon(s.ast) + if dispn.kind == nkSym: + let disp = dispn.sym + if sfDispatcher in disp.flags: result = disp + proc methodCall*(n: PNode): PNode = result = n # replace ordinary method by dispatcher method: - var disp = lastSon(result.sons[0].sym.ast).sym - assert sfDispatcher in disp.flags - result.sons[0].sym = disp - # change the arguments to up/downcasts to fit the dispatcher's parameters: - for i in countup(1, sonsLen(result)-1): - result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true) - -# save for incremental compilation: -var - gMethods: seq[tuple[methods: TSymSeq, dispatcher: PSym]] = @[] + let disp = getDispatcher(result.sons[0].sym) + if disp != nil: + result.sons[0].sym = disp + # change the arguments to up/downcasts to fit the dispatcher's parameters: + for i in countup(1, sonsLen(result)-1): + result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true) + else: + localError(n.info, "'" & $result.sons[0] & "' lacks a dispatcher") type MethodResult = enum No, Invalid, Yes @@ -55,8 +60,8 @@ type proc sameMethodBucket(a, b: PSym): MethodResult = if a.name.id != b.name.id: return if sonsLen(a.typ) != sonsLen(b.typ): - return # check for return type: - if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]): return + return + for i in countup(1, sonsLen(a.typ) - 1): var aa = a.typ.sons[i] var bb = b.typ.sons[i] @@ -84,6 +89,14 @@ proc sameMethodBucket(a, b: PSym): MethodResult = return No else: return No + if result == Yes: + # check for return type: + if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]): + if b.typ.sons[0] != nil and b.typ.sons[0].kind == tyExpr: + # infer 'auto' from the base to make it consistent: + b.typ.sons[0] = a.typ.sons[0] + else: + return No proc attachDispatcher(s: PSym, dispatcher: PNode) = var L = s.ast.len-1 @@ -144,27 +157,27 @@ proc fixupDispatcher(meth, disp: PSym) = if disp.typ.lockLevel < meth.typ.lockLevel: disp.typ.lockLevel = meth.typ.lockLevel -proc methodDef*(s: PSym, fromCache: bool) = - let L = len(gMethods) +proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) = + let L = len(g.methods) var witness: PSym for i in countup(0, L - 1): - let disp = gMethods[i].dispatcher + let disp = g.methods[i].dispatcher case sameMethodBucket(disp, s) of Yes: - add(gMethods[i].methods, s) + add(g.methods[i].methods, s) attachDispatcher(s, lastSon(disp.ast)) fixupDispatcher(s, disp) #echo "fixup ", disp.name.s, " ", disp.id when useEffectSystem: checkMethodEffects(disp, s) - if sfBase in s.flags and gMethods[i].methods[0] != s: + if sfBase in s.flags and g.methods[i].methods[0] != s: # already exists due to forwarding definition? localError(s.info, "method is not a base") return of No: discard of Invalid: - if witness.isNil: witness = gMethods[i].methods[0] + if witness.isNil: witness = g.methods[i].methods[0] # create a new dispatcher: - add(gMethods, (methods: @[s], dispatcher: createDispatcher(s))) + add(g.methods, (methods: @[s], dispatcher: createDispatcher(s))) #echo "adding ", s.info #if fromCache: # internalError(s.info, "no method dispatcher found") @@ -258,12 +271,12 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym = disp = ret result.ast.sons[bodyPos] = disp -proc generateMethodDispatchers*(): PNode = +proc generateMethodDispatchers*(g: ModuleGraph): PNode = result = newNode(nkStmtList) - for bucket in countup(0, len(gMethods) - 1): + for bucket in countup(0, len(g.methods) - 1): var relevantCols = initIntSet() - for col in countup(1, sonsLen(gMethods[bucket].methods[0].typ) - 1): - if relevantCol(gMethods[bucket].methods, col): incl(relevantCols, col) - sortBucket(gMethods[bucket].methods, relevantCols) + for col in countup(1, sonsLen(g.methods[bucket].methods[0].typ) - 1): + if relevantCol(g.methods[bucket].methods, col): incl(relevantCols, col) + sortBucket(g.methods[bucket].methods, relevantCols) addSon(result, - newSymNode(genDispatcher(gMethods[bucket].methods, relevantCols))) + newSymNode(genDispatcher(g.methods[bucket].methods, relevantCols))) diff --git a/compiler/compilerlog.nim b/compiler/compilerlog.nim new file mode 100644 index 000000000..fbf8cd9aa --- /dev/null +++ b/compiler/compilerlog.nim @@ -0,0 +1,9 @@ + +from os import getHomeDir, `/` + +proc logStr*(line: string) = + var f: File + if open(f, getHomeDir() / "nimsuggest.log", fmAppend): + f.writeLine(line) + f.close() + diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 9504ab52f..118f1c7c5 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -33,11 +33,11 @@ template closeImpl(body: untyped) {.dirty.} = except IOError: discard -proc close(p: PPassContext, n: PNode): PNode = +proc close(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = closeImpl: writeOutput(g.doc, g.module.filename, HtmlExt, useWarning) -proc closeJson(p: PPassContext, n: PNode): PNode = +proc closeJson(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = closeImpl: writeOutputJson(g.doc, g.module.filename, ".json", useWarning) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 7d40fe44a..8f819686d 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2237,13 +2237,13 @@ proc myProcess(b: PPassContext, n: PNode): PNode = add(p.g.code, p.body) globals.unique = p.unique -proc wholeCode*(m: BModule): Rope = +proc wholeCode(graph: ModuleGraph; m: BModule): Rope = for prc in globals.forwarded: if not globals.generatedSyms.containsOrIncl(prc.id): var p = newProc(globals, m, nil, m.module.options) attachProc(p, prc) - var disp = generateMethodDispatchers() + var disp = generateMethodDispatchers(graph) for i in 0..sonsLen(disp)-1: let prc = disp.sons[i].sym if not globals.generatedSyms.containsOrIncl(prc.id): @@ -2277,7 +2277,7 @@ proc genClass(obj: PType; content: Rope; ext: string) = let outfile = changeFileExt(completeCFilePath($cls), ext) discard writeRopeIfNotEqual(result, outfile) -proc myClose(b: PPassContext, n: PNode): PNode = +proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode = if passes.skipCodegen(n): return n result = myProcess(b, n) var m = BModule(b) @@ -2285,7 +2285,7 @@ proc myClose(b: PPassContext, n: PNode): PNode = let ext = if m.target == targetJS: "js" else: "php" let f = if globals.classes.len == 0: m.module.filename else: "nimsystem" - let code = wholeCode(m) + let code = wholeCode(graph, m) let outfile = if options.outFile.len > 0: if options.outFile.isAbsolute: options.outFile diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 19a4da07b..089e69ff9 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -115,7 +115,7 @@ proc errorSym*(c: PContext, n: PNode): PSym = considerQuotedIdent(m) else: getIdent("err:" & renderTree(m)) - result = newSym(skError, ident, getCurrOwner(), n.info) + result = newSym(skError, ident, getCurrOwner(c), n.info) result.typ = errorType(c) incl(result.flags, sfDiscardable) # pretend it's imported from some unknown module to prevent cascading errors: diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 87a35b290..c081a099a 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -40,9 +40,16 @@ type # module dependencies. backend*: RootRef # minor hack so that a backend can extend this easily config*: ConfigRef + doStopCompile*: proc(): bool {.closure.} + usageSym*: PSym # for nimsuggest + owners*: seq[PSym] + methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]] {.this: g.} +proc stopCompile*(g: ModuleGraph): bool {.inline.} = + result = doStopCompile != nil and doStopCompile() + proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph = result = ModuleGraph() initStrTable(result.packageSyms) @@ -54,6 +61,8 @@ proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph = result.config = newConfigRef() else: result.config = config + result.owners = @[] + result.methods = @[] proc resetAllModules*(g: ModuleGraph) = initStrTable(packageSyms) @@ -61,6 +70,9 @@ proc resetAllModules*(g: ModuleGraph) = modules = @[] importStack = @[] inclToMod = initTable[int32, int32]() + usageSym = nil + owners = @[] + methods = @[] proc getModule*(g: ModuleGraph; fileIdx: int32): PSym = if fileIdx >= 0 and fileIdx < modules.len: @@ -73,7 +85,7 @@ proc addDep*(g: ModuleGraph; m: PSym, dep: int32) = deps.incl m.position.dependsOn(dep) # we compute the transitive closure later when quering the graph lazily. # this improve efficiency quite a lot: - invalidTransitiveClosure = true + #invalidTransitiveClosure = true proc addIncludeDep*(g: ModuleGraph; module, includeFile: int32) = discard hasKeyOrPut(inclToMod, includeFile, module) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 49e4fa184..a1ba82263 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -567,6 +567,15 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo = if optEmbedOrigSrc in gGlobalOptions or true: result.lines = @[] +proc fileInfoKnown*(filename: string): bool = + var + canon: string + try: + canon = canonicalizePath(filename) + except: + canon = filename + result = filenameToIndexTbl.hasKey(canon) + proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 = var canon: string diff --git a/compiler/options.nim b/compiler/options.nim index 7fd7129e5..6281980ff 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -100,7 +100,7 @@ type IdeCmd* = enum ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod, - ideHighlight, ideOutline + ideHighlight, ideOutline, ideKnown ConfigRef* = ref object ## eventually all global configuration should be moved here cppDefines*: HashSet[string] @@ -436,6 +436,7 @@ proc parseIdeCmd*(s: string): IdeCmd = of "mod": ideMod of "highlight": ideHighlight of "outline": ideOutline + of "known": ideKnown else: ideNone proc `$`*(c: IdeCmd): string = @@ -450,3 +451,4 @@ proc `$`*(c: IdeCmd): string = of ideNone: "none" of ideHighlight: "highlight" of ideOutline: "outline" + of ideKnown: "known" diff --git a/compiler/passaux.nim b/compiler/passaux.nim index eeaf12953..2065d5893 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -29,21 +29,3 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode = message(n.info, hintProcessing, $idgen.gFrontendId) const verbosePass* = makePass(open = verboseOpen, process = verboseProcess) - -proc cleanUp(c: PPassContext, n: PNode): PNode = - result = n - # we cannot clean up if dead code elimination is activated - if optDeadCodeElim in gGlobalOptions or n == nil: return - case n.kind - of nkStmtList: - for i in countup(0, sonsLen(n) - 1): discard cleanUp(c, n.sons[i]) - of nkProcDef, nkMethodDef: - if n.sons[namePos].kind == nkSym: - var s = n.sons[namePos].sym - if sfDeadCodeElim notin getModule(s).flags and not astNeeded(s): - s.ast.sons[bodyPos] = ast.emptyNode # free the memory - else: - discard - -const cleanupPass* = makePass(process = cleanUp, close = cleanUp) - diff --git a/compiler/passes.nim b/compiler/passes.nim index 328826f82..7966ee88d 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -24,7 +24,7 @@ type TPassOpen* = proc (graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext {.nimcall.} TPassOpenCached* = proc (graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext {.nimcall.} - TPassClose* = proc (p: PPassContext, n: PNode): PNode {.nimcall.} + TPassClose* = proc (graph: ModuleGraph; p: PPassContext, n: PNode): PNode {.nimcall.} TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.} TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached, @@ -94,7 +94,7 @@ proc carryPass*(g: ModuleGraph; p: TPass, module: PSym; cache: IdentCache; m: TPassData): TPassData = var c = p.open(g, module, cache) result.input = p.process(c, m.input) - result.closeOutput = if p.close != nil: p.close(c, m.closeOutput) + result.closeOutput = if p.close != nil: p.close(g, c, m.closeOutput) else: m.closeOutput proc carryPasses*(g: ModuleGraph; nodes: PNode, module: PSym; @@ -121,10 +121,10 @@ proc openPassesCached(g: ModuleGraph; a: var TPassContextArray, module: PSym, else: a[i] = nil -proc closePasses(a: var TPassContextArray) = +proc closePasses(graph: ModuleGraph; a: var TPassContextArray) = var m: PNode = nil for i in countup(0, gPassesLen - 1): - if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m) + if not isNil(gPasses[i].close): m = gPasses[i].close(graph, a[i], m) a[i] = nil # free the memory here proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool = @@ -142,11 +142,11 @@ proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) = for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m) -proc closePassesCached(a: var TPassContextArray) = +proc closePassesCached(graph: ModuleGraph; a: var TPassContextArray) = var m: PNode = nil for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close): - m = gPasses[i].close(a[i], m) + m = gPasses[i].close(graph, a[i], m) a[i] = nil # free the memory here proc resolveMod(module, relativeTo: string): int32 = @@ -171,6 +171,7 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind, proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, rd: PRodReader; cache: IdentCache): bool {.discardable.} = + if graph.stopCompile(): return true var p: TParsers a: TPassContextArray @@ -198,6 +199,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, processImplicits implicitIncludes, nkIncludeStmt, a, module while true: + if graph.stopCompile(): break var n = parseTopLevelStmt(p) if n.kind == nkEmpty: break if sfNoForward in module.flags: @@ -213,12 +215,14 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, elif not processTopLevelStmt(n, a): break closeParsers(p) if s.kind != llsStdIn: break - closePasses(a) + closePasses(graph, a) # id synchronization point for more consistent code generation: idSynchronizationPoint(1000) else: openPassesCached(graph, a, module, rd) var n = loadInitSection(rd) - for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a) - closePassesCached(a) + for i in countup(0, sonsLen(n) - 1): + if graph.stopCompile(): break + processTopLevelStmtCached(n.sons[i], a) + closePassesCached(graph, a) result = true diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 09b8d3305..859fe2a81 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -289,7 +289,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode = # constraint not fulfilled: if not ok: return nil - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) if ctx.subMatch: assert m.len == 3 m.sons[1] = result diff --git a/compiler/plugins/locals/locals.nim b/compiler/plugins/locals/locals.nim index 8a3f67dd4..338e7bcac 100644 --- a/compiler/plugins/locals/locals.nim +++ b/compiler/plugins/locals/locals.nim @@ -28,7 +28,7 @@ proc semLocals(c: PContext, n: PNode): PNode = it.typ.skipTypes({tyGenericInst, tyVar}).kind notin {tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}: - var field = newSym(skField, it.name, getCurrOwner(), n.info) + var field = newSym(skField, it.name, getCurrOwner(c), n.info) field.typ = it.typ.skipTypes({tyGenericInst, tyVar}) field.position = counter inc(counter) diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 4ce9e616a..d61d817dd 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -641,7 +641,7 @@ proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = rawAddInterfaceSym(w, module) result = w -proc myClose(c: PPassContext, n: PNode): PNode = +proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = result = process(c, n) var w = PRodWriter(c) writeRod(w) diff --git a/compiler/sem.nim b/compiler/sem.nim index 59d726b43..682e9d0ca 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -166,7 +166,7 @@ proc commonType*(x, y: PType): PType = result.addSonSkipIntLit(r) proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = - result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info) + result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = proc `$`(kind: TSymKind): string = substr(system.`$`(kind), 2).toLowerAscii @@ -186,9 +186,9 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = # when there is a nested proc inside a template, semtmpl # will assign a wrong owner during the first pass over the # template; we must fix it here: see #909 - result.owner = getCurrOwner() + result.owner = getCurrOwner(c) else: - result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info) + result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info) #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule: # incl(result.flags, sfGlobal) @@ -376,7 +376,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, flags: TExprFlags = {}): PNode = pushInfoContext(nOrig.info) - markUsed(n.info, sym) + markUsed(n.info, sym, c.graph.usageSym) styleCheckUse(n.info, sym) if sym == c.p.owner: globalError(n.info, errRecursiveDependencyX, sym.name.s) @@ -434,7 +434,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = c.instTypeBoundOp = sigmatch.instTypeBoundOp pushProcCon(c, module) - pushOwner(c.module) + pushOwner(c, c.module) c.importTable = openScope(c) c.importTable.addSym(module) # a module knows itself if sfSystemModule in module.flags: @@ -450,7 +450,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext = result = myOpen(graph, module, rd.cache) - for m in items(rd.methods): methodDef(m, true) + for m in items(rd.methods): methodDef(graph, m, true) proc isImportSystemStmt(n: PNode): bool = if magicsys.systemModule == nil: return false @@ -502,7 +502,7 @@ proc recoverContext(c: PContext) = # faster than wrapping every stack operation in a 'try finally' block and # requires far less code. c.currentScope = c.topLevelScope - while getCurrOwner().kind != skModule: popOwner() + while getCurrOwner(c).kind != skModule: popOwner(c) while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next proc myProcess(context: PPassContext, n: PNode): PNode = @@ -523,7 +523,7 @@ proc myProcess(context: PPassContext, n: PNode): PNode = else: result = ast.emptyNode #if gCmd == cmdIdeTools: findSuggest(c, n) -proc myClose(context: PPassContext, n: PNode): PNode = +proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode = var c = PContext(context) closeScope(c) # close module's scope rawCloseScope(c) # imported symbols; don't check for unused ones! @@ -533,7 +533,7 @@ proc myClose(context: PPassContext, n: PNode): PNode = addCodeForGenerics(c, result) if c.module.ast != nil: result.add(c.module.ast) - popOwner() + popOwner(c) popProcCon(c) const semPass* = makePass(myOpen, myOpenCached, myProcess, myClose) diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index c4dc13624..70765d087 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -105,7 +105,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = of attachedDestructor: let op = t.destructor if op != nil: - markUsed(c.info, op) + markUsed(c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add newDestructorCall(op, x) result = true @@ -123,14 +123,14 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = op = t.assignment if op == nil: op = liftBody(c.c, t, c.info) - markUsed(c.info, op) + markUsed(c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add newAsgnCall(c.c, op, x, y) result = true of attachedDeepCopy: let op = t.deepCopy if op != nil: - markUsed(c.info, op) + markUsed(c.info, op, c.c.graph.usageSym) styleCheckUse(c.info, op) body.add newDeepCopyCall(op, x, y) result = true @@ -248,6 +248,7 @@ proc addParam(procType: PType; param: PSym) = proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym = var a: TLiftCtx a.info = info + a.c = c let body = newNodeI(nkStmtList, info) result = newSym(skProc, getIdent":lifted=", typ.owner, info) a.fn = result diff --git a/compiler/semcall.nim b/compiler/semcall.nim index ae7bab89d..fe73d60e6 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -335,7 +335,7 @@ proc inferWithMetatype(c: PContext, formal: PType, proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = assert x.state == csMatch var finalCallee = x.calleeSym - markUsed(n.sons[0].info, finalCallee) + markUsed(n.sons[0].info, finalCallee, c.graph.usageSym) styleCheckUse(n.sons[0].info, finalCallee) assert finalCallee.ast != nil if x.hasFauxMatch: @@ -411,7 +411,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = let tm = typeRel(m, formal, arg, true) if tm in {isNone, isConvertible}: return nil var newInst = generateInstance(c, s, m.bindings, n.info) - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(newInst, n.info) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index b501ec440..77d461007 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -124,22 +124,19 @@ proc scopeDepth*(c: PContext): int {.inline.} = result = if c.currentScope != nil: c.currentScope.depthLevel else: 0 -var gOwners*: seq[PSym] = @[] - -proc getCurrOwner*(): PSym = +proc getCurrOwner*(c: PContext): PSym = # owner stack (used for initializing the # owner field of syms) # the documentation comment always gets # assigned to the current owner - # BUGFIX: global array is needed! - result = gOwners[^1] + result = c.graph.owners[^1] -proc pushOwner*(owner: PSym) = - add(gOwners, owner) +proc pushOwner*(c: PContext; owner: PSym) = + add(c.graph.owners, owner) -proc popOwner*() = - var length = len(gOwners) - if length > 0: setLen(gOwners, length - 1) +proc popOwner*(c: PContext) = + var length = len(c.graph.owners) + if length > 0: setLen(c.graph.owners, length - 1) else: internalError("popOwner") proc lastOptionEntry*(c: PContext): POptionEntry = @@ -225,7 +222,7 @@ proc addToLib*(lib: PLib, sym: PSym) = sym.annex = lib proc newTypeS*(kind: TTypeKind, c: PContext): PType = - result = newType(kind, getCurrOwner()) + result = newType(kind, getCurrOwner(c)) proc makePtrType*(c: PContext, baseType: PType): PType = result = newTypeS(tyPtr, c) @@ -244,7 +241,7 @@ proc makeTypeDesc*(c: PContext, typ: PType): PType = proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = let typedesc = makeTypeDesc(c, typ) - let sym = newSym(skType, c.cache.idAnon, getCurrOwner(), info).linkTo(typedesc) + let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info).linkTo(typedesc) return newSymNode(sym, info) proc makeTypeFromExpr*(c: PContext, n: PNode): PType = @@ -254,7 +251,7 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType = proc newTypeWithSons*(c: PContext, kind: TTypeKind, sons: seq[PType]): PType = - result = newType(kind, getCurrOwner()) + result = newType(kind, getCurrOwner(c)) result.sons = sons proc makeStaticExpr*(c: PContext, n: PNode): PNode = @@ -325,7 +322,7 @@ proc errorNode*(c: PContext, n: PNode): PNode = proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) = dest.kind = kind - dest.owner = getCurrOwner() + dest.owner = getCurrOwner(c) dest.size = - 1 proc makeRangeType*(c: PContext; first, last: BiggestInt; diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim index a8873bbe2..b09404b39 100644 --- a/compiler/semdestruct.nim +++ b/compiler/semdestruct.nim @@ -51,7 +51,7 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) = let destructableT = instantiateDestructor(c, t.sons[i]) if destructableT != nil: n.sons[bodyPos].addSon(newNode(nkCall, t.sym.info, @[ - useSym(destructableT.destructor), + useSym(destructableT.destructor, c.graph.usageSym), n.sons[paramsPos][1][0]])) proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode @@ -60,8 +60,8 @@ proc destroySym(c: PContext, field: PSym, holder: PNode): PNode = let destructableT = instantiateDestructor(c, field.typ) if destructableT != nil: result = newNode(nkCall, field.info, @[ - useSym(destructableT.destructor), - newNode(nkDotExpr, field.info, @[holder, useSym(field)])]) + useSym(destructableT.destructor, c.graph.usageSym), + newNode(nkDotExpr, field.info, @[holder, useSym(field, c.graph.usageSym)])]) proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode = var nonTrivialFields = 0 @@ -181,7 +181,8 @@ proc createDestructorCall(c: PContext, s: PSym): PNode = let destructableT = instantiateDestructor(c, varTyp) if destructableT != nil: let call = semStmt(c, newNode(nkCall, s.info, @[ - useSym(destructableT.destructor), useSym(s)])) + useSym(destructableT.destructor, c.graph.usageSym), + useSym(s, c.graph.usageSym)])) result = newNode(nkDefer, s.info, @[call]) proc insertDestructors(c: PContext, @@ -233,8 +234,8 @@ proc insertDestructors(c: PContext, tryStmt.addSon( newNode(nkFinally, info, @[ semStmt(c, newNode(nkCall, info, @[ - useSym(destructableT.destructor), - useSym(varId.sym)]))])) + useSym(destructableT.destructor, c.graph.usageSym), + useSym(varId.sym, c.graph.usageSym)]))])) result.outer = newNodeI(nkStmtList, info) varSection.sons.setLen(j+1) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d9a5f6c50..6db7724f9 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -12,10 +12,10 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, flags: TExprFlags = {}): PNode = - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) pushInfoContext(n.info) - result = evalTemplate(n, s, getCurrOwner(), efFromHlo in flags) + result = evalTemplate(n, s, getCurrOwner(c), efFromHlo in flags) if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags) popInfoContext() @@ -209,7 +209,7 @@ proc semConv(c: PContext, n: PNode): PNode = let it = op.sons[i] let status = checkConvertible(c, result.typ, it.typ) if status in {convOK, convNotNeedeed}: - markUsed(n.info, it.sym) + markUsed(n.info, it.sym, c.graph.usageSym) styleCheckUse(n.info, it.sym) markIndirect(c, it.sym) return it @@ -926,7 +926,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = let s = getGenSym(c, sym) case s.kind of skConst: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, @@ -950,20 +950,20 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = result = newSymNode(s, n.info) of skMacro: if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) else: result = semMacroExpr(c, n, n, s, flags) of skTemplate: if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) else: result = semTemplateExpr(c, n, s, flags) of skParam: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) if s.typ.kind == tyStatic and s.typ.n != nil: # XXX see the hack in sigmatch.nim ... @@ -985,7 +985,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if s.magic == mNimvm: localError(n.info, "illegal context for 'nimvm' magic") - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) # We cannot check for access to outer vars for example because it's still @@ -1003,7 +1003,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = n.typ = s.typ return n of skType: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) if s.typ.kind == tyStatic and s.typ.n != nil: return s.typ.n @@ -1025,7 +1025,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if f != nil and fieldVisible(c, f): # is the access to a public field or in the same module or in a friend? doAssert f == s - markUsed(n.info, f) + markUsed(n.info, f, c.graph.usageSym) styleCheckUse(n.info, f) result = newNodeIT(nkDotExpr, n.info, f.typ) result.add makeDeref(newSymNode(p.selfSym)) @@ -1038,11 +1038,11 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if ty.sons[0] == nil: break ty = skipTypes(ty.sons[0], skipPtrs) # old code, not sure if it's live code: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) else: - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) @@ -1062,7 +1062,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = symChoice(c, n, s, scClosed) if result.kind == nkSym: result = semSym(c, n, s, flags) else: - markUsed(n.sons[1].info, s) + markUsed(n.sons[1].info, s, c.graph.usageSym) result = semSym(c, n, s, flags) styleCheckUse(n.sons[1].info, s) return @@ -1087,7 +1087,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = newSymNode(f) result.info = n.info result.typ = ty - markUsed(n.info, f) + markUsed(n.info, f, c.graph.usageSym) styleCheckUse(n.info, f) return of tyTypeParamsHolders: @@ -1120,7 +1120,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = if f != nil: if fieldVisible(c, f): # is the access to a public field or in the same module or in a friend? - markUsed(n.sons[1].info, f) + markUsed(n.sons[1].info, f, c.graph.usageSym) styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) # we now have the correct field @@ -1134,7 +1134,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = elif ty.kind == tyTuple and ty.n != nil: f = getSymFromList(ty.n, i) if f != nil: - markUsed(n.sons[1].info, f) + markUsed(n.sons[1].info, f, c.graph.usageSym) styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) @@ -1581,9 +1581,8 @@ proc getMagicSym(magic: TMagic): PSym = result = newSym(skProc, getIdent($magic), systemModule, gCodegenLineInfo) result.magic = magic -proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo, - owner = getCurrOwner()): PSym = - result = newSym(kind, c.cache.idAnon, owner, info) +proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym = + result = newSym(kind, c.cache.idAnon, getCurrOwner(c), info) result.flags = {sfGenSym} proc semExpandToAst(c: PContext, n: PNode): PNode = @@ -1592,7 +1591,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = if expandedSym.kind == skError: return n macroCall.sons[0] = newSymNode(expandedSym, macroCall.info) - markUsed(n.info, expandedSym) + markUsed(n.info, expandedSym, c.graph.usageSym) styleCheckUse(n.info, expandedSym) for i in countup(1, macroCall.len-1): @@ -1683,7 +1682,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # open a scope for temporary symbol inclusions: let oldScope = c.currentScope openScope(c) - let oldOwnerLen = len(gOwners) + let oldOwnerLen = len(c.graph.owners) let oldGenerics = c.generics let oldErrorOutputs = errorOutputs errorOutputs = {} @@ -1709,7 +1708,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = c.inGenericInst = oldInGenericInst c.p = oldProcCon msgs.setInfoContextLen(oldContextLen) - setLen(gOwners, oldOwnerLen) + setLen(c.graph.owners, oldOwnerLen) c.currentScope = oldScope errorOutputs = oldErrorOutputs msgs.gErrorCounter = oldErrorCount @@ -2108,7 +2107,7 @@ proc semBlock(c: PContext, n: PNode): PNode = if sfGenSym notin labl.flags: addDecl(c, labl) n.sons[0] = newSymNode(labl, n.sons[0].info) - suggestSym(n.sons[0].info, labl) + suggestSym(n.sons[0].info, labl, c.graph.usageSym) styleCheckDef(labl) n.sons[1] = semExpr(c, n.sons[1]) n.typ = n.sons[1].typ diff --git a/compiler/semfields.nim b/compiler/semfields.nim index 9d8cea862..5ac1ad11a 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -108,7 +108,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true") if trueSymbol == nil: localError(n.info, errSystemNeeds, "true") - trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info) + trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(c), n.info) trueSymbol.typ = getSysType(tyBool) result.sons[0] = newSymNode(trueSymbol, n.info) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index acaade494..82d27cf10 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -61,7 +61,7 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses: continue let symKind = if q.typ.kind == tyStatic: skConst else: skType - var s = newSym(symKind, q.name, getCurrOwner(), q.info) + var s = newSym(symKind, q.name, getCurrOwner(c), q.info) s.flags = s.flags + {sfUsed, sfFromGeneric} var t = PType(idTableGet(pt, q.typ)) if t == nil: @@ -255,7 +255,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, incl(result.flags, sfFromGeneric) result.owner = fn result.ast = n - pushOwner(result) + pushOwner(c, result) openScope(c) let gp = n.sons[genericParamsPos] @@ -304,7 +304,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, popProcCon(c) popInfoContext() closeScope(c) # close scope for parameters - popOwner() + popOwner(c) c.currentScope = oldScope discard c.friendModules.pop() dec(c.instCounter) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index e72172c81..5eed1e702 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -107,7 +107,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode = if t.sonsLen > 0: # This is either a type known to sem or a typedesc # param to a regular proc (again, known at instantiation) - result = evalTypeTrait(n[0], t, getCurrOwner()) + result = evalTypeTrait(n[0], t, getCurrOwner(c)) else: # a typedesc variable, pass unmodified to evals result = n diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 282d4da88..c28dbf82f 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -36,7 +36,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = x.info = n.info incl(s.flags, sfUsed) n.sons[0] = x - suggestSym(x.info, s) + suggestSym(x.info, s, c.graph.usageSym) styleCheckUse(x.info, s) else: localError(n.info, errInvalidControlFlowX, s.name.s) @@ -367,11 +367,13 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = if isTopLevel(c): result = semIdentWithPragma(c, kind, n, {sfExported}) incl(result.flags, sfGlobal) + #if kind in {skVar, skLet}: + # echo "global variable here ", n.info, " ", result.name.s else: result = semIdentWithPragma(c, kind, n, {}) if result.owner.kind == skModule: incl(result.flags, sfGlobal) - suggestSym(n.info, result) + suggestSym(n.info, result, c.graph.usageSym) styleCheckDef(result) proc checkNilable(v: PSym) = @@ -622,7 +624,7 @@ proc semForVars(c: PContext, n: PNode): PNode = if iter.kind != tyTuple or length == 3: if length == 3: var v = symForVar(c, n.sons[0]) - if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal) + if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal) # BUGFIX: don't use `iter` here as that would strip away # the ``tyGenericInst``! See ``tests/compile/tgeneric.nim`` # for an example: @@ -636,7 +638,7 @@ proc semForVars(c: PContext, n: PNode): PNode = else: for i in countup(0, length - 3): var v = symForVar(c, n.sons[i]) - if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal) + if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal) v.typ = iter.sons[i] n.sons[i] = newSymNode(v) if sfGenSym notin v.flags and not isDiscardUnderscore(v): @@ -746,7 +748,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = # We have a generic type declaration here. In generic types, # symbol lookup needs to be done here. openScope(c) - pushOwner(s) + pushOwner(c, s) if s.magic == mNone: s.typ.kind = tyGenericBody # XXX for generic type aliases this is not correct! We need the # underlying Id really: @@ -770,11 +772,11 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = body.sym = s body.size = -1 # could not be computed properly s.typ.sons[sonsLen(s.typ) - 1] = body - popOwner() + popOwner(c) closeScope(c) elif a.sons[2].kind != nkEmpty: # process the type's body: - pushOwner(s) + pushOwner(c, s) var t = semTypeNode(c, a.sons[2], s.typ) if s.typ == nil: s.typ = t @@ -783,7 +785,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = assignType(s.typ, t) #debug s.typ s.ast = a - popOwner() + popOwner(c) let aa = a.sons[2] if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and aa.sons[0].kind == nkObjectTy: @@ -794,7 +796,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = internalAssert st.lastSon.sym == nil incl st.flags, tfRefsAnonObj let obj = newSym(skType, getIdent(s.name.s & ":ObjectType"), - getCurrOwner(), s.info) + getCurrOwner(c), s.info) obj.typ = st.lastSon st.lastSon.sym = obj @@ -928,7 +930,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) = proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) = if t != nil: - var s = newSym(skResult, getIdent"result", getCurrOwner(), info) + var s = newSym(skResult, getIdent"result", getCurrOwner(c), info) s.typ = t incl(s.flags, sfUsed) addParamOrResult(c, s, owner) @@ -1003,12 +1005,12 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = checkSonsLen(n, bodyPos + 1) var s: PSym if n[namePos].kind != nkSym: - s = newSym(skProc, c.cache.idAnon, getCurrOwner(), n.info) + s = newSym(skProc, c.cache.idAnon, getCurrOwner(c), n.info) s.ast = n n.sons[namePos] = newSymNode(s) else: s = n[namePos].sym - pushOwner(s) + pushOwner(c, s) openScope(c) var gp: PNode if n.sons[genericParamsPos].kind != nkEmpty: @@ -1048,7 +1050,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = else: localError(n.info, errImplOfXexpected, s.name.s) closeScope(c) # close scope for parameters - popOwner() + popOwner(c) result.typ = s.typ proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode = @@ -1082,7 +1084,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = params[i].sym.name.s) #params[i].sym.owner = s openScope(c) - pushOwner(s) + pushOwner(c, s) addParams(c, params, skProc) pushProcCon(c, s) addResult(c, n.typ.sons[0], n.info, skProc) @@ -1090,7 +1092,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) n.sons[bodyPos] = transformBody(c.module, semBody, s) popProcCon(c) - popOwner() + popOwner(c) closeScope(c) # alternative variant (not quite working): @@ -1178,11 +1180,58 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = localError(n.info, errGenerated, "'destroy' or 'deepCopy' expected for 'override'") +proc cursorInProcAux(n: PNode): bool = + if inCheckpoint(n.info) != cpNone: return true + for i in 0..<n.safeLen: + if cursorInProcAux(n[i]): return true + +proc cursorInProc(n: PNode): bool = + if n.info.fileIndex == gTrackPos.fileIndex: + result = cursorInProcAux(n) + type TProcCompilationSteps = enum stepRegisterSymbol, stepDetermineType, +import compilerlog + +proc hasObjParam(s: PSym): bool = + var t = s.typ + for col in countup(1, sonsLen(t)-1): + if skipTypes(t.sons[col], skipPtrs).kind == tyObject: + return true + +proc finishMethod(c: PContext, s: PSym) = + if hasObjParam(s): + methodDef(c.graph, s, false) + +proc semMethodPrototype(c: PContext; s: PSym; n: PNode) = + if isGenericRoutine(s): + let tt = s.typ + var foundObj = false + # we start at 1 for now so that tparsecombnum continues to compile. + # XXX Revisit this problem later. + for col in countup(1, sonsLen(tt)-1): + let t = tt.sons[col] + if t != nil and t.kind == tyGenericInvocation: + var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst, + tyGenericInvocation, tyGenericBody, + tyAlias}) + if x.kind == tyObject and t.len-1 == n.sons[genericParamsPos].len: + foundObj = true + x.methods.safeAdd((col,s)) + if not foundObj: + message(n.info, warnDeprecated, "generic method not attachable to object type") + else: + # why check for the body? bug #2400 has none. Checking for sfForward makes + # no sense either. + # and result.sons[bodyPos].kind != nkEmpty: + if hasObjParam(s): + methodDef(c.graph, s, fromCache=false) + else: + localError(n.info, errXNeedsParamObjectType, "method") + proc semProcAux(c: PContext, n: PNode, kind: TSymKind, validPragmas: TSpecialWords, phase = stepRegisterSymbol): PNode = @@ -1197,7 +1246,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, assert phase == stepRegisterSymbol if n[namePos].kind == nkEmpty: - s = newSym(kind, c.cache.idAnon, getCurrOwner(), n.info) + s = newSym(kind, c.cache.idAnon, getCurrOwner(c), n.info) incl(s.flags, sfUsed) isAnon = true else: @@ -1214,7 +1263,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, return else: s = n[namePos].sym - s.owner = getCurrOwner() + s.owner = getCurrOwner(c) typeIsDetermined = s.typ == nil s.ast = n #s.scope = c.currentScope @@ -1223,7 +1272,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # where the proc was declared let oldScope = c.currentScope #c.currentScope = s.scope - pushOwner(s) + pushOwner(c, s) openScope(c) var gp: PNode if n.sons[genericParamsPos].kind != nkEmpty: @@ -1289,8 +1338,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if importantComments() and not isNil(proto.ast.comment): n.comment = proto.ast.comment proto.ast = n # needed for code generation - popOwner() - pushOwner(s) + popOwner(c) + pushOwner(c, s) s.options = gOptions if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) if s.name.s[0] in {'.', '('}: @@ -1304,30 +1353,40 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # Macros and Templates can have generic parameters, but they are # only used for overload resolution (there is no instantiation of # the symbol, so we must process the body now) - pushProcCon(c, s) - if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics: - if not usePseudoGenerics: paramsTypeCheck(c, s.typ) - - c.p.wasForwarded = proto != nil - maybeAddResult(c, s, n) - if lfDynamicLib notin s.loc.flags: - # no semantic checking for importc: - let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) - # unfortunately we cannot skip this step when in 'system.compiles' - # context as it may even be evaluated in 'system.compiles': - n.sons[bodyPos] = transformBody(c.module, semBody, s) + if not usePseudoGenerics and gIdeCmd in {ideSug, ideCon} and not + cursorInProc(n.sons[bodyPos]): + discard "speed up nimsuggest" + if s.kind == skMethod: semMethodPrototype(c, s, n) else: - if s.typ.sons[0] != nil and kind != skIterator: - addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info)) - openScope(c) - n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos]) - closeScope(c) - fixupInstantiatedSymbols(c, s) - if sfImportc in s.flags: - # so we just ignore the body after semantic checking for importc: - n.sons[bodyPos] = ast.emptyNode - popProcCon(c) + pushProcCon(c, s) + if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics: + if not usePseudoGenerics: paramsTypeCheck(c, s.typ) + + c.p.wasForwarded = proto != nil + maybeAddResult(c, s, n) + if s.kind == skMethod: semMethodPrototype(c, s, n) + + if lfDynamicLib notin s.loc.flags: + # no semantic checking for importc: + let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) + # unfortunately we cannot skip this step when in 'system.compiles' + # context as it may even be evaluated in 'system.compiles': + n.sons[bodyPos] = transformBody(c.module, semBody, s) + else: + if s.typ.sons[0] != nil and kind != skIterator: + addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info)) + + openScope(c) + n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos]) + closeScope(c) + fixupInstantiatedSymbols(c, s) + if s.kind == skMethod: semMethodPrototype(c, s, n) + if sfImportc in s.flags: + # so we just ignore the body after semantic checking for importc: + n.sons[bodyPos] = ast.emptyNode + popProcCon(c) else: + if s.kind == skMethod: semMethodPrototype(c, s, n) if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s) if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone: incl(s.flags, sfForward) @@ -1335,7 +1394,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, sideEffectsCheck(c, s) closeScope(c) # close scope for parameters # c.currentScope = oldScope - popOwner() + popOwner(c) if n.sons[patternPos].kind != nkEmpty: c.patterns.add(s) if isAnon: result.typ = s.typ @@ -1354,7 +1413,7 @@ proc semIterator(c: PContext, n: PNode): PNode = let isAnon = n[namePos].kind == nkEmpty if n[namePos].kind == nkSym: # gensym'ed iterators might need to become closure iterators: - n[namePos].sym.owner = getCurrOwner() + n[namePos].sym.owner = getCurrOwner(c) n[namePos].sym.kind = skIterator result = semProcAux(c, n, skIterator, iteratorPragmas) var s = result.sons[namePos].sym @@ -1381,46 +1440,22 @@ proc semIterator(c: PContext, n: PNode): PNode = proc semProc(c: PContext, n: PNode): PNode = result = semProcAux(c, n, skProc, procPragmas) -proc hasObjParam(s: PSym): bool = - var t = s.typ - for col in countup(1, sonsLen(t)-1): - if skipTypes(t.sons[col], skipPtrs).kind == tyObject: - return true - -proc finishMethod(c: PContext, s: PSym) = - if hasObjParam(s): - methodDef(s, false) - proc semMethod(c: PContext, n: PNode): PNode = if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method") result = semProcAux(c, n, skMethod, methodPragmas) - # macros can transform methods to nothing: + # macros can transform converters to nothing: if namePos >= result.safeLen: return result var s = result.sons[namePos].sym - if isGenericRoutine(s): - let tt = s.typ - var foundObj = false - # we start at 1 for now so that tparsecombnum continues to compile. - # XXX Revisit this problem later. - for col in countup(1, sonsLen(tt)-1): - let t = tt.sons[col] - if t != nil and t.kind == tyGenericInvocation: - var x = skipTypes(t.sons[0], {tyVar, tyPtr, tyRef, tyGenericInst, - tyGenericInvocation, tyGenericBody, - tyAlias}) - if x.kind == tyObject and t.len-1 == result.sons[genericParamsPos].len: - foundObj = true - x.methods.safeAdd((col,s)) - if not foundObj: - message(n.info, warnDeprecated, "generic method not attachable to object type") - else: - # why check for the body? bug #2400 has none. Checking for sfForward makes - # no sense either. - # and result.sons[bodyPos].kind != nkEmpty: - if hasObjParam(s): - methodDef(s, fromCache=false) - else: - localError(n.info, errXNeedsParamObjectType, "method") + # we need to fix the 'auto' return type for the dispatcher here (see tautonotgeneric + # test case): + let disp = getDispatcher(s) + # auto return type? + if disp != nil and disp.typ.sons[0] != nil and disp.typ.sons[0].kind == tyExpr: + let ret = s.typ.sons[0] + disp.typ.sons[0] = ret + if disp.ast[resultPos].kind == nkSym: + if isEmptyType(ret): disp.ast.sons[resultPos] = emptyNode + else: disp.ast[resultPos].sym.typ = ret proc semConverterDef(c: PContext, n: PNode): PNode = if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter") diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 420e36116..d7134402f 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -60,7 +60,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode = # (s.kind notin routineKinds or s.magic != mNone): # for instance 'nextTry' is both in tables.nim and astalgo.nim ... result = newSymNode(s, n.info) - markUsed(n.info, s) + markUsed(n.info, s, c.graph.usageSym) else: # semantic checking requires a type; ``fitNode`` deals with it # appropriately @@ -561,7 +561,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = styleCheckDef(s) # check parameter list: #s.scope = c.currentScope - pushOwner(s) + pushOwner(c, s) openScope(c) n.sons[namePos] = newSymNode(s, n.sons[namePos].info) if n.sons[pragmasPos].kind != nkEmpty: @@ -615,7 +615,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = # only parameters are resolved, no type checking is performed semIdeForTemplateOrGeneric(c, n.sons[bodyPos], ctx.cursorInBody) closeScope(c) - popOwner() + popOwner(c) s.ast = n result = n if n.sons[bodyPos].kind == nkEmpty: @@ -760,7 +760,7 @@ proc semPattern(c: PContext, n: PNode): PNode = ctx.toMixin = initIntSet() ctx.toInject = initIntSet() ctx.c = c - ctx.owner = getCurrOwner() + ctx.owner = getCurrOwner(c) result = flattenStmts(semPatternBody(ctx, n)) if result.kind in {nkStmtList, nkStmtListExpr}: if result.len == 1: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 440edd226..97af2c5cc 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -306,7 +306,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = else: result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) if result != nil: - markUsed(n.info, result) + markUsed(n.info, result, c.graph.usageSym) styleCheckUse(n.info, result) if result.kind == skParam and result.typ.kind == tyTypeDesc: # This is a typedesc param. is it already bound? @@ -608,7 +608,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, let rec = rectype.sym for i in countup(0, sonsLen(n)-3): var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported}) - suggestSym(n.sons[i].info, f) + suggestSym(n.sons[i].info, f, c.graph.usageSym) f.typ = typ f.position = pos if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and @@ -750,7 +750,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, return genericParams.sons[i].typ let owner = if typeClass.sym != nil: typeClass.sym - else: getCurrOwner() + else: getCurrOwner(c) var s = newSym(skType, finalTypId, owner, info) if typId == nil: s.flags.incl(sfAnon) s.linkTo(typeClass) @@ -850,7 +850,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, of tyGenericInst: if paramType.lastSon.kind == tyUserTypeClass: - var cp = copyType(paramType, getCurrOwner(), false) + var cp = copyType(paramType, getCurrOwner(c), false) cp.kind = tyUserTypeClassInst return addImplicitGeneric(cp) @@ -876,10 +876,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, result = liftingWalk(expanded, true) of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: - result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true)) + result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), true)) of tyGenericParam: - markUsed(info, paramType.sym) + markUsed(info, paramType.sym, c.graph.usageSym) styleCheckUse(info, paramType.sym) if tfWildcard in paramType.flags: paramType.flags.excl tfWildcard @@ -1267,7 +1267,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of mExpr: result = semTypeNode(c, n.sons[0], nil) if result != nil: - result = copyType(result, getCurrOwner(), false) + result = copyType(result, getCurrOwner(c), false) for i in countup(1, n.len - 1): result.rawAddSon(semTypeNode(c, n.sons[i], nil)) of mDistinct: @@ -1330,7 +1330,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = else: assignType(prev, t) result = prev - markUsed(n.info, n.sym) + markUsed(n.info, n.sym, c.graph.usageSym) styleCheckUse(n.info, n.sym) else: if s.kind != skError: localError(n.info, errTypeExpected) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index d3c142954..f2caab41f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -73,7 +73,7 @@ type const isNilConversion = isConvertible # maybe 'isIntConv' fits better? -proc markUsed*(info: TLineInfo, s: PSym) +proc markUsed*(info: TLineInfo, s: PSym; usageSym: var PSym) template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone @@ -543,7 +543,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = else: return isNone when useEffectSystem: - if not compatibleEffects(f, a): return isNone + if compatibleEffects(f, a) != efCompat: return isNone of tyNil: result = f.allowsNil @@ -1291,7 +1291,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, dest = generateTypeInstance(c, m.bindings, arg, dest) let fdest = typeRel(m, f, dest) if fdest in {isEqual, isGeneric}: - markUsed(arg.info, c.converters[i]) + markUsed(arg.info, c.converters[i], c.graph.usageSym) var s = newSymNode(c.converters[i]) s.typ = c.converters[i].typ s.info = arg.info @@ -1551,7 +1551,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, else: result = nil else: # only one valid interpretation found: - markUsed(arg.info, arg.sons[best].sym) + markUsed(arg.info, arg.sons[best].sym, m.c.graph.usageSym) styleCheckUse(arg.info, arg.sons[best].sym) result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best], argOrig) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 66876b9b5..9ae427583 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -28,7 +28,7 @@ type column*: int # Starts at 0 doc*: string # Not escaped (yet) symkind*: TSymKind - forth*: string # XXX TODO object on symkind + forth*: string # type quality*: range[0..100] # matching quality isGlobal*: bool # is a global variable tokenLen*: int @@ -88,7 +88,7 @@ proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo; when not defined(noDocgen): result.doc = s.extractDocComment -proc `$`(suggest: Suggest): string = +proc `$`*(suggest: Suggest): string = result = $suggest.section result.add(sep) if suggest.section == ideHighlight: @@ -131,7 +131,7 @@ proc suggestResult(s: Suggest) = if not isNil(suggestionResultHook): suggestionResultHook(s) else: - suggestWriteln($(s)) + suggestWriteln($s) proc filterSym(s: PSym): bool {.inline.} = result = s.kind != skModule @@ -297,10 +297,10 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) = suggestOperations(c, n, typ, outputs) type - TCheckPointResult = enum + TCheckPointResult* = enum cpNone, cpFuzzy, cpExact -proc inCheckpoint(current: TLineInfo): TCheckPointResult = +proc inCheckpoint*(current: TLineInfo): TCheckPointResult = if current.fileIndex == gTrackPos.fileIndex: if current.line == gTrackPos.line and abs(current.col-gTrackPos.col) < 4: @@ -353,10 +353,10 @@ when defined(nimsuggest): s.allUsages.add(info) var - usageSym*: PSym + #usageSym*: PSym lastLineInfo*: TLineInfo -proc findUsages(info: TLineInfo; s: PSym) = +proc findUsages(info: TLineInfo; s: PSym; usageSym: var PSym) = if suggestVersion < 2: if usageSym == nil and isTracked(info, s.name.s.len): usageSym = s @@ -385,7 +385,7 @@ proc ensureIdx[T](x: var T, y: int) = proc ensureSeq[T](x: var seq[T]) = if x == nil: newSeq(x, 0) -proc suggestSym*(info: TLineInfo; s: PSym; isDecl=true) {.inline.} = +proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} = ## misnamed: should be 'symDeclared' when defined(nimsuggest): if suggestVersion == 2: @@ -395,20 +395,20 @@ proc suggestSym*(info: TLineInfo; s: PSym; isDecl=true) {.inline.} = s.addNoDup(info) if gIdeCmd == ideUse: - findUsages(info, s) + findUsages(info, s, usageSym) elif gIdeCmd == ideDef: findDefinition(info, s) elif gIdeCmd == ideDus and s != nil: if isTracked(info, s.name.s.len): suggestResult(symToSuggest(s, isLocal=false, $ideDef, 100)) - findUsages(info, s) + findUsages(info, s, usageSym) elif gIdeCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex: suggestResult(symToSuggest(s, isLocal=false, $ideHighlight, info, 100)) elif gIdeCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and isDecl: suggestResult(symToSuggest(s, isLocal=false, $ideOutline, info, 100)) -proc markUsed(info: TLineInfo; s: PSym) = +proc markUsed(info: TLineInfo; s: PSym; usageSym: var PSym) = incl(s.flags, sfUsed) if s.kind == skEnumField and s.owner != nil: incl(s.owner.flags, sfUsed) @@ -416,11 +416,11 @@ proc markUsed(info: TLineInfo; s: PSym) = if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s) if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s) when defined(nimsuggest): - suggestSym(info, s, false) + suggestSym(info, s, usageSym, false) -proc useSym*(sym: PSym): PNode = +proc useSym*(sym: PSym; usageSym: var PSym): PNode = result = newSymNode(sym) - markUsed(result.info, sym) + markUsed(result.info, sym, usageSym) proc safeSemExpr*(c: PContext, n: PNode): PNode = # use only for idetools support! diff --git a/compiler/transf.nim b/compiler/transf.nim index e14985145..0c53c0cbf 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -694,9 +694,10 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = # bugfix: check after 'transformSons' if it's still a method call: # use the dispatcher for the call: if s.sons[0].kind == nkSym and s.sons[0].sym.kind == skMethod: - let t = lastSon(s.sons[0].sym.ast) - if t.kind != nkSym or sfDispatcher notin t.sym.flags: - methodDef(s.sons[0].sym, false) + when false: + let t = lastSon(s.sons[0].sym.ast) + if t.kind != nkSym or sfDispatcher notin t.sym.flags: + methodDef(s.sons[0].sym, false) result = methodCall(s).PTransNode else: result = s.PTransNode diff --git a/compiler/types.nim b/compiler/types.nim index d5ec2972a..b237753ae 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1377,7 +1377,16 @@ proc compatibleEffectsAux(se, re: PNode): bool = return false result = true -proc compatibleEffects*(formal, actual: PType): bool = +type + EffectsCompat* = enum + efCompat + efRaisesDiffer + efRaisesUnknown + efTagsDiffer + efTagsUnknown + efLockLevelsDiffer + +proc compatibleEffects*(formal, actual: PType): EffectsCompat = # for proc type compatibility checking: assert formal.kind == tyProc and actual.kind == tyProc internalAssert formal.n.sons[0].kind == nkEffectList @@ -1393,18 +1402,21 @@ proc compatibleEffects*(formal, actual: PType): bool = # 'r.msgHandler = if isNil(msgHandler): defaultMsgHandler else: msgHandler' if not isNil(se) and se.kind != nkArgList: # spec requires some exception or tag, but we don't know anything: - if real.len == 0: return false - result = compatibleEffectsAux(se, real.sons[exceptionEffects]) - if not result: return + if real.len == 0: return efRaisesUnknown + let res = compatibleEffectsAux(se, real.sons[exceptionEffects]) + if not res: return efRaisesDiffer let st = spec.sons[tagEffects] if not isNil(st) and st.kind != nkArgList: # spec requires some exception or tag, but we don't know anything: - if real.len == 0: return false - result = compatibleEffectsAux(st, real.sons[tagEffects]) - if not result: return - result = formal.lockLevel.ord < 0 or - actual.lockLevel.ord <= formal.lockLevel.ord + if real.len == 0: return efTagsUnknown + let res = compatibleEffectsAux(st, real.sons[tagEffects]) + if not res: return efTagsDiffer + if formal.lockLevel.ord < 0 or + actual.lockLevel.ord <= formal.lockLevel.ord: + result = efCompat + else: + result = efLockLevelsDiffer proc isCompileTimeOnly*(t: PType): bool {.inline.} = result = t.kind in {tyTypeDesc, tyStatic} @@ -1508,6 +1520,21 @@ proc typeMismatch*(n: PNode, formal, actual: PType) = let named = typeToString(formal) let desc = typeToString(formal, preferDesc) let x = if named == desc: named else: named & " = " & desc - localError(n.info, errGenerated, msgKindToString(errTypeMismatch) & - typeToString(actual) & ") " & - `%`(msgKindToString(errButExpectedX), [x])) + var msg = msgKindToString(errTypeMismatch) & + typeToString(actual) & ") " & + msgKindToString(errButExpectedX) % [x] + + if formal.kind == tyProc and actual.kind == tyProc: + case compatibleEffects(formal, actual) + of efCompat: discard + of efRaisesDiffer: + msg.add "\n.raise effects differ" + of efRaisesUnknown: + msg.add "\n.raise effect is 'can raise any'" + of efTagsDiffer: + msg.add "\n.tag effects differ" + of efTagsUnknown: + msg.add "\n.tag effect is 'any tag allowed'" + of efLockLevelsDiffer: + msg.add "\nlock levels differ" + localError(n.info, errGenerated, msg) diff --git a/compiler/vm.nim b/compiler/vm.nim index 5d4784281..6a9545193 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1556,7 +1556,10 @@ proc myProcess(c: PPassContext, n: PNode): PNode = result = n oldErrorCount = msgs.gErrorCounter -const evalPass* = makePass(myOpen, nil, myProcess, myProcess) +proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = + myProcess(c, n) + +const evalPass* = makePass(myOpen, nil, myProcess, myClose) proc evalConstExprAux(module: PSym; cache: IdentCache; prc: PSym, n: PNode, mode: TEvalMode): PNode = |