diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 63a7cda0e1..9db6b77740 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 eda80be30d..52fd8ab494 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) @@ -38,16 +38,18 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode = 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 dispn = lastSon(result.sons[0].sym.ast) + if dispn.kind == nkSym: + let disp = dispn.sym + if sfDispatcher notin disp.flags: + localError(n.info, "'" & $result & "' lacks a dispatcher") + return + 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 @@ -144,27 +146,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 +260,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/docgen2.nim b/compiler/docgen2.nim index 9504ab52f4..118f1c7c53 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 29a72c86e3..b2d291d706 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 19a4da07b7..089e69ff99 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 b86312209c..c081a099a3 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -41,6 +41,9 @@ type 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.} @@ -58,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) @@ -65,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: diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 49e4fa184a..a1ba82263a 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/passaux.nim b/compiler/passaux.nim index eeaf129537..2065d58932 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 783a7e13fc..abab599b6f 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 = @@ -215,7 +215,7 @@ 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: @@ -224,5 +224,5 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, for i in countup(0, sonsLen(n) - 1): if graph.stopCompile(): break processTopLevelStmtCached(n.sons[i], a) - closePassesCached(a) + closePassesCached(graph, a) result = true diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 09b8d33059..859fe2a818 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 8a3f67dd48..338e7bcac3 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 4ce9e616ac..d61d817dd2 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 fc7736b079..d73826965a 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 c4dc136243..063157891c 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 diff --git a/compiler/semcall.nim b/compiler/semcall.nim index ae7bab89d4..fe73d60e6a 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 77a530a150..93599f49fb 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -125,22 +125,20 @@ 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[high(gOwners)] + 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 = @@ -226,7 +224,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) @@ -245,7 +243,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 = @@ -255,7 +253,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 = @@ -326,7 +324,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 a8873bbe2b..b09404b391 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 542d7b4e39..64787b82cf 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 9d8cea862c..5ac1ad11a9 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 acaade4949..82d27cf100 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 e72172c815..5eed1e7025 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 6a3793d737..0dfcdc0db5 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -35,7 +35,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) @@ -366,11 +366,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) = @@ -621,7 +623,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: @@ -635,7 +637,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): @@ -745,7 +747,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: @@ -769,11 +771,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 @@ -782,7 +784,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: @@ -793,7 +795,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 @@ -927,7 +929,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) @@ -1002,12 +1004,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: @@ -1047,7 +1049,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 = @@ -1081,7 +1083,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) @@ -1089,7 +1091,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): @@ -1193,6 +1195,42 @@ type 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 = @@ -1207,7 +1245,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: @@ -1224,7 +1262,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 @@ -1233,7 +1271,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: @@ -1299,8 +1337,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 {'.', '('}: @@ -1317,6 +1355,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, 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: pushProcCon(c, s) if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics: @@ -1324,6 +1363,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, 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])) @@ -1333,15 +1374,18 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, 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) @@ -1349,7 +1393,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 @@ -1368,7 +1412,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 @@ -1395,46 +1439,9 @@ 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: - 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") 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 8819f17cc1..843bef1a8d 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 @@ -559,7 +559,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: @@ -613,7 +613,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: @@ -758,7 +758,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 440edd226f..97af2c5cc3 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 117b66cd8f..f2caab41f0 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 @@ -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 c228d1fa8d..9ae427583a 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -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 2103d48bf9..98e221b56a 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/vm.nim b/compiler/vm.nim index 5d47842813..6a9545193e 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 = diff --git a/tests/misc/parsecomb.nim b/tests/misc/parsecomb.nim index 05fe97ad16..4ff2f65d22 100644 --- a/tests/misc/parsecomb.nim +++ b/tests/misc/parsecomb.nim @@ -29,10 +29,10 @@ method runInput[T, O](self: Parser[T, O], inp: Input[T]): Result[T, O] = # XXX: above needed for now, as without the `tmp` bit below, it compiles to invalid C. tmp(self)(inp) -method run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] = +proc run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] = self.runInput(Input[T](toks: toks, index: 0)) -method chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] = +proc chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] = result = proc (inp: Input[T]): Result[T, O2] = let r = self.runInput(inp) case r.kind: @@ -41,7 +41,7 @@ method chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2] of rkFailure: Result[T, O2](kind: rkFailure) -method skip[T](self: Input[T], n: int): Input[T] = +method skip[T](self: Input[T], n: int): Input[T] {.base.} = Input[T](toks: self.toks, index: self.index + n) proc pskip*[T](n: int): Parser[T, tuple[]] = @@ -69,11 +69,11 @@ proc `+`*[T, O](first: Parser[T, O], second: Parser[T, O]): Parser[T, O] = # end of primitives (definitions involving Parser(..)) -method map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] = +proc map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] = self.chain(proc (v: O1): Parser[T, O2] = unit[T, O2](p(v))) -method then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] = +proc then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] = self.chain(proc (v: O1): Parser[T, O2] = next)