diff options
Diffstat (limited to 'compiler')
54 files changed, 612 insertions, 534 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 8fbec64cf..66fbe577c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -10,7 +10,7 @@ # abstract syntax tree + symbol table import - msgs, hashes, nversion, options, strutils, securehash, ropes, idents, lists, + msgs, hashes, nversion, options, strutils, securehash, ropes, idents, intsets, idgen type @@ -736,13 +736,15 @@ type TLibKind* = enum libHeader, libDynamic - TLib* = object of lists.TListEntry # also misused for headers! + + TLib* = object # also misused for headers! kind*: TLibKind generated*: bool # needed for the backends: isOverriden*: bool name*: Rope path*: PNode # can be a string literal! + CompilesId* = int ## id that is used for the caching logic within ## ``system.compiles``. See the seminst module. TInstantiation* = object @@ -1541,8 +1543,7 @@ proc skipGenericOwner*(s: PSym): PSym = ## Generic instantiations are owned by their originating generic ## symbol. This proc skips such owners and goes straight to the owner ## of the generic itself (the module or the enclosing proc). - result = if s.kind in skProcKinds and {sfGenSym, sfFromGeneric} * s.flags == - {sfFromGeneric}: + result = if s.kind in skProcKinds and sfFromGeneric in s.flags: s.owner.owner else: s.owner diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index affbdffd9..226d5ee42 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -388,6 +388,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int; [istr, makeYamlString($n.kind)] addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) if maxRecDepth != 0: + addf(result, ",$N$1\"flags\": $2", [istr, rope($n.flags)]) case n.kind of nkCharLit..nkUInt64Lit: addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)]) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 95a7beada..e9c78b48b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -220,7 +220,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = optAsgnLoc(src, t, field), newflags) proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, - t: PNode) = + t: PNode, typ: PType) = if t == nil: return let newflags = if src.s == OnStatic: @@ -232,10 +232,11 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, case t.kind of nkSym: let field = t.sym + if field.loc.r == nil: fillObjectFields(p.module, typ) genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r), optAsgnLoc(src, field.typ, field.loc.r), newflags) of nkRecList: - for child in items(t): genOptAsgnObject(p, dest, src, newflags, child) + for child in items(t): genOptAsgnObject(p, dest, src, newflags, child, typ) else: discard proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = @@ -315,9 +316,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = genGenericAsgn(p, dest, src, flags) elif needsComplexAssignment(ty): if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4: - discard getTypeDesc(p.module, dest.t) + discard getTypeDesc(p.module, ty) internalAssert ty.n != nil - genOptAsgnObject(p, dest, src, flags, ty.n) + genOptAsgnObject(p, dest, src, flags, ty.n, ty) else: genGenericAsgn(p, dest, src, flags) else: @@ -943,7 +944,7 @@ proc genEcho(p: BProc, n: PNode) = # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)`` # is threadsafe. internalAssert n.kind == nkBracket - discard lists.includeStr(p.module.headerFiles, "<stdio.h>") + p.module.includeHeader("<stdio.h>") var args: Rope = nil var a: TLoc for i in countup(0, n.len-1): diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 45d675f64..3a861ebd4 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -540,7 +540,7 @@ proc genBreakStmt(p: BProc, t: PNode) = # named break? assert(t.sons[0].kind == nkSym) var sym = t.sons[0].sym - assert(sym.loc.k == locOther) + doAssert(sym.loc.k == locOther) idx = sym.position-1 else: # an unnamed 'break' can only break a loop after 'transf' pass: @@ -884,7 +884,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = # if not isEmptyType(t.typ) and d.k == locNone: getTemp(p, t.typ, d) - discard lists.includeStr(p.module.headerFiles, "<setjmp.h>") + p.module.includeHeader("<setjmp.h>") genLineDir(p, t) var safePoint = getTempName(p.module) if getCompilerProc("Exception") != nil: @@ -1103,8 +1103,8 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) = genAssignment(p, a, tmp, {}) proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = - genLineDir(p, e) if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags: + genLineDir(p, e) genGotoVar(p, e.sons[1]) elif not fieldDiscriminantCheckNeeded(p, e): var a: TLoc @@ -1114,8 +1114,11 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = initLocExpr(p, e.sons[0], a) if fastAsgn: incl(a.flags, lfNoDeepCopy) assert(a.t != nil) - loadInto(p, e.sons[0], e.sons[1], a) + let ri = e.sons[1] + genLineDir(p, ri) + loadInto(p, e.sons[0], ri, a) else: + genLineDir(p, e) asgnFieldDiscriminant(p, e) proc genStmts(p: BProc, t: PNode) = diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index 3efddbf30..505b69eab 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -57,8 +57,8 @@ proc generateThreadLocalStorage(m: BModule) = proc generateThreadVarsSize(m: BModule) = if nimtv != nil: - let externc = if gCmd != cmdCompileToCpp and - sfCompileToCpp in m.module.flags: "extern \"C\"" + let externc = if gCmd == cmdCompileToCpp or + sfCompileToCpp in m.module.flags: "extern \"C\" " else: "" addf(m.s[cfsProcs], "$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n", diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index e30fe5598..29d4e23c9 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -24,7 +24,13 @@ proc isKeyword(w: PIdent): bool = proc mangleField(m: BModule; name: PIdent): string = result = mangle(name.s) - if isKeyword(name) or m.g.config.cppDefines.contains(result): + # fields are tricky to get right and thanks to generic types producing + # duplicates we can end up mangling the same field multiple times. However + # if we do so, the 'cppDefines' table might be modified in the meantime + # meaning we produce inconsistent field names (see bug #5404). + # Hence we do not check for ``m.g.config.cppDefines.contains(result)`` here + # anymore: + if isKeyword(name): result.add "_0" when false: diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index d42f0438f..a00ce3505 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -10,7 +10,7 @@ # This module declares some helpers for the C code generator. import - ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg, + ast, astalgo, ropes, hashes, strutils, types, msgs, wordrecg, platform, trees proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode = diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 62ed9ad6e..7fef34a27 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -11,7 +11,7 @@ import ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets, - nversion, nimsets, msgs, securehash, bitsets, idents, lists, types, + nversion, nimsets, msgs, securehash, bitsets, idents, types, ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings, semparallel, tables, sets, ndi @@ -75,12 +75,13 @@ proc isSimpleConst(typ: PType): bool = proc useStringh(m: BModule) = if includesStringh notin m.flags: incl m.flags, includesStringh - discard lists.includeStr(m.headerFiles, "<string.h>") + m.includeHeader("<string.h>") proc useHeader(m: BModule, sym: PSym) = if lfHeader in sym.loc.flags: assert(sym.annex != nil) - discard lists.includeStr(m.headerFiles, getStr(sym.annex.path)) + let str = getStr(sym.annex.path) + m.includeHeader(str) proc cgsym(m: BModule, name: string): Rope @@ -594,15 +595,14 @@ proc cgsym(m: BModule, name: string): Rope = proc generateHeaders(m: BModule) = add(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl) - var it = PStrEntry(m.headerFiles.head) - while it != nil: - if it.data[0] == '#': - add(m.s[cfsHeaders], rope(it.data.replace('`', '"') & tnl)) - elif it.data[0] notin {'\"', '<'}: - addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it.data)]) + + for it in m.headerFiles: + if it[0] == '#': + add(m.s[cfsHeaders], rope(it.replace('`', '"') & tnl)) + elif it[0] notin {'\"', '<'}: + addf(m.s[cfsHeaders], "#include \"$1\"$N", [rope(it)]) else: - addf(m.s[cfsHeaders], "#include $1$N", [rope(it.data)]) - it = PStrEntry(it.next) + addf(m.s[cfsHeaders], "#include $1$N", [rope(it)]) add(m.s[cfsHeaders], "#undef linux" & tnl) proc initFrame(p: BProc, procname, filename: Rope): Rope = @@ -715,10 +715,13 @@ proc genProcAux(m: BModule, prc: PSym) = add(generatedProc, ~"}$N") add(m.s[cfsProcs], generatedProc) -proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} = - result = sfCompileToCpp in m.module.flags and +proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} = + result = (sfCompileToCpp in m.module.flags and sfCompileToCpp notin sym.getModule().flags and - gCmd != cmdCompileToCpp + gCmd != cmdCompileToCpp) or ( + sym.flags * {sfImportc, sfInfixCall, sfCompilerProc} == {sfImportc} and + sym.magic == mNone and + gCmd == cmdCompileToCpp) proc genProcPrototype(m: BModule, sym: PSym) = useHeader(m, sym) @@ -732,7 +735,7 @@ proc genProcPrototype(m: BModule, sym: PSym) = var header = genProcHeader(m, sym) if sfNoReturn in sym.flags and hasDeclspec in extccomp.CC[cCompiler].props: header = "__declspec(noreturn) " & header - if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): + if sym.typ.callConv != ccInline and requiresExternC(m, sym): header = "extern \"C\" " & header if sfPure in sym.flags and hasAttribute in CC[cCompiler].props: header.add(" __attribute__((naked))") @@ -971,7 +974,7 @@ proc genMainProc(m: BModule) = else: nimMain = WinNimDllMain otherMain = WinCDllMain - discard lists.includeStr(m.headerFiles, "<windows.h>") + m.includeHeader("<windows.h>") elif optGenDynLib in gGlobalOptions: nimMain = PosixNimDllMain otherMain = PosixCDllMain @@ -1126,7 +1129,7 @@ proc initProcOptions(m: BModule): TOptions = proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule = new(result) result.tmpBase = rope("TM" & $hashOwner(module) & "_") - initLinkedList(result.headerFiles) + result.headerFiles = @[] result.declaredThings = initIntSet() result.declaredProtos = initIntSet() result.cfilename = filename @@ -1163,7 +1166,7 @@ proc nullify[T](arr: var T) = proc resetModule*(m: BModule) = # between two compilations in CAAS mode, we can throw # away all the data that was written to disk - initLinkedList(m.headerFiles) + m.headerFiles = @[] m.declaredProtos = initIntSet() m.forwTypeCache = initTable[SigHash, Rope]() m.initProc = newProc(nil, m) @@ -1363,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) @@ -1375,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/cgendata.nim b/compiler/cgendata.nim index 565399ead..be087095f 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -10,7 +10,7 @@ ## This module contains the data structures for the C code generation phase. import - ast, astalgo, ropes, passes, options, intsets, lists, platform, sighashes, + ast, astalgo, ropes, passes, options, intsets, platform, sighashes, tables, ndi from msgs import TLineInfo @@ -130,7 +130,7 @@ type forwTypeCache*: TypeCache # cache for forward declarations of types declaredThings*: IntSet # things we have declared in this .c file declaredProtos*: IntSet # prototypes we have declared in this .c file - headerFiles*: TLinkedList # needed headers to include + headerFiles*: seq[string] # needed headers to include typeInfoMarker*: TypeCache # needed for generating type information initProc*: BProc # code for init procedure postInitProc*: BProc # code to be executed after the init proc @@ -148,9 +148,13 @@ type g*: BModuleList ndi*: NdiFile +proc includeHeader*(this: BModule; header: string) = + if not this.headerFiles.contains header: + this.headerFiles.add header + proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} = # section in the current block - result = p.blocks[p.blocks.len - 1].sections[s] + result = p.blocks[^1].sections[s] proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} = # top level proc sections 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/commands.nim b/compiler/commands.nim index 74503a414..b75e953de 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -26,8 +26,8 @@ bootSwitch(usedGoGC, defined(gogc), "--gc:go") bootSwitch(usedNoGC, defined(nogc), "--gc:none") import - os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, - wordrecg, parseutils, nimblecmd, idents, parseopt + os, msgs, options, nversion, condsyms, strutils, extccomp, platform, + wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") @@ -335,12 +335,14 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "excludepath": expectArg(switch, arg, pass, info) let path = processPath(arg, info) - lists.excludePath(options.searchPaths, path) - lists.excludePath(options.lazyPaths, path) + + options.searchPaths.keepItIf( cmpPaths(it, path) != 0 ) + options.lazyPaths.keepItIf( cmpPaths(it, path) != 0 ) + if (len(path) > 0) and (path[len(path) - 1] == DirSep): let strippedPath = path[0 .. (len(path) - 2)] - lists.excludePath(options.searchPaths, strippedPath) - lists.excludePath(options.lazyPaths, strippedPath) + options.searchPaths.keepItIf( cmpPaths(it, strippedPath) != 0 ) + options.lazyPaths.keepItIf( cmpPaths(it, strippedPath) != 0 ) of "nimcache": expectArg(switch, arg, pass, info) options.nimcacheDir = processPath(arg, info, true) 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/extccomp.nim b/compiler/extccomp.nim index 0f283b208..dab643d50 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -13,7 +13,7 @@ # nim files. import - lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, + ropes, os, strutils, osproc, platform, condsyms, options, msgs, securehash, streams #from debuginfo import writeDebugInfo @@ -390,8 +390,8 @@ type CfileList = seq[Cfile] var - externalToLink: TLinkedList # files to link in addition to the file - # we compiled + externalToLink: seq[string] = @[] # files to link in addition to the file + # we compiled linkOptionsCmd: string = "" compileOptionsCmd: seq[string] = @[] linkOptions: string = "" @@ -486,11 +486,10 @@ proc resetCompilationLists* = # when the module is loaded/unloaded it adds/removes its items # That's because we still need to hash check the external files # Maybe we can do that in checkDep on the other hand? - initLinkedList(externalToLink) + externalToLink.setLen 0 proc addExternalFileToLink*(filename: string) = - prependStr(externalToLink, filename) - # BUGFIX: was ``appendStr`` + externalToLink.insert(filename, 0) proc execWithEcho(cmd: string, msg = hintExecuting): int = rawMessage(msg, cmd) @@ -527,9 +526,6 @@ proc noAbsolutePaths: bool {.inline.} = # `optGenMapping` is included here for niminst. result = gGlobalOptions * {optGenScript, optGenMapping} != {} -proc add(s: var string, many: openArray[string]) = - s.add many.join - proc cFileSpecificOptions(cfilename: string): string = result = compileOptions for option in compileOptionsCmd: @@ -560,22 +556,24 @@ proc getLinkOptions: string = for linkedLib in items(cLinkedLibs): result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell) for libDir in items(cLibs): - result.add([CC[cCompiler].linkDirCmd, libDir.quoteShell]) + result.add(join([CC[cCompiler].linkDirCmd, libDir.quoteShell])) proc needsExeExt(): bool {.inline.} = result = (optGenScript in gGlobalOptions and targetOS == osWindows) or (platform.hostOS == osWindows) -proc getCompilerExe(compiler: TSystemCC): string = - result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler - else: CC[compiler].compilerExe +proc getCompilerExe(compiler: TSystemCC; cfile: string): string = + result = if gCmd == cmdCompileToCpp and not cfile.endsWith(".c"): + CC[compiler].cppCompiler + else: + CC[compiler].compilerExe if result.len == 0: rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name) proc getLinkerExe(compiler: TSystemCC): string = result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler - else: compiler.getCompilerExe + else: compiler.getCompilerExe("") proc getCompileCFileCmd*(cfile: Cfile): string = var c = cCompiler @@ -596,7 +594,7 @@ proc getCompileCFileCmd*(cfile: Cfile): string = var options = cFileSpecificOptions(cfile.cname) var exe = getConfigVar(c, ".exe") - if exe.len == 0: exe = c.getCompilerExe + if exe.len == 0: exe = c.getCompilerExe(cfile.cname) if needsExeExt(): exe = addFileExt(exe, "exe") if optGenDynLib in gGlobalOptions and @@ -609,12 +607,12 @@ proc getCompileCFileCmd*(cfile: Cfile): string = includeCmd = CC[c].includeCmd & quoteShell(libpath) for includeDir in items(cIncludes): - includeCmd.add([CC[c].includeCmd, includeDir.quoteShell]) + includeCmd.add(join([CC[c].includeCmd, includeDir.quoteShell])) compilePattern = joinPath(ccompilerpath, exe) else: includeCmd = "" - compilePattern = c.getCompilerExe + compilePattern = c.getCompilerExe(cfile.cname) var cf = if noAbsolutePaths(): extractFilename(cfile.cname) else: cfile.cname @@ -784,14 +782,12 @@ proc callCCompiler*(projectfile: string) = rawMessage(errExecutionOfProgramFailed, cmds.join()) if optNoLinking notin gGlobalOptions: # call the linker: - var it = PStrEntry(externalToLink.head) var objfiles = "" - while it != nil: - let objFile = if noAbsolutePaths(): it.data.extractFilename else: it.data + for it in externalToLink: + let objFile = if noAbsolutePaths(): it.extractFilename else: it add(objfiles, ' ') add(objfiles, quoteShell( addFileExt(objFile, CC[cCompiler].objExt))) - it = PStrEntry(it.next) for x in toCompile: add(objfiles, ' ') add(objfiles, quoteShell(x.obj)) @@ -834,15 +830,14 @@ proc writeJsonBuildInstructions*(projectfile: string) = else: lit "],\L" - proc linkfiles(f: File; buf, objfiles: var string; toLink: TLinkedList) = - var it = PStrEntry(toLink.head) - while it != nil: - let objfile = addFileExt(it.data, CC[cCompiler].objExt) - str objfile + proc linkfiles(f: File; buf, objfiles: var string; toLink: seq[string]) = + for i, it in toLink: + let objfile = addFileExt(it, CC[cCompiler].objExt) + str(objfile) add(objfiles, ' ') add(objfiles, quoteShell(objfile)) - it = PStrEntry(it.next) - if it == nil: + + if i == toLink.high: lit "\L" else: lit ",\L" diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 29a72c86e..8f819686d 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -31,7 +31,7 @@ implements the required case distinction. import ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options, - nversion, nimsets, msgs, securehash, bitsets, idents, lists, types, os, + nversion, nimsets, msgs, securehash, bitsets, idents, types, os, times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils, intsets, cgmeth, lowerings @@ -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/lambdalifting.nim b/compiler/lambdalifting.nim index 8d4badb4e..cd2ccfe53 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -10,7 +10,7 @@ # This include file implements lambda lifting for the transformator. import - intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, + intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os, idents, renderer, types, magicsys, rodread, lowerings, tables discard """ diff --git a/compiler/lists.nim b/compiler/lists.nim index 27e373342..bfd052204 100644 --- a/compiler/lists.nim +++ b/compiler/lists.nim @@ -7,113 +7,22 @@ # distribution, for details about the copyright. # -# This module implements a generic doubled linked list. -# TODO Remove this and replace it with something sensible -import os -type - PListEntry* = ref TListEntry - TListEntry* = object of RootObj - prev*, next*: PListEntry - - TStrEntry* = object of TListEntry - data*: string - - PStrEntry* = ref TStrEntry - TLinkedList* = object # for the "find" operation: - head*, tail*: PListEntry - counter*: int - - TCompareProc* = proc (entry: PListEntry, closure: pointer): bool {.nimcall.} - -proc initLinkedList*(list: var TLinkedList) = - list.counter = 0 - list.head = nil - list.tail = nil - -proc append*(list: var TLinkedList, entry: PListEntry) = - inc(list.counter) - entry.next = nil - entry.prev = list.tail - if list.tail != nil: - assert(list.tail.next == nil) - list.tail.next = entry - list.tail = entry - if list.head == nil: list.head = entry - -proc contains*(list: TLinkedList, data: string): bool = - var it = list.head - while it != nil: - if PStrEntry(it).data == data: - return true - it = it.next +# This module is deprecated, don't use it. +# TODO Remove this -proc newStrEntry(data: string): PStrEntry = - new(result) - result.data = data - -proc appendStr*(list: var TLinkedList, data: string) = - append(list, newStrEntry(data)) - -proc includeStr*(list: var TLinkedList, data: string): bool = - if contains(list, data): return true - appendStr(list, data) # else: add to list - -proc prepend*(list: var TLinkedList, entry: PListEntry) = - inc(list.counter) - entry.prev = nil - entry.next = list.head - if list.head != nil: - assert(list.head.prev == nil) - list.head.prev = entry - list.head = entry - if list.tail == nil: list.tail = entry - -proc prependStr*(list: var TLinkedList, data: string) = - prepend(list, newStrEntry(data)) +import os -proc insertBefore*(list: var TLinkedList, pos, entry: PListEntry) = - assert(pos != nil) - if pos == list.head: - prepend(list, entry) - else: - inc(list.counter) - entry.next = pos - entry.prev = pos.prev - if pos.prev != nil: pos.prev.next = entry - pos.prev = entry +static: + echo "WARNING: imported deprecated module compiler/lists.nim, use seq ore lists from the standard library" -proc remove*(list: var TLinkedList, entry: PListEntry) = - dec(list.counter) - if entry == list.tail: - list.tail = entry.prev - if entry == list.head: - list.head = entry.next - if entry.next != nil: entry.next.prev = entry.prev - if entry.prev != nil: entry.prev.next = entry.next +proc appendStr*(list: var seq[string]; data: string) {.deprecated.} = + # just use system.add + list.add(data) -proc bringToFront*(list: var TLinkedList, entry: PListEntry) = - when true: - list.remove entry - list.prepend entry +proc includeStr(list: var seq[string]; data: string): bool {.deprecated.} = + if list.contains(data): + result = true else: - if entry == list.head: return - if entry == list.tail: list.tail = entry.prev - if entry.next != nil: entry.next.prev = entry.prev - if entry.prev != nil: entry.prev.next = entry.next - entry.prev = nil - entry.next = list.head - list.head = entry - -proc excludePath*(list: var TLinkedList, data: string) = - var it = list.head - while it != nil: - let nxt = it.next - if cmpPaths(PStrEntry(it).data, data) == 0: - remove(list, it) - it = nxt + result = false + list.add data -proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry = - result = list.head - while result != nil: - if fn(result, closure): return - result = result.next 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/main.nim b/compiler/main.nim index 2acb7620c..5f86e6188 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -15,7 +15,7 @@ import wordrecg, sem, semdata, idents, passes, docgen, extccomp, cgen, jsgen, json, nversion, platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, - docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists, + docgen2, service, parser, modules, ccgutils, sigmatch, ropes, modulegraphs from magicsys import systemModule, resetSysTypes @@ -151,7 +151,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = # In "nim serve" scenario, each command must reset the registered passes clearPasses() gLastCmdTime = epochTime() - appendStr(searchPaths, options.libpath) + searchPaths.add(options.libpath) when false: # gProjectFull.len != 0: # current path is always looked first for modules prependStr(searchPaths, gProjectPath) @@ -229,7 +229,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = for s in definedSymbolNames(): definedSymbols.elems.add(%s) var libpaths = newJArray() - for dir in iterSearchPath(searchPaths): libpaths.elems.add(%dir) + for dir in searchPaths: libpaths.elems.add(%dir) var dumpdata = % [ (key: "version", val: %VersionAsString), @@ -245,7 +245,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = for s in definedSymbolNames(): msgWriteln(s, {msgStdout, msgSkipHook}) msgWriteln("-- end of list --", {msgStdout, msgSkipHook}) - for it in iterSearchPath(searchPaths): msgWriteln(it) + for it in searchPaths: msgWriteln(it) of "check": gCmd = cmdCheck commandCheck(graph, cache) 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/nimblecmd.nim b/compiler/nimblecmd.nim index 9c5c17287..e6466fc24 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -9,11 +9,11 @@ ## Implements some helper procs for Nimble (Nim's package manager) support. -import parseutils, strutils, strtabs, os, options, msgs, lists +import parseutils, strutils, strtabs, os, options, msgs proc addPath*(path: string, info: TLineInfo) = - if not contains(options.searchPaths, path): - lists.prependStr(options.searchPaths, path) + if not options.searchPaths.contains(path): + options.searchPaths.insert(path, 0) proc versionSplitPos(s: string): int = result = s.len-2 @@ -61,7 +61,7 @@ iterator chosen(packages: StringTableRef): string = proc addNimblePath(p: string, info: TLineInfo) = if not contains(options.searchPaths, p): message(info, hintPath, p) - lists.prependStr(options.lazyPaths, p) + options.lazyPaths.insert(p, 0) proc addPathRec(dir: string, info: TLineInfo) = var packages = newStringTable(modeStyleInsensitive) diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index 2872bdade..aca03fc16 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -10,7 +10,7 @@ ## exposes the Nim VM to clients. import ast, modules, passes, passaux, condsyms, - options, nimconf, lists, sem, semdata, llstream, vm, modulegraphs, idents + options, nimconf, sem, semdata, llstream, vm, modulegraphs, idents proc execute*(program: string) = passes.gIncludeFile = includeModule @@ -25,7 +25,7 @@ proc execute*(program: string) = registerPass(semPass) registerPass(evalPass) - appendStr(searchPaths, options.libpath) + searchPaths.add options.libpath var graph = newModuleGraph() var cache = newIdentCache() var m = makeStdinModule(graph) diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim index 4afb16912..a97d88078 100644 --- a/compiler/nimfix/nimfix.nim +++ b/compiler/nimfix/nimfix.nim @@ -13,7 +13,7 @@ import strutils, os, parseopt import compiler/[options, commands, modules, sem, passes, passaux, nimfix/pretty, msgs, nimconf, - extccomp, condsyms, lists, + extccomp, condsyms, modulegraphs, idents] const Usage = """ @@ -39,10 +39,10 @@ proc mainCommand = registerPass verbosePass registerPass semPass gCmd = cmdPretty - appendStr(searchPaths, options.libpath) + searchPaths.add options.libpath if gProjectFull.len != 0: # current path is always looked first for modules - prependStr(searchPaths, gProjectPath) + searchPaths.insert(gProjectPath, 0) compileProject(newModuleGraph(), newIdentCache()) pretty.overwriteFiles() diff --git a/compiler/options.nim b/compiler/options.nim index 2295bbf93..6281980ff 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -8,7 +8,7 @@ # import - os, lists, strutils, strtabs, osproc, sets + os, strutils, strtabs, osproc, sets const hasTinyCBackend* = defined(tinyc) @@ -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] @@ -129,7 +129,8 @@ var gExitcode*: int8 gCmd*: TCommands = cmdNone # the command gSelectedGC* = gcRefc # the selected GC - searchPaths*, lazyPaths*: TLinkedList + searchPaths*: seq[string] = @[] + lazyPaths*: seq[string] = @[] outFile*: string = "" docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \ # The string uses the formatting variables `path` and `line`. @@ -267,9 +268,7 @@ proc removeTrailingDirSep*(path: string): string = proc disableNimblePath*() = gNoNimblePath = true - lazyPaths.head = nil - lazyPaths.tail = nil - lazyPaths.counter = 0 + lazyPaths.setLen(0) include packagehandling @@ -336,27 +335,22 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = result = joinPath(subdir, tail) #echo "completeGeneratedFilePath(", f, ") = ", result -iterator iterSearchPath*(searchPaths: TLinkedList): string = - var it = PStrEntry(searchPaths.head) - while it != nil: - yield it.data - it = PStrEntry(it.next) - proc rawFindFile(f: string): string = - for it in iterSearchPath(searchPaths): + for it in searchPaths: result = joinPath(it, f) if existsFile(result): return result.canonicalizePath result = "" proc rawFindFile2(f: string): string = - var it = PStrEntry(lazyPaths.head) - while it != nil: - result = joinPath(it.data, f) + for i, it in lazyPaths: + result = joinPath(it, f) if existsFile(result): - bringToFront(lazyPaths, it) + # bring to front + for j in countDown(i,1): + swap(lazyPaths[j], lazyPaths[j-1]) + return result.canonicalizePath - it = PStrEntry(it.next) result = "" template patchModule() {.dirty.} = @@ -442,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 = @@ -456,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 3cc15147e..7966ee88d 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -11,7 +11,7 @@ # `TPass` interface. import - strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, + strutils, options, ast, astalgo, llstream, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, nimsets, syntaxes, times, rodread, idgen, modulegraphs @@ -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/pragmas.nim b/compiler/pragmas.nim index 04dbd3612..4476dab72 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -11,7 +11,7 @@ import os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer, - wordrecg, ropes, options, strutils, lists, extccomp, math, magicsys, trees, + wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees, rodread, types, lookups const @@ -25,19 +25,19 @@ const wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl, wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, - wOverride, wConstructor, wExportNims} + wOverride, wConstructor, wExportNims, wUsed} converterPragmas* = procPragmas methodPragmas* = procPragmas+{wBase}-{wImportCpp} templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty, - wDelegator, wExportNims} + wDelegator, wExportNims, wUsed} macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc, wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator, - wExportNims} + wExportNims, wUsed} iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises, - wTags, wLocks, wGcSafe, wExportNims} + wTags, wLocks, wGcSafe, wExportNims, wUsed} exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, @@ -55,16 +55,16 @@ const wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow, wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef, wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, - wBorrow, wGcSafe, wExportNims, wPartial} + wBorrow, wGcSafe, wExportNims, wPartial, wUsed} fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, - wImportCpp, wImportObjC, wError, wGuard, wBitsize} + wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed} varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern, wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal, - wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims} + wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims, wUsed} constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims, - wIntDefine, wStrDefine} + wIntDefine, wStrDefine, wUsed} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect, wThread, wRaises, wLocks, wTags, wGcSafe} @@ -218,20 +218,19 @@ proc processCallConv(c: PContext, n: PNode) = var sw = whichKeyword(n.sons[1].ident) case sw of FirstCallConv..LastCallConv: - POptionEntry(c.optionStack.tail).defaultCC = wordToCallConv(sw) + c.optionStack[^1].defaultCC = wordToCallConv(sw) else: localError(n.info, errCallConvExpected) else: localError(n.info, errCallConvExpected) proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib = - var it = PLib(c.libs.head) - while it != nil: - if it.kind == kind: - if trees.exprStructuralEquivalent(it.path, path): return it - it = PLib(it.next) + for it in c.libs: + if it.kind == kind and trees.exprStructuralEquivalent(it.path, path): + return it + result = newLib(kind) result.path = path - append(c.libs, result) + c.libs.add result if path.kind in {nkStrLit..nkTripleStrLit}: result.isOverriden = options.isDynlibOverride(path.strVal) @@ -254,7 +253,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) = if (sym == nil) or (sym.kind == skModule): let lib = getLib(c, libDynamic, expectDynlibNode(c, n)) if not lib.isOverriden: - POptionEntry(c.optionStack.tail).dynlib = lib + c.optionStack[^1].dynlib = lib else: if n.kind == nkExprColonExpr: var lib = getLib(c, libDynamic, expectDynlibNode(c, n)) @@ -350,12 +349,12 @@ proc processPush(c: PContext, n: PNode, start: int) = if n.sons[start-1].kind == nkExprColonExpr: localError(n.info, errGenerated, "':' after 'push' not supported") var x = newOptionEntry() - var y = POptionEntry(c.optionStack.tail) + var y = c.optionStack[^1] x.options = gOptions x.defaultCC = y.defaultCC x.dynlib = y.dynlib x.notes = gNotes - append(c.optionStack, x) + c.optionStack.add(x) for i in countup(start, sonsLen(n) - 1): if processOption(c, n.sons[i]): # simply store it somewhere: @@ -365,12 +364,12 @@ proc processPush(c: PContext, n: PNode, start: int) = #localError(n.info, errOptionExpected) proc processPop(c: PContext, n: PNode) = - if c.optionStack.counter <= 1: + if c.optionStack.len <= 1: localError(n.info, errAtPopWithoutPush) else: - gOptions = POptionEntry(c.optionStack.tail).options - gNotes = POptionEntry(c.optionStack.tail).notes - remove(c.optionStack, c.optionStack.tail) + gOptions = c.optionStack[^1].options + gNotes = c.optionStack[^1].notes + c.optionStack.setLen(c.optionStack.len - 1) proc processDefine(c: PContext, n: PNode) = if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent): @@ -582,7 +581,13 @@ proc pragmaLocks(c: PContext, it: PNode): TLockLevel = if it.kind != nkExprColonExpr: invalidPragma(it) else: - if it[1].kind != nkNilLit: + case it[1].kind + of nkStrLit, nkRStrLit, nkTripleStrLit: + if it[1].strVal == "unknown": + result = UnknownLockLevel + else: + localError(it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")") + else: let x = expectIntLit(c, it) if x < 0 or x > MaxLockLevel: localError(it[1].info, "integer must be within 0.." & $MaxLockLevel) @@ -961,14 +966,17 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, sym.magic = mIntDefine of wStrDefine: sym.magic = mStrDefine + of wUsed: + noVal(it) + if sym == nil: invalidPragma(it) + else: sym.flags.incl sfUsed else: invalidPragma(it) else: invalidPragma(it) proc implicitPragmas*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = if sym != nil and sym.kind != skModule: - var it = POptionEntry(c.optionStack.head) - while it != nil: + for it in c.optionStack: let o = it.otherPragmas if not o.isNil: pushInfoContext(n.info) @@ -976,11 +984,10 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode, if singlePragma(c, sym, o, i, validPragmas): internalError(n.info, "implicitPragmas") popInfoContext() - it = it.next.POptionEntry if lfExportLib in sym.loc.flags and sfExportc notin sym.flags: localError(n.info, errDynlibRequiresExportc) - var lib = POptionEntry(c.optionStack.tail).dynlib + var lib = c.optionStack[^1].dynlib if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and sfImportc in sym.flags and lib != nil: incl(sym.loc.flags, lfDynamicLib) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 1602988dd..5ce8414d6 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -10,7 +10,7 @@ # This module implements the renderer of the standard Nim representation. import - lexer, options, idents, strutils, ast, msgs, lists + lexer, options, idents, strutils, ast, msgs type TRenderFlag* = enum 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/scriptconfig.nim b/compiler/scriptconfig.nim index 9e94f1c19..0c31eadbe 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -12,7 +12,7 @@ import ast, modules, idents, passes, passaux, condsyms, - options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs, + options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs, os, times, osproc, wordrecg, strtabs, modulegraphs # we support 'cmpIgnoreStyle' natively for efficiency: @@ -153,7 +153,7 @@ proc runNimScript*(cache: IdentCache; scriptName: string; registerPass(semPass) registerPass(evalPass) - appendStr(searchPaths, options.libpath) + searchPaths.add(options.libpath) var m = graph.makeModule(scriptName) incl(m.flags, sfMainModule) diff --git a/compiler/sem.nim b/compiler/sem.nim index dbf237635..682e9d0ca 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -10,7 +10,7 @@ # This module implements the semantic checking pass. import - ast, strutils, hashes, lists, options, lexer, astalgo, trees, treetab, + ast, strutils, hashes, options, lexer, astalgo, trees, treetab, wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math, magicsys, parser, nversion, nimsets, semfold, importer, procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch, @@ -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 @@ -178,12 +178,17 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = if result.kind != kind: localError(n.info, "cannot use symbol of kind '" & $result.kind & "' as a '" & $kind & "'") + if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}: + # declarative context, so produce a fresh gensym: + result = copySym(result) + result.ast = n.sym.ast + put(c.p, n.sym, result) # 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) @@ -371,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) @@ -429,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: @@ -445,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 @@ -497,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 = @@ -518,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! @@ -528,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 20fd1d9be..77d461007 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -10,15 +10,14 @@ ## This module contains the data structures for the semantic checking phase. import - strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab, + strutils, intsets, options, lexer, ast, astalgo, trees, treetab, wordrecg, ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef, modulegraphs type - TOptionEntry* = object of lists.TListEntry # entries to put on a - # stack for pragma parsing + TOptionEntry* = object # entries to put on a stack for pragma parsing options*: TOptions defaultCC*: TCallingConvention dynlib*: PLib @@ -39,6 +38,7 @@ type next*: PProcCon # used for stacking procedure contexts wasForwarded*: bool # whether the current proc has a separate header bracketExpr*: PNode # current bracket expression (for ^ support) + mapping*: TIdTable TInstantiationPair* = object genericSym*: PSym @@ -78,10 +78,10 @@ type inGenericInst*: int # > 0 if we are instantiating a generic converters*: TSymSeq # sequence of converters patterns*: TSymSeq # sequence of pattern matchers - optionStack*: TLinkedList + optionStack*: seq[POptionEntry] symMapping*: TIdTable # every gensym'ed symbol needs to be mapped # to some new symbol in a generic instantiation - libs*: TLinkedList # all libs used by this module + libs*: seq[PLib] # all libs used by this module semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}): PNode {.nimcall.} @@ -124,29 +124,55 @@ 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 = - result = POptionEntry(c.optionStack.tail) + result = c.optionStack[^1] proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next +proc put*(p: PProcCon; key, val: PSym) = + if p.mapping.data == nil: initIdTable(p.mapping) + #echo "put into table ", key.info + p.mapping.idTablePut(key, val) + +proc get*(p: PProcCon; key: PSym): PSym = + if p.mapping.data == nil: return nil + result = PSym(p.mapping.idTableGet(key)) + +proc getGenSym*(c: PContext; s: PSym): PSym = + if sfGenSym notin s.flags: return s + var it = c.p + while it != nil: + result = get(it, s) + if result != nil: + #echo "got from table ", result.name.s, " ", result.info + return result + it = it.next + result = s + +proc considerGenSyms*(c: PContext; n: PNode) = + if n.kind == nkSym: + let s = getGenSym(c, n.sym) + if n.sym != s: + n.sym = s + else: + for i in 0..<n.safeLen: + considerGenSyms(c, n.sons[i]) + proc newOptionEntry*(): POptionEntry = new(result) result.options = gOptions @@ -157,9 +183,9 @@ proc newOptionEntry*(): POptionEntry = proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext = new(result) result.ambiguousSymbols = initIntSet() - initLinkedList(result.optionStack) - initLinkedList(result.libs) - append(result.optionStack, newOptionEntry()) + result.optionStack = @[] + result.libs = @[] + result.optionStack.add(newOptionEntry()) result.module = module result.friendModules = @[module] result.converters = @[] @@ -196,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) @@ -215,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 = @@ -225,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 = @@ -296,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 57674735a..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 @@ -922,10 +922,11 @@ proc readTypeParameter(c: PContext, typ: PType, return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info) #echo "came here: returned nil" -proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = +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, @@ -949,20 +950,20 @@ proc semSym(c: PContext, n: PNode, s: 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 ... @@ -984,7 +985,7 @@ proc semSym(c: PContext, n: PNode, s: 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 @@ -1002,7 +1003,7 @@ proc semSym(c: PContext, n: PNode, s: 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 @@ -1024,7 +1025,7 @@ proc semSym(c: PContext, n: PNode, s: 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)) @@ -1037,11 +1038,11 @@ proc semSym(c: PContext, n: PNode, s: 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) @@ -1061,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 @@ -1086,18 +1087,18 @@ 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: return readTypeParameter(c, ty, i, n.info) of tyObject, tyTuple: if ty.n != nil and ty.n.kind == nkRecList: - for field in ty.n: - if field.sym.name == i: - n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ]) - n.typ.n = copyTree(n) - return n + let field = lookupInRecord(ty.n, i) + if field != nil: + n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.typ]) + n.typ.n = copyTree(n) + return n else: # echo "TYPE FIELD ACCESS" # debug ty @@ -1119,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 @@ -1133,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) @@ -1580,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 = @@ -1591,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): @@ -1682,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 = {} @@ -1708,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 @@ -2106,8 +2106,8 @@ proc semBlock(c: PContext, n: PNode): PNode = var labl = newSymG(skLabel, n.sons[0], c) if sfGenSym notin labl.flags: addDecl(c, labl) - n.sons[0] = newSymNode(labl, n.sons[0].info) - suggestSym(n.sons[0].info, labl) + n.sons[0] = newSymNode(labl, n.sons[0].info) + 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/semfold.nim b/compiler/semfold.nim index 05e398c9a..58239d23e 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -11,7 +11,7 @@ # and evaluation phase import - strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times, + strutils, options, ast, astalgo, trees, treetab, nimsets, times, nversion, platform, math, msgs, os, condsyms, idents, renderer, types, commands, magicsys, saturate @@ -628,7 +628,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of {skProc, skMethod}: result = n of skType: - result = newSymNodeTypeDesc(s, n.info) + # XXX gensym'ed symbols can come here and cannot be resolved. This is + # dirty, but correct. + if s.typ != nil: + result = newSymNodeTypeDesc(s, n.info) of skGenericParam: if s.typ.kind == tyStatic: if s.typ.n != nil: @@ -656,7 +659,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode = localError(a.info, errCannotEvalXBecauseIncompletelyDefined, "sizeof") result = nil - elif skipTypes(a.typ, typedescInst).kind in + elif skipTypes(a.typ, typedescInst+{tyRange}).kind in IntegralTypes+NilableTypes+{tySet}: #{tyArray,tyObject,tyTuple}: result = newIntNodeT(getSize(a.typ), n) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index bc80c41ad..9c05ab2f9 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -174,7 +174,11 @@ proc semGenericStmt(c: PContext, n: PNode, # XXX for example: ``result.add`` -- ``add`` needs to be looked up here... var dummy: bool result = fuzzyLookup(c, n, flags, ctx, dummy) - of nkEmpty, nkSym..nkNilLit: + of nkSym: + let a = n.sym + let b = getGenSym(c, a) + if b != a: n.sym = b + of nkEmpty, succ(nkSym)..nkNilLit: # see tests/compile/tgensymgeneric.nim: # We need to open the gensym'ed symbol again so that the instantiation # creates a fresh copy; but this is wrong the very first reason for gensym diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 9c57be023..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: @@ -106,15 +106,18 @@ proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) = #if n.kind == nkSym and sfGenSym in n.sym.flags: # if n.sym.owner != orig: # echo "symbol ", n.sym.name.s, " orig ", orig, " owner ", n.sym.owner - if n.kind == nkSym and {sfGenSym, sfFromGeneric} * n.sym.flags == {sfGenSym}: # and + if n.kind == nkSym and sfGenSym in n.sym.flags: # and # (n.sym.owner == orig or n.sym.owner.kind in {skPackage}): let s = n.sym var x = PSym(idTableGet(symMap, s)) - if x == nil: + if x != nil: + n.sym = x + elif s.owner.kind == skPackage: + #echo "copied this ", s.name.s x = copySym(s, false) x.owner = owner idTablePut(symMap, s, x) - n.sym = x + n.sym = x else: for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, orig, symMap) @@ -252,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] @@ -301,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 25d4b3c74..c28dbf82f 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -30,12 +30,13 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = of nkIdent: s = lookUp(c, n.sons[0]) of nkSym: s = n.sons[0].sym else: illFormedAst(n) + s = getGenSym(c, s) if s.kind == skLabel and s.owner.id == c.p.owner.id: var x = newSymNode(s) 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 +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) = @@ -621,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: @@ -635,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): @@ -745,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: @@ -769,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 @@ -782,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: @@ -793,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 @@ -927,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) @@ -1002,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: @@ -1047,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 = @@ -1081,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) @@ -1089,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): @@ -1177,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 = @@ -1196,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: @@ -1213,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 @@ -1222,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: @@ -1288,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 {'.', '('}: @@ -1303,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) @@ -1334,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 @@ -1345,6 +1405,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, proc determineType(c: PContext, s: PSym) = if s.typ != nil: return #if s.magic != mNone: return + #if s.ast.isNil: return discard semProcAux(c, s.ast, s.kind, {}, stepDetermineType) proc semIterator(c: PContext, n: PNode): PNode = @@ -1352,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 @@ -1379,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 a69fe477b..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 @@ -172,7 +172,7 @@ proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym = result = newSym(kind, considerQuotedIdent(n), c.owner, n.info) incl(result.flags, sfGenSym) incl(result.flags, sfShadowed) - if c.scopeN == 0: incl(result.flags, sfFromGeneric) + #if c.scopeN == 0: incl(result.flags, sfFromGeneric) proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = # locals default to 'gensym': @@ -384,11 +384,13 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = checkSonsLen(n, 2) openScope(c) if n.sons[0].kind != nkEmpty: - # labels are always 'gensym'ed: - let s = newGenSym(skLabel, n.sons[0], c) - addPrelimDecl(c.c, s) - styleCheckDef(s) - n.sons[0] = newSymNode(s, n.sons[0].info) + addLocalDecl(c, n.sons[0], skLabel) + when false: + # labels are always 'gensym'ed: + let s = newGenSym(skLabel, n.sons[0], c) + addPrelimDecl(c.c, s) + styleCheckDef(s) + n.sons[0] = newSymNode(s, n.sons[0].info) n.sons[1] = semTemplBody(c, n.sons[1]) closeScope(c) of nkTryStmt: @@ -559,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: @@ -613,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: @@ -758,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 17c065b49..97af2c5cc 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -297,7 +297,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType = proc semTypeIdent(c: PContext, n: PNode): PSym = if n.kind == nkSym: - result = n.sym + result = getGenSym(c, n.sym) else: when defined(nimfix): result = pickSym(c, n, skType) @@ -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: @@ -1319,8 +1319,9 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = prev.id = s.typ.id result = prev of nkSym: - if n.sym.kind == skType and n.sym.typ != nil: - var t = n.sym.typ + let s = getGenSym(c, n.sym) + if s.kind == skType and s.typ != nil: + var t = s.typ let alias = maybeAliasType(c, t, prev) if alias != nil: result = alias @@ -1329,10 +1330,10 @@ 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 n.sym.kind != skError: localError(n.info, errTypeExpected) + if s.kind != skError: localError(n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) of nkObjectTy: result = semObjectNode(c, n, prev) of nkTupleTy: result = semTuple(c, n, prev) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 90253a691..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) @@ -1583,12 +1583,14 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode = result = c.semOperand(c, a, flags) else: result = a + considerGenSyms(c, result) proc prepareOperand(c: PContext; a: PNode): PNode = if a.typ.isNil: result = c.semOperand(c, a, {efDetermineType}) else: result = a + considerGenSyms(c, result) proc prepareNamedParam(a: PNode) = if a.sons[0].kind != nkIdent: 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 13c6dd8fe..0c53c0cbf 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -19,7 +19,7 @@ # * transforms 'defer' into a 'try finally' statement import - intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, + intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os, idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread, lambdalifting, sempass2, lowerings, lookups @@ -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 @@ -869,7 +870,12 @@ proc transform(c: PTransf, n: PNode): PTransNode = else: result = transformSons(c, n) of nkIdentDefs, nkConstDef: - result = transformSons(c, n) + when true: + result = transformSons(c, n) + else: + result = n.PTransNode + let L = n.len-1 + result[L] = transform(c, n.sons[L]) # XXX comment handling really sucks: if importantComments(): PNode(result).comment = n.comment diff --git a/compiler/trees.nim b/compiler/trees.nim index 7208f7d7b..424fba14c 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -38,7 +38,7 @@ proc exprStructuralEquivalent*(a, b: PNode; strictSymEquality=false): bool = # don't go nuts here: same symbol as string is enough: result = a.sym.name.id == b.sym.name.id of nkIdent: result = a.ident.id == b.ident.id - of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal + of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkEmpty, nkNilLit, nkType: result = true @@ -62,7 +62,7 @@ proc sameTree*(a, b: PNode): bool = # don't go nuts here: same symbol as string is enough: result = a.sym.name.id == b.sym.name.id of nkIdent: result = a.ident.id == b.ident.id - of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal + of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkEmpty, nkNilLit, nkType: result = true 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 = diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index cf66b6358..6072bd64c 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -45,7 +45,7 @@ type wImportc, wExportc, wExportNims, wIncompleteStruct, wRequiresInit, wAlign, wNodecl, wPure, wSideeffect, wHeader, wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib, - wCompilerproc, wProcVar, wBase, + wCompilerproc, wProcVar, wBase, wUsed, wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wLink, wCompile, wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger, @@ -131,7 +131,7 @@ const "incompletestruct", "requiresinit", "align", "nodecl", "pure", "sideeffect", "header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib", - "compilerproc", "procvar", "base", + "compilerproc", "procvar", "base", "used", "fatal", "error", "warning", "hint", "line", "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", "link", "compile", "linksys", "deprecated", "varargs", |