diff options
Diffstat (limited to 'compiler')
43 files changed, 456 insertions, 303 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index a61ac055e..a722f63f6 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -591,7 +591,7 @@ type mAddI, mSubI, mMulI, mDivI, mModI, mSucc, mPred, mAddF64, mSubF64, mMulF64, mDivF64, - mShrI, mShlI, mBitandI, mBitorI, mBitxorI, + mShrI, mShlI, mAshrI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, mMinF64, mMaxF64, mAddU, mSubU, mMulU, mDivU, mModU, @@ -972,8 +972,8 @@ const tyFloat..tyFloat128, tyUInt..tyUInt64} ConstantDataTypes*: TTypeKinds = {tyArray, tySet, tyTuple, tySequence} - NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence, - tyProc, tyString, tyError} + NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, + tyProc, tyError} ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType, skIterator, skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias} @@ -1151,7 +1151,10 @@ proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) = for i in countup(0, high(src.data)): dest.data[i] = src.data[i] proc discardSons*(father: PNode) = - father.sons = nil + when defined(nimNoNilSeqs): + father.sons = @[] + else: + father.sons = nil proc withInfo*(n: PNode, info: TLineInfo): PNode = n.info = info @@ -1368,7 +1371,7 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo; result.loc = s.loc result.annex = s.annex # XXX once usedGenerics is used, ensure module aliases keep working! - assert s.usedGenerics == nil + assert s.usedGenerics.len == 0 proc initStrTable*(x: var TStrTable) = x.counter = 0 @@ -1593,7 +1596,10 @@ proc getStr*(a: PNode): string = of nkStrLit..nkTripleStrLit: result = a.strVal of nkNilLit: # let's hope this fixes more problems than it creates: - result = nil + when defined(nimNoNilSeqs): + result = "" + else: + result = nil else: doAssert false, "getStr" #internalError(a.info, "getStr") @@ -1675,6 +1681,14 @@ proc skipStmtList*(n: PNode): PNode = else: result = n +proc toVar*(typ: PType): PType = + ## If ``typ`` is not a tyVar then it is converted into a `var <typ>` and + ## returned. Otherwise ``typ`` is simply returned as-is. + result = typ + if typ.kind != tyVar: + result = newType(tyVar, typ.owner) + rawAddSon(result, typ) + proc toRef*(typ: PType): PType = ## If ``typ`` is a tyObject then it is converted into a `ref <typ>` and ## returned. Otherwise ``typ`` is simply returned as-is. diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 333376f6a..152802ba1 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -412,6 +412,8 @@ proc debugTree(conf: ConfigRef; n: PNode, indent: int, maxRecDepth: int; else: addf(result, ",$N$1\"ident\": null", [istr]) else: + if renderType and n.typ != nil: + addf(result, ",$N$1\"typ\": $2", [istr, debugType(conf, n.typ, 2)]) if sonsLen(n) > 0: addf(result, ",$N$1\"sons\": [", [istr]) for i in countup(0, sonsLen(n) - 1): diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index ab15b9f2f..83461350b 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -435,7 +435,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = assert(sonsLen(typ) == sonsLen(typ.n)) # don't call '$' here for efficiency: let pat = ri.sons[0].sym.loc.r.data - internalAssert p.config, pat != nil + internalAssert p.config, pat.len > 0 if pat.contains({'#', '(', '@', '\''}): var pl = genPatternCall(p, ri, pat, typ) # simpler version of 'fixupCall' that works with the pl+params combination: @@ -484,7 +484,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = # don't call '$' here for efficiency: let pat = ri.sons[0].sym.loc.r.data - internalAssert p.config, pat != nil + internalAssert p.config, pat.len > 0 var start = 3 if ' ' in pat: start = 1 diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 5af0fe4e0..65cae8866 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -65,9 +65,10 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = of tyString: # with the new semantics for 'nil' strings, we can map "" to nil and # save tons of allocations: - #if n.strVal.len == 0: result = genNilStringLiteral(p.module, n.info) - #else: - result = genStringLiteral(p.module, n) + if n.strVal.len == 0 and optNilSeqs notin p.options: + result = genNilStringLiteral(p.module, n.info) + else: + result = genStringLiteral(p.module, n) else: if n.strVal.isNil: result = rope("NIM_NIL") else: result = makeCString(n.strVal) @@ -567,9 +568,9 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = "(($4)($1) - ($4)($2))", # SubF64 "(($4)($1) * ($4)($2))", # MulF64 "(($4)($1) / ($4)($2))", # DivF64 - "($4)((NU$5)($1) >> (NU$3)($2))", # ShrI "($4)((NU$3)($1) << (NU$3)($2))", # ShlI + "($4)((NI$3)($1) >> (NU$3)($2))", # AshrI "($4)($1 & $2)", # BitandI "($4)($1 | $2)", # BitorI "($4)($1 ^ $2)", # BitxorI @@ -996,7 +997,7 @@ proc genEcho(p: BProc, n: PNode) = # is threadsafe. internalAssert p.config, n.kind == nkBracket if p.config.target.targetOS == osGenode: - # bypass libc and print directly to the Genode LOG session + # echo directly to the Genode LOG session var args: Rope = nil var a: TLoc for it in n.sons: @@ -1004,8 +1005,9 @@ proc genEcho(p: BProc, n: PNode) = add(args, ", \"\"") else: initLocExpr(p, it, a) - add(args, ropecg(p.module, ", #nimToCStringConv($1)", [rdLoc(a)])) + add(args, ropecg(p.module, ", Genode::Cstring($1->data, $1->len)", [rdLoc(a)])) p.module.includeHeader("<base/log.h>") + p.module.includeHeader("<util/string.h>") linefmt(p, cpsStmts, """Genode::log(""$1);$n""", args) else: if n.len == 0: @@ -1112,8 +1114,8 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = initLoc(call, locCall, e, OnHeap) call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)]) genAssignment(p, dest, call, {}) + gcUsage(p.config, e) add(p.s(cpsStmts), appends) - gcUsage(p.config, e) proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq &= x --> @@ -1201,7 +1203,7 @@ proc genNew(p: BProc, e: PNode) = rawGenNew(p, a, nil) gcUsage(p.config, e) -proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) = +proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = let seqtype = skipTypes(dest.t, abstractVarRange) let args = [getTypeDesc(p.module, seqtype), genTypeInfo(p.module, seqtype, dest.lode.info), length] @@ -1212,10 +1214,14 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) = linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc) else: linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", dest.rdLoc) - call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args) - linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc) + if not lenIsZero: + call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args) + linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc) else: - call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args) + if lenIsZero: + call.r = rope"NIM_NIL" + else: + call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args) genAssignment(p, dest, call, {}) proc genNewSeq(p: BProc, e: PNode) = @@ -1228,7 +1234,9 @@ proc genNewSeq(p: BProc, e: PNode) = a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon), getSeqPayloadType(p.module, seqtype)) else: - genNewSeqAux(p, a, b.rdLoc) + let lenIsZero = optNilSeqs notin p.options and + e[2].kind == nkIntLit and e[2].intVal == 0 + genNewSeqAux(p, a, b.rdLoc, lenIsZero) gcUsage(p.config, e) proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = @@ -1328,7 +1336,8 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = elif d.k == locNone: getTemp(p, n.typ, d) # generate call to newSeq before adding the elements per hand: - genNewSeqAux(p, dest[], intLiteral(sonsLen(n))) + genNewSeqAux(p, dest[], intLiteral(sonsLen(n)), + optNilSeqs notin p.options and n.len == 0) for i in countup(0, sonsLen(n) - 1): initLoc(arr, locExpr, n[i], OnHeap) arr.r = ropecg(p.module, "$1$3[$2]", rdLoc(dest[]), intLiteral(i), dataField(p)) @@ -1351,7 +1360,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = getTemp(p, n.typ, d) # generate call to newSeq before adding the elements per hand: let L = int(lengthOrd(p.config, n.sons[1].typ)) - genNewSeqAux(p, d, intLiteral(L)) + genNewSeqAux(p, d, intLiteral(L), optNilSeqs notin p.options and L == 0) initLocExpr(p, n.sons[1], a) # bug #5007; do not produce excessive C source code: if L < 10: diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index 664f89b73..067a60c57 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -58,7 +58,7 @@ proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope = proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope = if compilationCachePresent(conf): - result = rope(nil) + result = rope("") add(result, "\n/*\t") add(result, CProcSectionNames[ps]) add(result, ":*/\n") diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 9a8d3bcd3..69e6558bb 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -256,7 +256,15 @@ proc genSingleVar(p: BProc, a: PNode) = # That's why we are doing the construction inside the preInitProc. # genObjectInit relies on the C runtime's guarantees that # global variables will be initialized to zero. - genObjectInit(p.module.preInitProc, cpsInit, v.typ, v.loc, true) + var loc = v.loc + + # When the native TLS is unavailable, a global thread-local variable needs + # one more layer of indirection in order to access the TLS block. + # Only do this for complex types that may need a call to `objectInit` + if sfThread in v.flags and emulatedThreadVars(p.config) and + isComplexValueType(v.typ): + initLocExprSingleUse(p.module.preInitProc, vn, loc) + genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, true) # Alternative construction using default constructor (which may zeromem): # if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc) if sfExportc in v.flags and p.module.g.generatedHeader != nil: @@ -1130,8 +1138,8 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = patchAsgnStmtListExpr(patchedTree, e, ri) genStmts(p, patchedTree) return - var a: TLoc + discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs)) if le.kind in {nkDerefExpr, nkHiddenDeref}: genDeref(p, le, a, enforceDeref=true) else: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 80c03f9e4..2cb431ff9 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1147,12 +1147,29 @@ proc genInitCode(m: BModule) = appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n", [m.nimTypesName, rope(m.nimTypes)]) + # Give this small function its own scope + addf(prc, "{$N", []) + block: + # Keep a bogus frame in case the code needs one + add(prc, ~"\tTFrame FR_; FR_.len = 0;$N") + + add(prc, genSectionStart(cpsLocals, m.config)) + add(prc, m.preInitProc.s(cpsLocals)) + add(prc, genSectionEnd(cpsLocals, m.config)) + + add(prc, genSectionStart(cpsInit, m.config)) + add(prc, m.preInitProc.s(cpsInit)) + add(prc, genSectionEnd(cpsInit, m.config)) + + add(prc, genSectionStart(cpsStmts, m.config)) + add(prc, m.preInitProc.s(cpsStmts)) + add(prc, genSectionEnd(cpsStmts, m.config)) + addf(prc, "}$N", []) + add(prc, initGCFrame(m.initProc)) add(prc, genSectionStart(cpsLocals, m.config)) - add(prc, m.preInitProc.s(cpsLocals)) add(prc, m.initProc.s(cpsLocals)) - add(prc, m.postInitProc.s(cpsLocals)) add(prc, genSectionEnd(cpsLocals, m.config)) if optStackTrace in m.initProc.options and frameDeclared notin m.flags: @@ -1166,16 +1183,13 @@ proc genInitCode(m: BModule) = add(prc, ~"\tTFrame FR_; FR_.len = 0;$N") add(prc, genSectionStart(cpsInit, m.config)) - add(prc, m.preInitProc.s(cpsInit)) add(prc, m.initProc.s(cpsInit)) - add(prc, m.postInitProc.s(cpsInit)) add(prc, genSectionEnd(cpsInit, m.config)) add(prc, genSectionStart(cpsStmts, m.config)) - add(prc, m.preInitProc.s(cpsStmts)) add(prc, m.initProc.s(cpsStmts)) - add(prc, m.postInitProc.s(cpsStmts)) add(prc, genSectionEnd(cpsStmts, m.config)) + if optStackTrace in m.initProc.options and preventStackTrace notin m.flags: add(prc, deinitFrame(m.initProc)) add(prc, deinitGCFrame(m.initProc)) @@ -1221,11 +1235,6 @@ proc newPreInitProc(m: BModule): BProc = # little hack so that unique temporaries are generated: result.labels = 100_000 -proc newPostInitProc(m: BModule): BProc = - result = newProc(nil, m) - # little hack so that unique temporaries are generated: - result.labels = 200_000 - proc initProcOptions(m: BModule): TOptions = let opts = m.config.options if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts @@ -1247,7 +1256,6 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule = result.initProc = newProc(nil, result) result.initProc.options = initProcOptions(result) result.preInitProc = newPreInitProc(result) - result.postInitProc = newPostInitProc(result) initNodeTable(result.dataCache) result.typeStack = @[] result.forwardedProcs = @[] @@ -1258,7 +1266,6 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule = if sfSystemModule in module.flags: incl result.flags, preventStackTrace excl(result.preInitProc.options, optStackTrace) - excl(result.postInitProc.options, optStackTrace) let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi") else: "" open(result.ndi, ndiName, g.config) @@ -1276,7 +1283,6 @@ proc resetModule*(m: BModule) = m.initProc = newProc(nil, m) m.initProc.options = initProcOptions(m) m.preInitProc = newPreInitProc(m) - m.postInitProc = newPostInitProc(m) initNodeTable(m.dataCache) m.typeStack = @[] m.forwardedProcs = @[] diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index a526a0f00..56dbd65a2 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -147,7 +147,6 @@ type 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 preInitProc*: BProc # code executed before the init proc typeStack*: TTypeSeq # used for type generation dataCache*: TNodeTable diff --git a/compiler/commands.nim b/compiler/commands.nim index ef5a2a40f..f7c8cf9f2 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -279,6 +279,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool of "implicitstatic": result = contains(conf.options, optImplicitStatic) of "patterns": result = contains(conf.options, optPatterns) of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace) + of "nilseqs": result = contains(conf.options, optNilSeqs) else: invalidCmdLineOption(conf, passCmd1, switch, info) proc processPath(conf: ConfigRef; path: string, info: TLineInfo, @@ -497,6 +498,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; else: localError(conf, info, errOnOrOffExpectedButXFound % arg) of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info) + of "nilseqs": processOnOffSwitch(conf, {optNilSeqs}, arg, pass, info) of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info) of "floatchecks": processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index d853ce969..0cf264ac3 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -12,6 +12,8 @@ import strtabs, platform, strutils, idents +from options import Feature + const catNone = "false" @@ -74,3 +76,10 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimVmExportFixed") defineSymbol("nimNewRuntime") defineSymbol("nimIncrSeqV3") + defineSymbol("nimAshr") + defineSymbol("nimNoNilSeqs") + defineSymbol("nimNoNilSeqs2") + + defineSymbol("nimHasNilSeqs") + for f in low(Feature)..high(Feature): + defineSymbol("nimHas" & $f) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 8d233566c..b35452365 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -191,7 +191,7 @@ proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr, proc genComment(d: PDoc, n: PNode): string = result = "" var dummyHasToc: bool - if n.comment != nil: + if n.comment.len > 0: renderRstToOut(d[], parseRst(n.comment, toFilename(d.conf, n.info), toLinenumber(n.info), toColumn(n.info), dummyHasToc, d.options, d.conf), result) @@ -205,7 +205,8 @@ proc genRecComment(d: PDoc, n: PNode): Rope = result = genRecComment(d, n.sons[i]) if result != nil: return else: - n.comment = nil + when defined(nimNoNilSeqs): n.comment = "" + else: n.comment = nil proc getPlainDocstring(n: PNode): string = ## Gets the plain text docstring of a node non destructively. @@ -215,7 +216,7 @@ proc getPlainDocstring(n: PNode): string = ## the concatenated ``##`` comments of the node. result = "" if n == nil: return - if n.comment != nil and startsWith(n.comment, "##"): + if startsWith(n.comment, "##"): result = n.comment if result.len < 1: for i in countup(0, safeLen(n)-1): @@ -564,9 +565,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = result = %{ "name": %name, "type": %($k), "line": %n.info.line.int, "col": %n.info.col} - if comm != nil and comm != "": + if comm.len > 0: result["description"] = %comm - if r.buf != nil: + if r.buf.len > 0: result["code"] = %r.buf proc checkForFalse(n: PNode): bool = @@ -634,7 +635,7 @@ proc add(d: PDoc; j: JsonNode) = proc generateJson*(d: PDoc, n: PNode) = case n.kind of nkCommentStmt: - if n.comment != nil and startsWith(n.comment, "##"): + if startsWith(n.comment, "##"): let stripped = n.comment.substr(2).strip d.add %{ "comment": %stripped, "line": %n.info.line.int, "col": %n.info.col } @@ -678,7 +679,7 @@ proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string = proc generateTags*(d: PDoc, n: PNode, r: var Rope) = case n.kind of nkCommentStmt: - if n.comment != nil and startsWith(n.comment, "##"): + if startsWith(n.comment, "##"): let stripped = n.comment.substr(2).strip r.add stripped of nkProcDef: diff --git a/compiler/idents.nim b/compiler/idents.nim index 0a2f2d5cf..58800b73d 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -30,14 +30,7 @@ type wordCounter: int idAnon*, idDelegator*, emptyIdent*: PIdent -when false: - var - legacy: IdentCache - -proc resetIdentCache*() = - when false: - for i in low(legacy.buckets)..high(legacy.buckets): - legacy.buckets[i] = nil +proc resetIdentCache*() = discard proc cmpIgnoreStyle*(a, b: cstring, blen: int): int = if a[0] != b[0]: return 1 @@ -73,11 +66,9 @@ proc cmpExact(a, b: cstring, blen: int): int = if result == 0: if a[i] != '\0': result = 1 -{.this: self.} - -proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PIdent = - var idx = h and high(buckets) - result = buckets[idx] +proc getIdent*(ic: IdentCache; identifier: cstring, length: int, h: Hash): PIdent = + var idx = h and high(ic.buckets) + result = ic.buckets[idx] var last: PIdent = nil var id = 0 while result != nil: @@ -85,8 +76,8 @@ proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PId if last != nil: # make access to last looked up identifier faster: last.next = result.next - result.next = buckets[idx] - buckets[idx] = result + result.next = ic.buckets[idx] + ic.buckets[idx] = result return elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0: assert((id == 0) or (id == result.id)) @@ -97,20 +88,20 @@ proc getIdent*(self: IdentCache; identifier: cstring, length: int, h: Hash): PId result.h = h result.s = newString(length) for i in countup(0, length - 1): result.s[i] = identifier[i] - result.next = buckets[idx] - buckets[idx] = result + result.next = ic.buckets[idx] + ic.buckets[idx] = result if id == 0: - inc(wordCounter) - result.id = -wordCounter + inc(ic.wordCounter) + result.id = -ic.wordCounter else: result.id = id -proc getIdent*(self: IdentCache; identifier: string): PIdent = - result = getIdent(cstring(identifier), len(identifier), +proc getIdent*(ic: IdentCache; identifier: string): PIdent = + result = getIdent(ic, cstring(identifier), len(identifier), hashIgnoreStyle(identifier)) -proc getIdent*(self: IdentCache; identifier: string, h: Hash): PIdent = - result = getIdent(cstring(identifier), len(identifier), h) +proc getIdent*(ic: IdentCache; identifier: string, h: Hash): PIdent = + result = getIdent(ic, cstring(identifier), len(identifier), h) proc newIdentCache*(): IdentCache = result = IdentCache() diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index ef54841ae..462c622aa 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -379,6 +379,7 @@ const # magic checked op; magic unchecked op; checked op; unchecked op ["", "", "($1 / $2)", "($1 / $2)"], # DivF64 ["", "", "", ""], # ShrI ["", "", "($1 << $2)", "($1 << $2)"], # ShlI + ["", "", "($1 >> $2)", "($1 >> $2)"], # AshrI ["", "", "($1 & $2)", "($1 & $2)"], # BitandI ["", "", "($1 | $2)", "($1 | $2)"], # BitorI ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI @@ -1266,7 +1267,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = if f.loc.r == nil: f.loc.r = mangleName(p.module, f) if sfInfixCall in f.flags: let pat = n.sons[0].sym.loc.r.data - internalAssert p.config, pat != nil + internalAssert p.config, pat.len > 0 if pat.contains({'#', '(', '@'}): var typ = skipTypes(n.sons[0].typ, abstractInst) assert(typ.kind == tyProc) @@ -1349,7 +1350,7 @@ proc arrayTypeForElemType(typ: PType): string = of tyUint8: "Uint8Array" of tyFloat32: "Float32Array" of tyFloat64, tyFloat: "Float64Array" - else: nil + else: "" proc createVar(p: PProc, typ: PType, indirect: bool): Rope = var t = skipTypes(typ, abstractInst) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 261dcb44e..c5a641713 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -92,7 +92,7 @@ const warnResultShadowed: "Special variable 'result' is shadowed.", warnInconsistentSpacing: "Number of spaces around '$#' is not consistent", warnUser: "$1", - hintSuccess: "operation successful", + hintSuccess: "operation successful: $#", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)", hintCC: "CC: \'$1\'", # unused hintLineTooLong: "line too long", @@ -164,13 +164,13 @@ type TNoteKinds* = set[TNoteKind] proc computeNotesVerbosity(): array[0..3, TNoteKinds] = - result[3] = {low(TNoteKind)..high(TNoteKind)} - {} - result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext} - result[1] = result[2] - {warnShadowIdent, warnProveField, warnProveIndex, - warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, - hintSource, hintGlobalVar, hintGCStats} - result[0] = result[1] - {hintSuccessX, hintConf, hintProcessing, - hintPattern, hintExecuting, hintLinking} + result[3] = {low(TNoteKind)..high(TNoteKind)} - {} + result[2] = result[3] - {hintStackTrace, warnUninit, hintExtendedContext} + result[1] = result[2] - {warnShadowIdent, warnProveField, warnProveIndex, + warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, + hintSource, hintGlobalVar, hintGCStats} + result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf, + hintProcessing, hintPattern, hintExecuting, hintLinking} const NotesVerbosity* = computeNotesVerbosity() diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 87694988a..1e9d963fa 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -11,7 +11,7 @@ import intsets, ast, astalgo, idents, semdata, types, msgs, options, - renderer, wordrecg, idgen, nimfix.prettybase, lineinfos, strutils + renderer, wordrecg, idgen, nimfix/prettybase, lineinfos, strutils proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) @@ -262,7 +262,7 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) = err.add "\nThis might be caused by a recursive module dependency: " err.add c.recursiveDep # prevent excessive errors for 'nim check' - c.recursiveDep = nil + c.recursiveDep = "" localError(c.config, info, errGenerated, err) proc lookUp*(c: PContext, n: PNode): PSym = diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 334cd1ae6..1eecc4176 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -65,10 +65,8 @@ type proc hash*(x: FileIndex): Hash {.borrow.} -{.this: g.} - proc stopCompile*(g: ModuleGraph): bool {.inline.} = - result = doStopCompile != nil and doStopCompile() + result = g.doStopCompile != nil and g.doStopCompile() proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym = result = newSym(skProc, getIdent(g.cache, name), nil, unknownLineInfo(), {}) @@ -98,44 +96,44 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = result.cacheTables = initTable[string, BTree[string, PNode]]() proc resetAllModules*(g: ModuleGraph) = - initStrTable(packageSyms) - deps = initIntSet() - modules = @[] - importStack = @[] - inclToMod = initTable[FileIndex, FileIndex]() - usageSym = nil - owners = @[] - methods = @[] - initStrTable(compilerprocs) - initStrTable(exposed) + initStrTable(g.packageSyms) + g.deps = initIntSet() + g.modules = @[] + g.importStack = @[] + g.inclToMod = initTable[FileIndex, FileIndex]() + g.usageSym = nil + g.owners = @[] + g.methods = @[] + initStrTable(g.compilerprocs) + initStrTable(g.exposed) proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = - if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len: - result = modules[fileIdx.int32] + if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len: + result = g.modules[fileIdx.int32] proc dependsOn(a, b: int): int {.inline.} = (a shl 15) + b proc addDep*(g: ModuleGraph; m: PSym, dep: FileIndex) = assert m.position == m.info.fileIndex.int32 addModuleDep(g.incr, g.config, m.info.fileIndex, dep, isIncludeFile = false) - if suggestMode: - deps.incl m.position.dependsOn(dep.int) + if g.suggestMode: + g.deps.incl m.position.dependsOn(dep.int) # we compute the transitive closure later when quering the graph lazily. # this improves efficiency quite a lot: #invalidTransitiveClosure = true proc addIncludeDep*(g: ModuleGraph; module, includeFile: FileIndex) = addModuleDep(g.incr, g.config, module, includeFile, isIncludeFile = true) - discard hasKeyOrPut(inclToMod, includeFile, module) + discard hasKeyOrPut(g.inclToMod, includeFile, module) proc parentModule*(g: ModuleGraph; fileIdx: FileIndex): FileIndex = ## returns 'fileIdx' if the file belonging to this index is ## directly used as a module or else the module that first ## references this include file. - if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len and modules[fileIdx.int32] != nil: + if fileIdx.int32 >= 0 and fileIdx.int32 < g.modules.len and g.modules[fileIdx.int32] != nil: result = fileIdx else: - result = inclToMod.getOrDefault(fileIdx) + result = g.inclToMod.getOrDefault(fileIdx) proc transitiveClosure(g: var IntSet; n: int) = # warshall's algorithm @@ -147,22 +145,22 @@ proc transitiveClosure(g: var IntSet; n: int) = g.incl i.dependsOn(j) proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) = - let m = getModule fileIdx + let m = g.getModule fileIdx if m != nil: incl m.flags, sfDirty proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) = # we need to mark its dependent modules D as dirty right away because after # nimsuggest is done with this module, the module's dirty flag will be # cleared but D still needs to be remembered as 'dirty'. - if invalidTransitiveClosure: - invalidTransitiveClosure = false - transitiveClosure(deps, modules.len) + if g.invalidTransitiveClosure: + g.invalidTransitiveClosure = false + transitiveClosure(g.deps, g.modules.len) # every module that *depends* on this file is also dirty: - for i in 0i32..<modules.len.int32: - let m = modules[i] - if m != nil and deps.contains(i.dependsOn(fileIdx.int)): + for i in 0i32..<g.modules.len.int32: + let m = g.modules[i] + if m != nil and g.deps.contains(i.dependsOn(fileIdx.int)): incl m.flags, sfDirty proc isDirty*(g: ModuleGraph; m: PSym): bool = - result = suggestMode and sfDirty in m.flags + result = g.suggestMode and sfDirty in m.flags diff --git a/compiler/msgs.nim b/compiler/msgs.nim index be2ece911..1d7939142 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -391,10 +391,10 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = if conf.structuredErrorHook != nil: conf.structuredErrorHook(conf, unknownLineInfo(), - s & (if kind != nil: KindFormat % kind else: ""), sev) + s & (if kind.len > 0: KindFormat % kind else: ""), sev) if not ignoreMsgBecauseOfIdeTools(conf, msg): - if kind != nil: + if kind.len > 0: styledMsgWriteln(color, title, resetStyle, s, KindColor, `%`(KindFormat, kind)) else: @@ -483,9 +483,9 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, if not ignoreMsg: if conf.structuredErrorHook != nil: - conf.structuredErrorHook(conf, info, s & (if kind != nil: KindFormat % kind else: ""), sev) + conf.structuredErrorHook(conf, info, s & (if kind.len > 0: KindFormat % kind else: ""), sev) if not ignoreMsgBecauseOfIdeTools(conf, msg): - if kind != nil: + if kind.len > 0: styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s, KindColor, `%`(KindFormat, kind)) else: diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index d3b4645dc..1a8a0acb5 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -220,7 +220,7 @@ proc readConfigFile( return true proc getUserConfigPath(filename: string): string = - result = joinPath(getConfigDir(), filename) + result = joinPath([getConfigDir(), "nim", filename]) proc getSystemConfigPath(conf: ConfigRef; filename: string): string = # try standard configuration file (installation did not distribute files @@ -228,8 +228,8 @@ proc getSystemConfigPath(conf: ConfigRef; filename: string): string = let p = getPrefixDir(conf) result = joinPath([p, "config", filename]) when defined(unix): - if not existsFile(result): result = joinPath([p, "etc", filename]) - if not existsFile(result): result = "/etc/" & filename + if not existsFile(result): result = joinPath([p, "etc/nim", filename]) + if not existsFile(result): result = "/etc/nim/" & filename proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) = setDefaultLibpath(conf) diff --git a/compiler/options.nim b/compiler/options.nim index a776961fc..04b14c65f 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -38,7 +38,8 @@ type # please make sure we have under 32 options optPatterns, # en/disable pattern matching optMemTracker, optHotCodeReloading, - optLaxStrings + optLaxStrings, + optNilSeqs TOptions* = set[TOption] TGlobalOption* = enum # **keep binary compatible** @@ -110,14 +111,16 @@ type ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod, ideHighlight, ideOutline, ideKnown, ideMsg - Feature* = enum ## experimental features + Feature* = enum ## experimental features; DO NOT RENAME THESE! implicitDeref, dotOperators, callOperator, parallel, destructor, notnil, - dynamicBindSym + dynamicBindSym, + forLoopMacros, + caseStmtMacros SymbolFilesOption* = enum disabledSf, writeOnlySf, readOnlySf, v2Sf @@ -354,6 +357,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = of "msdos": result = conf.target.targetOS == osDos of "mswindows", "win32": result = conf.target.targetOS == osWindows of "macintosh": result = conf.target.targetOS in {osMacos, osMacosx} + of "osx": result = conf.target.targetOS == osMacosx of "sunos": result = conf.target.targetOS == osSolaris of "nintendoswitch": result = conf.target.targetOS == osNintendoSwitch @@ -479,9 +483,20 @@ proc disableNimblePath*(conf: ConfigRef) = include packagehandling +proc getOsCacheDir(): string = + when defined(posix): + result = getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache") / "nim" + else: + result = getHomeDir() / genSubDir + proc getNimcacheDir*(conf: ConfigRef): string = - result = if conf.nimcacheDir.len > 0: conf.nimcacheDir - else: shortenDir(conf, conf.projectPath) / genSubDir + # XXX projectName should always be without a file extension! + result = if conf.nimcacheDir.len > 0: + conf.nimcacheDir + elif conf.cmd == cmdCompileToJS: + shortenDir(conf, conf.projectPath) / genSubDir + else: getOsCacheDir() / splitFile(conf.projectName).name & + (if isDefined(conf, "release"): "_r" else: "_d") proc pathSubs*(conf: ConfigRef; p, config: string): string = let home = removeTrailingDirSep(os.getHomeDir()) @@ -588,18 +603,22 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): string = proc findProjectNimFile*(conf: ConfigRef; pkg: string): string = const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"] var candidates: seq[string] = @[] - for k, f in os.walkDir(pkg, relative=true): - if k == pcFile and f != "config.nims": - let (_, name, ext) = splitFile(f) - if ext in extensions: - let x = changeFileExt(pkg / name, ".nim") - if fileExists(x): - candidates.add x - for c in candidates: - # nim-foo foo or foo nfoo - if (pkg in c) or (c in pkg): return c - if candidates.len >= 1: - return candidates[0] + var dir = pkg + while true: + for k, f in os.walkDir(dir, relative=true): + if k == pcFile and f != "config.nims": + let (_, name, ext) = splitFile(f) + if ext in extensions: + let x = changeFileExt(dir / name, ".nim") + if fileExists(x): + candidates.add x + for c in candidates: + # nim-foo foo or foo nfoo + if (pkg in c) or (c in pkg): return c + if candidates.len >= 1: + return candidates[0] + dir = parentDir(dir) + if dir == "": break return "" proc canonDynlibName(s: string): string = diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 944aec048..bbaf7a069 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -217,7 +217,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult if n.typ != nil and n.typ.kind == tyVar: result = arLValue of nkSym: - let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet} + let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet, skForVar} else: {skVar, skResult, skTemp} if n.sym.kind in kinds: if owner != nil and owner == n.sym.owner and diff --git a/compiler/parser.nim b/compiler/parser.nim index 5664a9f67..98ccb05b9 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -150,7 +150,8 @@ template sameOrNoInd(p): bool = p.tok.indent == p.currInd or p.tok.indent < 0 proc rawSkipComment(p: var TParser, node: PNode) = if p.tok.tokType == tkComment: if node != nil: - if node.comment == nil: node.comment = "" + when not defined(nimNoNilSeqs): + if node.comment == nil: node.comment = "" when defined(nimpretty): if p.tok.commentOffsetB > p.tok.commentOffsetA: add node.comment, fileSection(p.lex.config, p.lex.fileIdx, p.tok.commentOffsetA, p.tok.commentOffsetB) diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 2d2aeba76..ebb3a7c1d 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -21,14 +21,17 @@ type formals: int c: PContext subMatch: bool # subnode matches are special + mappingIsFull: bool PPatternContext = var TPatternContext proc getLazy(c: PPatternContext, sym: PSym): PNode = - if not isNil(c.mapping): + if c.mappingIsFull: result = c.mapping[sym.position] proc putLazy(c: PPatternContext, sym: PSym, n: PNode) = - if isNil(c.mapping): newSeq(c.mapping, c.formals) + if not c.mappingIsFull: + newSeq(c.mapping, c.formals) + c.mappingIsFull = true c.mapping[sym.position] = n proc matches(c: PPatternContext, p, n: PNode): bool @@ -209,7 +212,11 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode = for j in 0 ..< p.len: if not matches(c, p.sons[j], n.sons[i+j]): # we need to undo any bindings: - if not isNil(c.mapping): c.mapping = nil + when defined(nimNoNilSeqs): + c.mapping = @[] + c.mappingIsFull = false + else: + if not isNil(c.mapping): c.mapping = nil return false result = true diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index afe60e9dd..a067f2074 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1066,8 +1066,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wThis: if it.kind in nkPragmaCallKinds and it.len == 2: c.selfName = considerQuotedIdent(c, it[1]) + message(c.config, n.info, warnDeprecated, "the '.this' pragma") elif it.kind == nkIdent or it.len == 1: c.selfName = getIdent(c.cache, "self") + message(c.config, n.info, warnDeprecated, "the '.this' pragma") else: localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments") of wNoRewrite: diff --git a/compiler/renderer.nim b/compiler/renderer.nim index ce27e1cd9..c3e151f5a 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -281,7 +281,7 @@ const proc shouldRenderComment(g: var TSrcGen, n: PNode): bool = result = false - if n.comment != nil: + if n.comment.len > 0: result = (renderNoComments notin g.flags) or (renderDocComments in g.flags) @@ -402,7 +402,7 @@ proc lsons(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int = proc lsub(g: TSrcGen; n: PNode): int = # computes the length of a tree if isNil(n): return 0 - if n.comment != nil: return MaxLineLen + 1 + if n.comment.len > 0: return MaxLineLen + 1 case n.kind of nkEmpty: result = 0 of nkTripleStrLit: @@ -500,7 +500,7 @@ proc lsub(g: TSrcGen; n: PNode): int = of nkBreakStmt: result = lsub(g, n.sons[0]) + len("break_") of nkContinueStmt: result = lsub(g, n.sons[0]) + len("continue_") of nkPragma: result = lcomma(g, n) + 4 - of nkCommentStmt: result = if n.comment.isNil: 0 else: len(n.comment) + of nkCommentStmt: result = len(n.comment) of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_") of nkImportAs: result = lsub(g, n.sons[0]) + len("_as_") + lsub(g, n.sons[1]) of nkElifBranch: result = lsons(g, n) + len("elif_:_") @@ -539,7 +539,7 @@ proc gsub(g: var TSrcGen, n: PNode) = proc hasCom(n: PNode): bool = result = false if n.isNil: return false - if n.comment != nil: return true + if n.comment.len > 0: return true case n.kind of nkEmpty..nkNilLit: discard else: @@ -602,7 +602,7 @@ proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType, dedent(g) proc longMode(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): bool = - result = n.comment != nil + result = n.comment.len > 0 if not result: # check further for i in countup(start, sonsLen(n) + theEnd): @@ -637,7 +637,7 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) = proc gcond(g: var TSrcGen, n: PNode) = if n.kind == nkStmtListExpr: put(g, tkParLe, "(") - gsub(g, n) + gsub(g, n) if n.kind == nkStmtListExpr: put(g, tkParRi, ")") @@ -864,7 +864,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = if isNil(n): return var a: TContext - if n.comment != nil: pushCom(g, n) + if n.comment.len > 0: pushCom(g, n) case n.kind # atoms: of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n)) of nkEmpty: discard @@ -1079,7 +1079,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = elif n[0].kind in {nkOpenSymChoice, nkClosedSymChoice}: n[0][0].sym.name else: nil var n_next = n[1] - while n_next.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, + while n_next.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString} and n_next.len > 0: n_next = n_next[0] if n_next.kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)): diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 66d7f63c2..a774cdba7 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -10,6 +10,27 @@ ## Serialization utilities for the compiler. import strutils, math +# MSVC prior to 2013 doesn't have C99 functions +when defined(windows) and (defined(vcc) or defined(bcc)): + {.emit: """#if defined(_MSC_VER) && _MSC_VER < 1900 + #include <stdarg.h> + static int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { + int count = -1; + if (size != 0) count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) count = _vscprintf(format, ap); + return count; + } + int snprintf(char *outBuf, size_t size, const char *format, ...) { + int count; + va_list ap; + va_start(ap, format); + count = c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + return count; + } + #endif + """.} + proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "<stdio.h>", nodecl, varargs.} proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = diff --git a/compiler/ropes.nim b/compiler/ropes.nim index 973f16916..81ee01dbf 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -66,29 +66,19 @@ type Rope* = ref RopeObj RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented # by nil to safe space - left*, right*: Rope - length*: int - data*: string # != nil if a leaf + left, right: Rope + L: int # <= 0 if a leaf + data*: string proc len*(a: Rope): int = ## the rope's length if a == nil: result = 0 - else: result = a.length + else: result = abs a.L -proc newRope(data: string = nil): Rope = +proc newRope(data: string = ""): Rope = new(result) - if data != nil: - result.length = len(data) - result.data = data - -proc newMutableRope*(capacity = 30): Rope = - ## creates a new rope that supports direct modifications of the rope's - ## 'data' and 'length' fields. - new(result) - result.data = newStringOfCap(capacity) - -proc freezeMutableRope*(r: Rope) {.inline.} = - r.length = r.data.len + result.L = -len(data) + result.data = data var cache: array[0..2048*2 - 1, Rope] # XXX Global here! @@ -147,7 +137,7 @@ proc `&`*(a, b: Rope): Rope = result = a else: result = newRope() - result.length = a.length + b.length + result.L = abs(a.L) + abs(b.L) result.left = a result.right = b diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index ae7e030b8..659206a40 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -45,7 +45,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string; template cbos(name, body) {.dirty.} = result.registerCallback "stdlib.system." & astToStr(name), proc (a: VmArgs) = - errorMsg = nil + errorMsg = "" try: body except OSError: @@ -159,8 +159,11 @@ proc runNimScript*(cache: IdentCache; scriptName: string; defineSymbol(conf.symbols, "nimscript") defineSymbol(conf.symbols, "nimconfig") - registerPass(graph, semPass) - registerPass(graph, evalPass) + var registeredPasses {.global.} = false + if not registeredPasses: + registerPass(graph, semPass) + registerPass(graph, evalPass) + registeredPasses = true conf.searchPaths.add(conf.libpath) diff --git a/compiler/sem.nim b/compiler/sem.nim index 2c3fab5a5..6128c02d1 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -16,12 +16,12 @@ import procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, - semparallel, lowerings, pluginsupport, plugins.active, rod, lineinfos + semparallel, lowerings, pluginsupport, plugins/active, rod, lineinfos from modulegraphs import ModuleGraph when defined(nimfix): - import nimfix.prettybase + import nimfix/prettybase # implementation @@ -119,7 +119,7 @@ proc commonType*(x, y: PType): PType = elif b.kind == tyStmt: result = b elif a.kind == tyTypeDesc: # turn any concrete typedesc into the abstract typedesc type - if a.sons == nil: result = a + if a.len == 0: result = a else: result = newType(tyTypeDesc, a.owner) rawAddSon(result, newType(tyNone, a.owner)) @@ -621,7 +621,8 @@ proc testExamples(c: PContext) = if os.execShellCmd(os.getAppFilename() & " " & backend & " --nimcache:" & nimcache & " -r " & outp) != 0: quit "[Examples] failed: see " & outp else: - removeFile(outp) + # keep generated source file `outp` to allow inspection. + rawMessage(c.config, hintSuccess, ["runnableExamples: " & outp]) removeFile(outp.changeFileExt(ExeExt)) try: removeDir(nimcache) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index aa5394a71..ef452fcdc 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -89,7 +89,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, continue determineType(c, sym) initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag) - if c.currentScope.symbols.counter == counterInitial or syms != nil: + if c.currentScope.symbols.counter == counterInitial or syms.len != 0: matches(c, n, orig, z) if z.state == csMatch: #if sym.name.s == "==" and (n.info ?? "temp3"): @@ -237,7 +237,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) = if symx.kind in routineKinds: errors.add(CandidateError(sym: symx, unmatchedVarParam: 0, firstMismatch: 0, - diagnostics: nil, + diagnostics: @[], enabled: false)) symx = nextOverloadIter(o, c, headSymbol) if errors.len == 0: @@ -455,7 +455,7 @@ proc tryDeref(n: PNode): PNode = proc semOverloadedCall(c: PContext, n, nOrig: PNode, filter: TSymKinds, flags: TExprFlags): PNode = - var errors: CandidateErrors = if efExplain in flags: @[] else: nil + var errors: CandidateErrors = @[] # if efExplain in flags: @[] else: nil var r = resolveOverloads(c, n, nOrig, filter, flags, errors, efExplain in flags) if r.state == csMatch: # this may be triggered, when the explain pragma is used diff --git a/compiler/semdata.nim b/compiler/semdata.nim index aa0cb6e8e..4189a5214 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -37,6 +37,7 @@ type # in standalone ``except`` and ``finally`` next*: PProcCon # used for stacking procedure contexts wasForwarded*: bool # whether the current proc has a separate header + mappingExists*: bool mapping*: TIdTable TMatchedConcept* = object @@ -176,12 +177,14 @@ proc lastOptionEntry*(c: PContext): POptionEntry = 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) + if not p.mappingExists: + initIdTable(p.mapping) + p.mappingExists = true #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 + if not p.mappingExists: return nil result = PSym(p.mapping.idTableGet(key)) proc getGenSym*(c: PContext; s: PSym): PSym = diff --git a/compiler/semfold.nim b/compiler/semfold.nim index d2abfac13..a6c185fdc 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -268,6 +268,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode = of tyInt64, tyInt, tyUInt..tyUInt64: result = newIntNodeT(`shr`(getInt(a), getInt(b)), n, g) else: internalError(g.config, n.info, "constant folding for shr") + of mAshrI: + case skipTypes(n.typ, abstractRange).kind + of tyInt8: result = newIntNodeT(ashr(int8(getInt(a)), int8(getInt(b))), n, g) + of tyInt16: result = newIntNodeT(ashr(int16(getInt(a)), int16(getInt(b))), n, g) + of tyInt32: result = newIntNodeT(ashr(int32(getInt(a)), int32(getInt(b))), n, g) + of tyInt64, tyInt: + result = newIntNodeT(ashr(getInt(a), getInt(b)), n, g) + else: internalError(g.config, n.info, "constant folding for ashr") of mDivI: result = foldDiv(getInt(a), getInt(b), n, g) of mModI: result = foldMod(getInt(a), getInt(b), n, g) of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index fac04e3a0..f9d7c3754 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -97,10 +97,9 @@ proc sameInstantiation(a, b: TInstantiation): bool = proc genericCacheGet(genericSym: PSym, entry: TInstantiation; id: CompilesId): PSym = - if genericSym.procInstCache != nil: - for inst in genericSym.procInstCache: - if inst.compilesId == id and sameInstantiation(entry, inst[]): - return inst.sym + for inst in genericSym.procInstCache: + if inst.compilesId == id and sameInstantiation(entry, inst[]): + return inst.sym when false: proc `$`(x: PSym): string = diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index 02c56c035..3056f5d72 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -88,7 +88,7 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) = else: globalError(conf, n.info, "string literal must be of some string type") of nkNilLit: - if x.kind in NilableTypes: + if x.kind in NilableTypes+{tyString, tySequence}: n.typ = t else: globalError(conf, n.info, "nil literal must be of some pointer type") diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 8b639806d..90ab2c57a 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -121,7 +121,7 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string if {tfNotNil, tfNeedsInit} * r.sym.typ.flags != {}: let assignment = locateFieldInInitExpr(c, r.sym, initExpr) if assignment == nil: - if result == nil: + if result.len == 0: result = r.sym.name.s else: result.add ", " @@ -129,7 +129,7 @@ proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string proc checkForMissingFields(c: PContext, recList, initExpr: PNode) = let missing = missingMandatoryFields(c, recList, initExpr) - if missing != nil: + if missing.len > 0: localError(c.config, initExpr.info, "fields not initialized: $1.", [missing]) proc semConstructFields(c: PContext, recNode: PNode, diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f7d8b6b7b..3a1278137 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -178,71 +178,6 @@ proc semIf(c: PContext, n: PNode): PNode = result.kind = nkIfExpr result.typ = typ -proc semCase(c: PContext, n: PNode): PNode = - result = n - checkMinSonsLen(n, 2, c.config) - openScope(c) - n.sons[0] = semExprWithType(c, n.sons[0]) - var chckCovered = false - var covered: BiggestInt = 0 - var typ = commonTypeBegin - var hasElse = false - let caseTyp = skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}) - case caseTyp.kind - of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool: - chckCovered = true - of tyFloat..tyFloat128, tyString, tyError: - discard - else: - localError(c.config, n.info, errSelectorMustBeOfCertainTypes) - return - for i in countup(1, sonsLen(n) - 1): - var x = n.sons[i] - when defined(nimsuggest): - if c.config.ideCmd == ideSug and exactEquals(c.config.m.trackPos, x.info) and caseTyp.kind == tyEnum: - suggestEnum(c, x, caseTyp) - case x.kind - of nkOfBranch: - checkMinSonsLen(x, 2, c.config) - semCaseBranch(c, n, x, i, covered) - var last = sonsLen(x)-1 - x.sons[last] = semExprBranchScope(c, x.sons[last]) - typ = commonType(typ, x.sons[last]) - of nkElifBranch: - chckCovered = false - checkSonsLen(x, 2, c.config) - openScope(c) - x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0])) - x.sons[1] = semExprBranch(c, x.sons[1]) - typ = commonType(typ, x.sons[1]) - closeScope(c) - of nkElse: - chckCovered = false - checkSonsLen(x, 1, c.config) - x.sons[0] = semExprBranchScope(c, x.sons[0]) - typ = commonType(typ, x.sons[0]) - hasElse = true - else: - illFormedAst(x, c.config) - if chckCovered: - if covered == toCover(c, n.sons[0].typ): - hasElse = true - else: - localError(c.config, n.info, "not all cases are covered") - closeScope(c) - if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: - for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) - # propagate any enforced VoidContext: - if typ == c.enforceVoidContext: - result.typ = c.enforceVoidContext - else: - for i in 1..n.len-1: - var it = n.sons[i] - let j = it.len-1 - if not endsInNoReturn(it.sons[j]): - it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info) - result.typ = typ - proc semTry(c: PContext, n: PNode): PNode = var check = initIntSet() @@ -683,29 +618,28 @@ proc isTrivalStmtExpr(n: PNode): bool = return false result = true -proc handleForLoopMacro(c: PContext; n: PNode): PNode = - let iterExpr = n[^2] - if iterExpr.kind in nkCallKinds: +proc handleStmtMacro(c: PContext; n, selector: PNode; magicType: string): PNode = + if selector.kind in nkCallKinds: # we transform # n := for a, b, c in m(x, y, z): Y # to # m(n) - let forLoopStmt = magicsys.getCompilerProc(c.graph, "ForLoopStmt") - if forLoopStmt == nil: return + let maType = magicsys.getCompilerProc(c.graph, magicType) + if maType == nil: return - let headSymbol = iterExpr[0] + let headSymbol = selector[0] var o: TOverloadIter var match: PSym = nil var symx = initOverloadIter(o, c, headSymbol) while symx != nil: if symx.kind in {skTemplate, skMacro}: - if symx.typ.len == 2 and symx.typ[1] == forLoopStmt.typ: + if symx.typ.len == 2 and symx.typ[1] == maType.typ: if match == nil: match = symx else: localError(c.config, n.info, errAmbiguousCallXYZ % [ getProcHeader(c.config, match), - getProcHeader(c.config, symx), $iterExpr]) + getProcHeader(c.config, symx), $selector]) symx = nextOverloadIter(o, c, headSymbol) if match == nil: return @@ -717,11 +651,44 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode = of skTemplate: result = semTemplateExpr(c, callExpr, match, {}) else: result = nil +proc handleForLoopMacro(c: PContext; n: PNode): PNode = + result = handleStmtMacro(c, n, n[^2], "ForLoopStmt") + +proc handleCaseStmtMacro(c: PContext; n: PNode): PNode = + # n[0] has been sem'checked and has a type. We use this to resolve + # 'match(n[0])' but then we pass 'n' to the 'match' macro. This seems to + # be the best solution. + var toResolve = newNodeI(nkCall, n.info) + toResolve.add newIdentNode(getIdent(c.cache, "match"), n.info) + toResolve.add n[0] + + var errors: CandidateErrors + var r = resolveOverloads(c, toResolve, toResolve, {skTemplate, skMacro}, {}, + errors, false) + if r.state == csMatch: + var match = r.calleeSym + markUsed(c.config, n[0].info, match, c.graph.usageSym) + styleCheckUse(n[0].info, match) + + # but pass 'n' to the 'match' macro, not 'n[0]': + r.call.sons[1] = n + let toExpand = semResolvedCall(c, r, r.call, {}) + case match.kind + of skMacro: result = semMacroExpr(c, toExpand, toExpand, match, {}) + of skTemplate: result = semTemplateExpr(c, toExpand, match, {}) + else: result = nil + # this would be the perfectly consistent solution with 'for loop macros', + # but it kinda sucks for pattern matching as the matcher is not attached to + # a type then: + when false: + result = handleStmtMacro(c, n, n[0], "CaseStmt") + proc semFor(c: PContext, n: PNode): PNode = checkMinSonsLen(n, 3, c.config) var length = sonsLen(n) - result = handleForLoopMacro(c, n) - if result != nil: return result + if forLoopMacros in c.features: + result = handleForLoopMacro(c, n) + if result != nil: return result openScope(c) result = n n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator}) @@ -757,6 +724,75 @@ proc semFor(c: PContext, n: PNode): PNode = result.typ = c.enforceVoidContext closeScope(c) +proc semCase(c: PContext, n: PNode): PNode = + result = n + checkMinSonsLen(n, 2, c.config) + openScope(c) + n.sons[0] = semExprWithType(c, n.sons[0]) + var chckCovered = false + var covered: BiggestInt = 0 + var typ = commonTypeBegin + var hasElse = false + let caseTyp = skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}) + case caseTyp.kind + of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool: + chckCovered = true + of tyFloat..tyFloat128, tyString, tyError: + discard + else: + if caseStmtMacros in c.features: + result = handleCaseStmtMacro(c, n) + if result != nil: return result + + localError(c.config, n.info, errSelectorMustBeOfCertainTypes) + return + for i in countup(1, sonsLen(n) - 1): + var x = n.sons[i] + when defined(nimsuggest): + if c.config.ideCmd == ideSug and exactEquals(c.config.m.trackPos, x.info) and caseTyp.kind == tyEnum: + suggestEnum(c, x, caseTyp) + case x.kind + of nkOfBranch: + checkMinSonsLen(x, 2, c.config) + semCaseBranch(c, n, x, i, covered) + var last = sonsLen(x)-1 + x.sons[last] = semExprBranchScope(c, x.sons[last]) + typ = commonType(typ, x.sons[last]) + of nkElifBranch: + chckCovered = false + checkSonsLen(x, 2, c.config) + openScope(c) + x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0])) + x.sons[1] = semExprBranch(c, x.sons[1]) + typ = commonType(typ, x.sons[1]) + closeScope(c) + of nkElse: + chckCovered = false + checkSonsLen(x, 1, c.config) + x.sons[0] = semExprBranchScope(c, x.sons[0]) + typ = commonType(typ, x.sons[0]) + hasElse = true + else: + illFormedAst(x, c.config) + if chckCovered: + if covered == toCover(c, n.sons[0].typ): + hasElse = true + else: + localError(c.config, n.info, "not all cases are covered") + closeScope(c) + if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: + for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) + # propagate any enforced VoidContext: + if typ == c.enforceVoidContext: + result.typ = c.enforceVoidContext + else: + for i in 1..n.len-1: + var it = n.sons[i] + let j = it.len-1 + if not endsInNoReturn(it.sons[j]): + it.sons[j] = fitNode(c, typ, it.sons[j], it.sons[j].info) + result.typ = typ + proc semRaise(c: PContext, n: PNode): PNode = result = n checkSonsLen(n, 1, c.config) @@ -970,7 +1006,10 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = var body = s.typ.lastSon if body.kind == tyObject: # erases all declared fields - body.n.sons = nil + when defined(nimNoNilSeqs): + body.n.sons = @[] + else: + body.n.sons = nil popOwner(c) closeScope(c) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 28dd15209..1669a7707 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -196,6 +196,8 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = if region.skipTypes({tyGenericInst, tyAlias, tySink}).kind notin { tyError, tyObject}: message c.config, n[i].info, errGenerated, "region needs to be an object type" + else: + message(c.config, n.info, warnDeprecated, "region for pointer types") addSonSkipIntLit(result, region) addSonSkipIntLit(result, t) if tfPartial in result.flags: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index ff7cb0bb0..c315cbebb 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -40,8 +40,8 @@ proc searchInstTypes*(key: PType): PType = if not (genericTyp.kind == tyGenericBody and key.sons[0] == genericTyp and genericTyp.sym != nil): return - if genericTyp.sym.typeInstCache == nil: - return + when not defined(nimNoNilSeqs): + if genericTyp.sym.typeInstCache == nil: return for inst in genericTyp.sym.typeInstCache: if inst.id == key.id: return inst diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 29f16b808..f206119ec 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -143,7 +143,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, c.calleeScope = 1 else: c.calleeScope = calleeScope - c.diagnostics = if diagnosticsEnabled: @[] else: nil + c.diagnostics = @[] # if diagnosticsEnabled: @[] else: nil c.diagnosticsEnabled = diagnosticsEnabled c.magic = c.calleeSym.magic initIdTable(c.bindings) @@ -535,6 +535,12 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation = proc allowsNil(f: PType): TTypeRelation {.inline.} = result = if tfNotNil notin f.flags: isSubtype else: isNone +proc allowsNilDeprecated(c: TCandidate, f: PType): TTypeRelation = + if optNilSeqs in c.c.config.options: + result = allowsNil(f) + else: + result = isNone + proc inconsistentVarTypes(f, a: PType): bool {.inline.} = result = f.kind != a.kind and (f.kind in {tyVar, tyLent} or a.kind in {tyVar, tyLent}) @@ -741,7 +747,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = diagnostics = @[] flags = {efExplain} m.c.config.writelnHook = proc (s: string) = - if errorPrefix == nil: errorPrefix = typeClass.sym.name.s & ":" + if errorPrefix.len == 0: errorPrefix = typeClass.sym.name.s & ":" let msg = s.replace("Error:", errorPrefix) if oldWriteHook != nil: oldWriteHook msg diagnostics.add msg @@ -858,6 +864,10 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool = if lhs[2].kind == nkIntLit: return inferStaticParam(c, lhs[1], rhs shl lhs[2].intVal) + of mAshrI: + if lhs[2].kind == nkIntLit: + return inferStaticParam(c, lhs[1], ashr(rhs, lhs[2].intVal)) + of mUnaryMinusI: return inferStaticParam(c, lhs[1], -rhs) @@ -1249,7 +1259,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, result = isNone elif tfNotNil in f.flags and tfNotNil notin a.flags: result = isNilConversion - of tyNil: result = f.allowsNil + of tyNil: result = allowsNilDeprecated(c, f) else: discard of tyOrdinal: if isOrdinalType(a): @@ -1334,7 +1344,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, result = isNilConversion else: result = isEqual - of tyNil: result = f.allowsNil + of tyNil: result = allowsNilDeprecated(c, f) else: discard of tyCString: # conversion from string to cstring is automatic: @@ -1608,7 +1618,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, if f.sonsLen == 0: result = isGeneric else: - internalAssert c.c.graph.config, a.sons != nil and a.sons.len > 0 + internalAssert c.c.graph.config, a.len > 0 c.typedescMatched = true var aa = a while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0: @@ -1806,6 +1816,10 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, let srca = typeRel(m, src, a) if srca notin {isEqual, isGeneric, isSubtype}: continue + let constraint = c.converters[i].typ.n[1].sym.constraint + if not constraint.isNil and not matchNodeKinds(constraint, arg): + continue + let destIsGeneric = containsGenericType(dest) if destIsGeneric: dest = generateTypeInstance(c, m.bindings, arg, dest) diff --git a/compiler/transf.nim b/compiler/transf.nim index acfccb5ff..84297aa6a 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -369,6 +369,8 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode = result = PTransNode(n.sons[0]) if n.typ.skipTypes(abstractVar).kind != tyOpenArray: PNode(result).typ = n.typ + elif n.typ.skipTypes(abstractInst).kind in {tyVar}: + PNode(result).typ = toVar(PNode(result).typ) of nkHiddenStdConv, nkHiddenSubConv, nkConv: var m = n.sons[0].sons[1] if m.kind == a or m.kind == b: @@ -377,6 +379,8 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode = result = PTransNode(n.sons[0]) if n.typ.skipTypes(abstractVar).kind != tyOpenArray: PNode(result).typ = n.typ + elif n.typ.skipTypes(abstractInst).kind in {tyVar}: + PNode(result).typ = toVar(PNode(result).typ) else: if n.sons[0].kind == a or n.sons[0].kind == b: # addr ( deref ( x )) --> x @@ -539,11 +543,8 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or call.sons[0].typ.callConv == ccClosure: n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode - if not c.tooEarly: - n.sons[length-2] = transform(c, n.sons[length-2]).PNode - result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode - else: - result[1] = newNode(nkEmpty).PTransNode + n.sons[length-2] = transform(c, n.sons[length-2]).PNode + result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode discard c.breakSyms.pop return result diff --git a/compiler/types.nim b/compiler/types.nim index 514f5cee5..674819bc5 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -430,7 +430,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = t.sym.name.s & " literal(" & $t.n.intVal & ")" elif prefer in {preferName, preferTypeName} or t.sym.owner.isNil: result = t.sym.name.s - if t.kind == tyGenericParam and t.sons != nil and t.sonsLen > 0: + if t.kind == tyGenericParam and t.sonsLen > 0: result.add ": " var first = true for son in t.sons: @@ -1202,7 +1202,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, tyNone, tyForward, tyFromExpr: result = t of tyNil: - if kind != skConst: result = t + if kind != skConst and kind != skParam: result = t of tyString, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, tyPointer: result = nil of tyOrdinal: @@ -1539,10 +1539,9 @@ proc isCompileTimeOnly*(t: PType): bool {.inline.} = proc containsCompileTimeOnly*(t: PType): bool = if isCompileTimeOnly(t): return true - if t.sons != nil: - for i in 0 ..< t.sonsLen: - if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]): - return true + for i in 0 ..< t.sonsLen: + if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]): + return true return false type diff --git a/compiler/vm.nim b/compiler/vm.nim index a6ec4788b..c49b66b82 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -752,6 +752,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcShlInt: decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal shl regs[rc].intVal + of opcAshrInt: + decodeBC(rkInt) + regs[ra].intVal = ashr(regs[rb].intVal, regs[rc].intVal) of opcBitandInt: decodeBC(rkInt) regs[ra].intVal = regs[rb].intVal and regs[rc].intVal @@ -1422,24 +1425,23 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = ensureKind(rkNode) if c.callsite != nil: regs[ra].node = c.callsite else: stackTrace(c, tos, pc, errFieldXNotFound & "callsite") - of opcNGetFile: - decodeB(rkNode) - let n = regs[rb].node - regs[ra].node = newStrNode(nkStrLit, toFullPath(c.config, n.info)) - regs[ra].node.info = n.info - regs[ra].node.typ = n.typ - of opcNGetLine: - decodeB(rkNode) + of opcNGetLineInfo: + decodeBImm(rkNode) let n = regs[rb].node - regs[ra].node = newIntNode(nkIntLit, n.info.line.int) + case imm + of 0: # getFile + regs[ra].node = newStrNode(nkStrLit, toFullPath(c.config, n.info)) + of 1: # getLine + regs[ra].node = newIntNode(nkIntLit, n.info.line.int) + of 2: # getColumn + regs[ra].node = newIntNode(nkIntLit, n.info.col) + else: + internalAssert c.config, false regs[ra].node.info = n.info regs[ra].node.typ = n.typ - of opcNGetColumn: + of opcNSetLineInfo: decodeB(rkNode) - let n = regs[rb].node - regs[ra].node = newIntNode(nkIntLit, n.info.col) - regs[ra].node.info = n.info - regs[ra].node.typ = n.typ + regs[ra].node.info = regs[rb].node.info of opcEqIdent: decodeBC(rkInt) # aliases for shorter and easier to understand code below diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 866b79568..1abd9ae4a 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -17,7 +17,7 @@ const byteExcess* = 128 # we use excess-K for immediates wordExcess* = 32768 - MaxLoopIterations* = 1_000_000_000 # max iterations of all loops + MaxLoopIterations* = 3_000_000 # max iterations of all loops type @@ -57,7 +57,8 @@ type opcLenStr, opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt, - opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, opcShrInt, opcShlInt, + opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, + opcShrInt, opcShlInt, opcAshrInt, opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu, opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat, opcLeFloat, opcLtFloat, opcLeu, opcLtu, @@ -102,7 +103,7 @@ type opcNError, opcNWarning, opcNHint, - opcNGetLine, opcNGetColumn, opcNGetFile, + opcNGetLineInfo, opcNSetLineInfo, opcEqIdent, opcStrToIdent, opcGetImpl, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 3b5ea4beb..a36f559ca 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -939,6 +939,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.freeTemp(tmp2) of mShlI: genBinaryABCnarrowU(c, n, dest, opcShlInt) + of mAshrI: genBinaryABCnarrow(c, n, dest, opcAshrInt) of mBitandI: genBinaryABCnarrowU(c, n, dest, opcBitandInt) of mBitorI: genBinaryABCnarrowU(c, n, dest, opcBitorInt) of mBitxorI: genBinaryABCnarrowU(c, n, dest, opcBitxorInt) @@ -1181,14 +1182,14 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of mSameNodeType: genBinaryABC(c, n, dest, opcSameNodeType) of mNLineInfo: case n[0].sym.name.s - of "getFile": - genUnaryABC(c, n, dest, opcNGetFile) - of "getLine": - genUnaryABC(c, n, dest, opcNGetLine) - of "getColumn": - genUnaryABC(c, n, dest, opcNGetColumn) - else: - internalAssert c.config, false + of "getFile": genUnaryABI(c, n, dest, opcNGetLineInfo, 0) + of "getLine": genUnaryABI(c, n, dest, opcNGetLineInfo, 1) + of "getColumn": genUnaryABI(c, n, dest, opcNGetLineInfo, 2) + of "copyLineInfo": + internalAssert c.config, n.len == 3 + unused(c, n, dest) + genBinaryStmt(c, n, opcNSetLineInfo) + else: internalAssert c.config, false of mNHint: unused(c, n, dest) genUnaryStmt(c, n, opcNHint) |