From 20591845df1e2b44ed365dd3aa62199371f0d273 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 18 Jul 2018 13:51:31 -0700 Subject: [PATCH 001/103] ospaths.expandTilde: handle ~ correctly; refactor to use DirSep, AltSep --- lib/pure/ospaths.nim | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index 4ae5afd6c..bc523e551 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -548,23 +548,21 @@ proc getTempDir*(): string {.rtl, extern: "nos$1", proc expandTilde*(path: string): string {. tags: [ReadEnvEffect, ReadIOEffect].} = - ## Expands a path starting with ``~/`` to a full path. + ## Expands ``~`` or a path starting with ``~/`` to a full path, replacing + ## ``~`` with ``getHomeDir()`` (otherwise returns ``path`` unmodified). ## - ## If `path` starts with the tilde character and is followed by `/` or `\\` - ## this proc will return the reminder of the path appended to the result of - ## the getHomeDir() proc, otherwise the input path will be returned without - ## modification. - ## - ## The behaviour of this proc is the same on the Windows platform despite - ## not having this convention. Example: - ## - ## .. code-block:: nim - ## let configFile = expandTilde("~" / "appname.cfg") - ## echo configFile - ## # --> C:\Users\amber\appname.cfg - if len(path) > 1 and path[0] == '~' and (path[1] == '/' or path[1] == '\\'): + ## Windows: this is still supported despite Windows platform not having this + ## convention; also, both ``~/`` and ``~\`` are handled. + runnableExamples: + doAssert expandTilde("~" / "appname.cfg") == getHomeDir() / "appname.cfg" + if len(path) == 0 or path[0] != '~': + result = path + elif len(path) == 1: + result = getHomeDir() + elif (path[1] in {DirSep, AltSep}): result = getHomeDir() / path.substr(2) else: + # TODO: handle `~bob` and `~bob/` which means home of bob result = path proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} = From cc1fd50b2785cdb6ec14f283bc7d7ef87f64dd9e Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Sun, 5 Aug 2018 02:53:10 -0500 Subject: [PATCH 002/103] Try to let memTracker compile (#8502) --- lib/system/alloc.nim | 10 +++++----- lib/system/memtracker.nim | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index ffb7aaf86..b090117a9 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -454,10 +454,10 @@ proc requestOsChunks(a: var MemRegion, size: int): PBigChunk = a.addHeapLink(result, size) when defined(debugHeapLinks): cprintf("owner: %p; result: %p; next pointer %p; size: %ld\n", addr(a), - result, result.heapLink, result.origSize) + result, result.heapLink, result.size) when defined(memtracker): - trackLocation(addr result.origSize, sizeof(int)) + trackLocation(addr result.size, sizeof(int)) sysAssert((cast[ByteAddress](result) and PageMask) == 0, "requestOsChunks 1") #zeroMem(result, size) @@ -527,7 +527,7 @@ proc updatePrevSize(a: var MemRegion, c: PBigChunk, proc splitChunk2(a: var MemRegion, c: PBigChunk, size: int): PBigChunk = result = cast[PBigChunk](cast[ByteAddress](c) +% size) result.size = c.size - size - track("result.origSize", addr result.origSize, sizeof(int)) + track("result.size", addr result.size, sizeof(int)) # XXX check if these two nil assignments are dead code given # addChunkToMatrix's implementation: result.next = nil @@ -602,7 +602,7 @@ proc getBigChunk(a: var MemRegion, size: int): PBigChunk = splitChunk(a, result, size) # set 'used' to to true: result.prevSize = 1 - track("setUsedToFalse", addr result.origSize, sizeof(int)) + track("setUsedToFalse", addr result.size, sizeof(int)) incl(a, a.chunkStarts, pageIndex(result)) dec(a.freeMem, size) @@ -968,7 +968,7 @@ proc deallocOsPages(a: var MemRegion) = let (p, size) = it.chunks[i] when defined(debugHeapLinks): cprintf("owner %p; dealloc A: %p size: %ld; next: %p\n", addr(a), - it, it.origSize, next) + it, it.size, next) sysAssert size >= PageSize, "origSize too small" osDeallocPages(p, size) it = next diff --git a/lib/system/memtracker.nim b/lib/system/memtracker.nim index ae0297438..1b1f18039 100644 --- a/lib/system/memtracker.nim +++ b/lib/system/memtracker.nim @@ -73,12 +73,12 @@ proc addEntry(entry: LogEntry) = let x = cast[proc() {.nimcall, tags: [], gcsafe, locks: 0.}](writeStackTrace) x() quit 1 - if gLog.count > high(gLog.data): - gLogger(gLog) - gLog.count = 0 - gLog.data[gLog.count] = entry - inc gLog.count - gLog.disabled = false + #if gLog.count > high(gLog.data): + # gLogger(gLog) + # gLog.count = 0 + #gLog.data[gLog.count] = entry + #inc gLog.count + #gLog.disabled = false proc memTrackerWrite(address: pointer; size: int; file: cstring; line: int) {.compilerProc.} = addEntry LogEntry(op: "write", address: address, From c57e320c9486248a82c19d13e03178745d8eb53f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 5 Aug 2018 11:42:38 +0200 Subject: [PATCH 003/103] fixes 7833 (#8533) * fixes #7833; still to-do: fix setLen * make tests green again * also fixes setLen and string concats; refs #7833 * change formating to avoid a compiler warning * emit the write barrier also for addChar * fixes yet another regression * make setLengthStr compile for the old version * make growobjcrash complete earlier --- compiler/ccgexprs.nim | 52 ++++++++++++++++-------- compiler/condsyms.nim | 1 + compiler/docgen.nim | 2 +- lib/system/gc.nim | 5 ++- lib/system/sysstr.nim | 79 ++++++++++++++++++++++++++++++++----- tests/closure/tclosure3.nim | 2 +- tests/gc/growobjcrash.nim | 2 +- 7 files changed, 114 insertions(+), 29 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 2e9fb2cc2..3bcf2c29b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1063,7 +1063,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = # appendChar(s, 'z'); # } var - a, dest: TLoc + a, dest, call: TLoc appends, lens: Rope assert(d.k == locNone) var L = 0 @@ -1082,8 +1082,9 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)]) add(appends, ropecg(p.module, "#appendString($1, $2);$n", rdLoc(dest), rdLoc(a))) - linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", - rdLoc(dest), lens, rope(L)) + initLoc(call, locCall, e, OnHeap) + call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)]) + genAssignment(p, dest, call, {}) add(p.s(cpsStmts), appends) gcUsage(p.config, e) @@ -1092,17 +1093,20 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq->data[seq->len-1] = x; let seqAppendPattern = if not p.module.compileToCpp: - "$1 = ($2) #incrSeqV3(&($1)->Sup, $3);$n" + "($2) #incrSeqV3(&($1)->Sup, $3)" else: - "$1 = ($2) #incrSeqV3($1, $3);$n" - var a, b, dest, tmpL: TLoc + "($2) #incrSeqV3($1, $3)" + var a, b, dest, tmpL, call: TLoc initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) let seqType = skipTypes(e.sons[1].typ, {tyVar}) - lineCg(p, cpsStmts, seqAppendPattern, [ - rdLoc(a), - getTypeDesc(p.module, e.sons[1].typ), - genTypeInfo(p.module, seqType, e.info)]) + initLoc(call, locCall, e, OnHeap) + call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), + getTypeDesc(p.module, e.sons[1].typ), + genTypeInfo(p.module, seqType, e.info)]) + # emit the write barrier if required, but we can always move here, so + # use 'genRefAssign' for the seq. + genRefAssign(p, a, call, {}) #if bt != b.t: # echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t) initLoc(dest, locExpr, e.sons[2], OnHeap) @@ -1509,7 +1513,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: internalError(p.config, e.info, "genArrayLen()") proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = - var a, b: TLoc + var a, b, call: TLoc assert(d.k == locNone) var x = e.sons[1] if x.kind in {nkAddr, nkHiddenAddr}: x = x[0] @@ -1517,17 +1521,27 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[2], b) let t = skipTypes(e.sons[1].typ, {tyVar}) let setLenPattern = if not p.module.compileToCpp: - "$1 = ($3) #setLengthSeqV2(&($1)->Sup, $4, $2);$n" + "($3) #setLengthSeqV2(&($1)->Sup, $4, $2)" else: - "$1 = ($3) #setLengthSeqV2($1, $4, $2);$n" + "($3) #setLengthSeqV2($1, $4, $2)" - lineCg(p, cpsStmts, setLenPattern, [ + initLoc(call, locCall, e, OnHeap) + call.r = ropecg(p.module, setLenPattern, [ rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)]) + genAssignment(p, a, call, {}) gcUsage(p.config, e) proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = - binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n") + var a, b, call: TLoc + if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr") + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + + initLoc(call, locCall, e, OnHeap) + call.r = ropecg(p.module, "#setLengthStr($1, $2)", [ + rdLoc(a), rdLoc(b)]) + genAssignment(p, a, call, {}) gcUsage(p.config, e) proc genSwap(p: BProc, e: PNode, d: var TLoc) = @@ -1844,7 +1858,13 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = getTypeDesc(p.module, ranged), res]) of mConStrStr: genStrConcat(p, e, d) - of mAppendStrCh: binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n") + of mAppendStrCh: + var dest, b, call: TLoc + initLoc(call, locCall, e, OnHeap) + initLocExpr(p, e.sons[1], dest) + initLocExpr(p, e.sons[2], b) + call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)]) + genAssignment(p, dest, call, {}) of mAppendStrStr: genStrAppend(p, e, d) of mAppendSeqElem: genSeqElemAppend(p, e, d) of mEqStr: genStrEquals(p, e, d) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 8b2d36722..9dfe69442 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -72,3 +72,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimNoZeroTerminator") defineSymbol("nimNotNil") defineSymbol("nimVmExportFixed") + defineSymbol("nimIncrSeqV3") diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 63883af5c..8d233566c 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -259,7 +259,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe of tkSpaces, tkInvalid: add(result, literal) of tkCurlyDotLe: - dispA(d.conf, result, "" & # This span is required for the JS to work properly + dispA(d.conf, result, "" & # This span is required for the JS to work properly """{...} diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 425963f3f..74ac68eea 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -548,7 +548,10 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = gcTrace(res, csAllocated) track("growObj old", ol, 0) track("growObj new", res, newsize) - when reallyDealloc: + when defined(nimIncrSeqV3): + # since we steal the old seq's contents, we set the old length to 0. + cast[PGenericSeq](old).len = 0 + elif reallyDealloc: sysAssert(allocInv(gch.region), "growObj before dealloc") if ol.refcount shr rcShift <=% 1: # free immediately to save space: diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 8e9e18b05..19c2c62ad 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -184,8 +184,13 @@ proc addChar(s: NimString, c: char): NimString = result = s if result.len >= result.space: let r = resize(result.space) - result = cast[NimString](growObj(result, - sizeof(TGenericSeq) + r + 1)) + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(r) + result.len = s.len + copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1) + else: + result = cast[NimString](growObj(result, + sizeof(TGenericSeq) + r + 1)) result.reserved = r result.data[result.len] = c result.data[result.len+1] = '\0' @@ -228,8 +233,13 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} = elif dest.len + addlen <= dest.space: result = dest else: # slow path: - var sp = max(resize(dest.space), dest.len + addlen) - result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1)) + let sp = max(resize(dest.space), dest.len + addlen) + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(sp) + result.len = dest.len + copyMem(addr result.data[0], unsafeAddr(dest.data[0]), dest.len+1) + else: + result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1)) result.reserved = sp #result = rawNewString(sp) #copyMem(result, dest, dest.len + sizeof(TGenericSeq)) @@ -246,13 +256,21 @@ proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} = inc(dest.len) proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} = - var n = max(newLen, 0) + let n = max(newLen, 0) if s == nil: result = mnewString(newLen) elif n <= s.space: result = s else: - result = resizeString(s, n) + let sp = max(resize(s.space), newLen) + when defined(nimIncrSeqV3): + result = rawNewStringNoInit(sp) + result.len = s.len + copyMem(addr result.data[0], unsafeAddr(s.data[0]), s.len+1) + zeroMem(addr result.data[s.len], newLen - s.len) + result.reserved = sp + else: + result = resizeString(s, n) result.len = n result.data[n] = '\0' @@ -282,6 +300,9 @@ proc incrSeqV2(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} = GenericSeqSize)) result.reserved = r +template `+!`(p: pointer, s: int): pointer = + cast[pointer](cast[int](p) +% s) + proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} = if s == nil: result = cast[PGenericSeq](newSeq(typ, 1)) @@ -290,9 +311,16 @@ proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} = result = s if result.len >= result.space: let r = resize(result.space) - result = cast[PGenericSeq](growObj(result, typ.base.size * r + + when defined(nimIncrSeqV3): + result = cast[PGenericSeq](newSeq(typ, r)) + result.len = s.len + copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * typ.base.size) + # since we steal the content from 's', it's crucial to set s's len to 0. + s.len = 0 + else: + result = cast[PGenericSeq](growObj(result, typ.base.size * r + GenericSeqSize)) - result.reserved = r + result.reserved = r proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. compilerRtl, inl.} = @@ -336,10 +364,43 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. compilerRtl.} = + sysAssert typ.kind == tySequence, "setLengthSeqV2: type is not a seq" if s == nil: result = cast[PGenericSeq](newSeq(typ, newLen)) else: - result = setLengthSeq(s, typ.base.size, newLen) + when defined(nimIncrSeqV3): + let elemSize = typ.base.size + if s.space < newLen: + let r = max(resize(s.space), newLen) + result = cast[PGenericSeq](newSeq(typ, r)) + copyMem(result +! GenericSeqSize, s +! GenericSeqSize, s.len * elemSize) + # since we steal the content from 's', it's crucial to set s's len to 0. + s.len = 0 + elif newLen < s.len: + result = s + # we need to decref here, otherwise the GC leaks! + when not defined(boehmGC) and not defined(nogc) and + not defined(gcMarkAndSweep) and not defined(gogc) and + not defined(gcRegions): + if ntfNoRefs notin typ.base.flags: + for i in newLen..result.len-1: + forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% + GenericSeqSize +% (i*%elemSize)), + extGetCellType(result).base, waZctDecRef) + + # XXX: zeroing out the memory can still result in crashes if a wiped-out + # cell is aliased by another pointer (ie proc parameter or a let variable). + # This is a tough problem, because even if we don't zeroMem here, in the + # presence of user defined destructors, the user will expect the cell to be + # "destroyed" thus creating the same problem. We can destoy the cell in the + # finalizer of the sequence, but this makes destruction non-deterministic. + zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +% + (newLen*%elemSize)), (result.len-%newLen) *% elemSize) + else: + result = s + result.len = newLen + else: + result = setLengthSeq(s, typ.base.size, newLen) # --------------- other string routines ---------------------------------- proc add*(result: var string; x: int64) = diff --git a/tests/closure/tclosure3.nim b/tests/closure/tclosure3.nim index d5ffb5ab2..4de07bdb5 100644 --- a/tests/closure/tclosure3.nim +++ b/tests/closure/tclosure3.nim @@ -15,7 +15,7 @@ proc main = let val = s[i]() if val != $(i*i): echo "bug ", val - if getOccupiedMem() > 3000_000: quit("still a leak!") + if getOccupiedMem() > 5000_000: quit("still a leak!") echo "success" main() diff --git a/tests/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim index a16468c7e..07f92b8f4 100644 --- a/tests/gc/growobjcrash.nim +++ b/tests/gc/growobjcrash.nim @@ -14,7 +14,7 @@ proc handleRequest(query: string): StringTableRef = let x = foo result = x() -const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 700_000 +const Limit = 5*1024*1024 proc main = var counter = 0 From baa77387d7b9ecda84a58af2fed515cb32cb2a5b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Sun, 5 Aug 2018 03:15:40 -0700 Subject: [PATCH 004/103] fixes #8215; remove reference to old doc command which was deprecated (#8418) --- doc/docgen.rst | 21 +++------------------ tools/nimweb.nim | 10 +++------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/doc/docgen.rst b/doc/docgen.rst index d196b3a18..fa23bdc79 100644 --- a/doc/docgen.rst +++ b/doc/docgen.rst @@ -97,24 +97,9 @@ Partial Output:: proc helloWorld(times: int) {.raises: [], tags: [].} ... -The full output can be seen here: `docgen_sample2.html `_. - -The older version of the ``doc`` command, now renamed ``doc0`` runs before -semantic checking which means it lacks some of the things ``doc`` will output. - -The ``doc0`` command:: - nim doc0 sample - -Partial Output:: - ... - proc helloWorld*(times: int) - ... - -Output can be viewed in full here: `docgen_sample.html `_. -As you can see, the tool has extracted less information than what the ``doc`` -command provides, such as pragmas attached implicitly by the compiler. This type -of information is not available from looking at the AST (Abstract Syntax Tree) -prior to semantic checking, which is why ``doc0`` doesn't show it. +The full output can be seen here: `docgen_sample.html `_. +It runs after semantic checking, and includes pragmas attached implicitly by the +compiler. JSON diff --git a/tools/nimweb.nim b/tools/nimweb.nim index e74b081ea..61cae5170 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -303,14 +303,10 @@ proc mexec(cmds: openarray[string], processors: int) = proc buildDocSamples(c: var TConfigData, destPath: string) = ## Special case documentation sample proc. ## - ## The docgen sample needs to be generated twice with different commands, so - ## it didn't make much sense to integrate into the existing generic - ## documentation builders. - const src = "doc"/"docgen_sample.nim" + ## TODO: consider integrating into the existing generic documentation builders + ## now that we have a single `doc` command. exec(findNim(c) & " doc $# -o:$# $#" % - [c.nimArgs, destPath / "docgen_sample.html", src]) - exec(findNim(c) & " doc2 $# -o:$# $#" % - [c.nimArgs, destPath / "docgen_sample2.html", src]) + [c.nimArgs, destPath / "docgen_sample.html", "doc" / "docgen_sample.nim"]) proc pathPart(d: string): string = splitFile(d).dir.replace('\\', '/') From 6e3d1dced55229309a85849a45c877a798080453 Mon Sep 17 00:00:00 2001 From: andri lim Date: Mon, 6 Aug 2018 04:38:21 +0700 Subject: [PATCH 005/103] fixes #5617, 'copyLineInfo' addition (#8523) --- changelog.md | 1 + compiler/vm.nim | 27 +++++++++++++-------------- compiler/vmdef.nim | 2 +- compiler/vmgen.nim | 16 ++++++++-------- lib/core/macros.nim | 3 +++ tests/macros/tlineinfo.nim | 14 ++++++++++++++ 6 files changed, 40 insertions(+), 23 deletions(-) create mode 100644 tests/macros/tlineinfo.nim diff --git a/changelog.md b/changelog.md index 045286ef9..4c19abfc0 100644 --- a/changelog.md +++ b/changelog.md @@ -91,6 +91,7 @@ - ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt`` - Added the proc ``flush`` for memory mapped files. - Added the ``MemMapFileStream``. +- Added ``macros.copyLineInfo`` to copy lineInfo from other node ### Library changes diff --git a/compiler/vm.nim b/compiler/vm.nim index a6ec4788b..d4b041dea 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1422,24 +1422,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) + of opcNGetLineInfo: + decodeBImm(rkNode) let n = regs[rb].node - regs[ra].node = newStrNode(nkStrLit, toFullPath(c.config, n.info)) + 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 opcNGetLine: + of opcNSetLineInfo: decodeB(rkNode) - let n = regs[rb].node - regs[ra].node = newIntNode(nkIntLit, n.info.line.int) - regs[ra].node.info = n.info - regs[ra].node.typ = n.typ - of opcNGetColumn: - 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..a4489513a 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -102,7 +102,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..965c75485 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1181,14 +1181,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) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index d4e8ada0a..90fea440e 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -432,6 +432,9 @@ proc getLine(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.} proc getColumn(arg: NimNode): int {.magic: "NLineInfo", noSideEffect.} proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.} +proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.} + ## copy lineinfo from info node + proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} = ## returns ``LineInfo`` of ``n``, using absolute path for ``filename`` result.filename = n.getFile diff --git a/tests/macros/tlineinfo.nim b/tests/macros/tlineinfo.nim new file mode 100644 index 000000000..2ab0e1ee8 --- /dev/null +++ b/tests/macros/tlineinfo.nim @@ -0,0 +1,14 @@ +# issue #5617, feature request +# Ability to set a NimNode's lineinfo +import macros + +type + Test = object + +macro mixer(n: typed): untyped = + let x = newIdentNode("echo") + x.copyLineInfo(n) + result = newLit(x.lineInfo == n.lineInfo) + +var z = mixer(Test) +doAssert z From 8ad59e6857305264a0e415ce995e02b0ab32f770 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 6 Aug 2018 02:50:42 -0700 Subject: [PATCH 006/103] remove redundant test for nil before `add` (#8460) --- lib/pure/unittest.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index d804ba7c8..aa07a4fa6 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -525,8 +525,6 @@ proc checkpoint*(msg: string) = ## checkpoint("Checkpoint B") ## ## outputs "Checkpoint A" once it fails. - if checkpoints == nil: - checkpoints = @[] checkpoints.add(msg) # TODO: add support for something like SCOPED_TRACE from Google Test From 39b3b940084d6d04293504024dd62005348b86cf Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Aug 2018 14:21:29 +0200 Subject: [PATCH 007/103] OSX: make tioslectors test green --- lib/pure/ioselects/ioselectors_kqueue.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/pure/ioselects/ioselectors_kqueue.nim b/lib/pure/ioselects/ioselectors_kqueue.nim index 142e988d0..0e133f650 100644 --- a/lib/pure/ioselects/ioselectors_kqueue.nim +++ b/lib/pure/ioselects/ioselectors_kqueue.nim @@ -567,8 +567,11 @@ proc selectInto*[T](s: Selector[T], timeout: int, doAssert(true, "Unsupported kqueue filter in the queue!") if (kevent.flags and EV_EOF) != 0: + # TODO this error handling needs to be rethought. + # `fflags` can sometimes be `0x80000000` and thus we use 'cast' + # here: if kevent.fflags != 0: - rkey.errorCode = kevent.fflags.OSErrorCode + rkey.errorCode = cast[OSErrorCode](kevent.fflags) else: # This assumes we are dealing with sockets. # TODO: For future-proofing it might be a good idea to give the From 7f8eccb46f43ed689e1724915f4e66ae92bc94eb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Aug 2018 14:38:38 +0200 Subject: [PATCH 008/103] make 'flags' test green on OSX --- tests/testament/categories.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index cde8880b3..75da486dc 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -76,7 +76,7 @@ proc flagTests(r: var TResults, cat: Category, options: string) = testExec r, makeTest(filename, " cmd /c cd " & nimcache & " && compile_tgenscript.bat", cat) - when defined(linux): + elif defined(posix): testExec r, makeTest(filename, " sh -c \"cd " & nimcache & " && sh compile_tgenscript.sh\"", cat) From 559c4b8a200c89a2f530891b4720d16cfae412d6 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 6 Aug 2018 17:42:08 +0200 Subject: [PATCH 009/103] attempt to make the travis OSX build green --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e9b76bf6a..2896b126a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,7 @@ before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install boehmgc; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install sfml; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install node@8; fi before_script: - set -e From 6c319d4f74514f7113dbca2bf07dacc3d932fd67 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Aug 2018 19:16:23 +0200 Subject: [PATCH 010/103] travis/testament: disable JS tests on OSX --- .travis.yml | 1 - tests/testament/categories.nim | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2896b126a..e9b76bf6a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,6 @@ before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install boehmgc; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install sfml; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install node@8; fi before_script: - set -e diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 75da486dc..f7cd0815c 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -482,8 +482,10 @@ proc processCategory(r: var TResults, cat: Category, options: string) = compileRodFiles(r, cat, options) runRodFiles(r, cat, options) of "js": - # XXX JS doesn't need to be special anymore - jsTests(r, cat, options) + # only run the JS tests on Windows or Linux because Travis is bad + # and other OSes like Haiku might lack nodejs: + when defined(linux) or defined(windows): + jsTests(r, cat, options) of "dll": dllTests(r, cat, options) of "flags": From bbc404d80d77365a1c402a0862a3d26958b16e7b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Aug 2018 19:44:15 +0200 Subject: [PATCH 011/103] disable tioselectors test for OSX --- tests/async/tioselectors.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim index d2e4cfec1..a556b6dd2 100644 --- a/tests/async/tioselectors.nim +++ b/tests/async/tioselectors.nim @@ -11,7 +11,9 @@ template processTest(t, x: untyped) = #stdout.flushFile() if not x: echo(t & " FAILED\r\n") -when not defined(windows): +when defined(macosx): + echo "All tests passed!" +elif not defined(windows): import os, posix, nativesockets, times when ioselSupportedPlatform: From e9d67266eff64d6ffecedda49421bfda0edd1a0e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Aug 2018 19:58:48 +0200 Subject: [PATCH 012/103] introduce the --define 'osx' as an alias for 'macosx' --- compiler/options.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/options.nim b/compiler/options.nim index 598adf27d..7d7327d28 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -354,6 +354,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 From e555e97b4b9a561e14b1c5441e85db9167d03a87 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Aug 2018 20:00:26 +0200 Subject: [PATCH 013/103] use slashes instead of dots for paths --- compiler/lookups.nim | 2 +- compiler/sem.nim | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 87694988a..bab631e6f 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) diff --git a/compiler/sem.nim b/compiler/sem.nim index 2c3fab5a5..68a0a7094 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 From e067a7681fd8db93e51fa65569829b8c485c6bfe Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Aug 2018 23:38:29 +0200 Subject: [PATCH 014/103] 'nimcache' defaults to ~/.cache on Posix; cleaned up documentation --- changelog.md | 13 ++++++++----- compiler/options.nim | 14 ++++++++++++-- doc/backends.txt | 13 ++++++------- doc/nimc.rst | 35 ++++++++++++----------------------- 4 files changed, 38 insertions(+), 37 deletions(-) diff --git a/changelog.md b/changelog.md index 4c19abfc0..56830628a 100644 --- a/changelog.md +++ b/changelog.md @@ -20,7 +20,7 @@ - The parser now warns about inconsistent spacing around binary operators as these can easily be confused with unary operators. This warning will likely become an error in the future. -- The ``'c`` and ``'C'`` prefix for octal literals is now deprecated to +- The ``'c`` and ``'C'`` suffix for octal literals is now deprecated to bring the language in line with the standard library (e.g. ``parseOct``). - The dot style for import paths (e.g ``import path.to.module`` instead of ``import path/to/module``) has been deprecated. @@ -67,6 +67,9 @@ - The undocumented ``#? braces`` parsing mode was removed. - The undocumented PHP backend was removed. +- The default location of ``nimcache`` for the native code targets was + changed. Read [the compiler user guide](https://nim-lang.org/docs/nimc.html#generated-c-code-directory) + for more information. ### Library additions @@ -91,7 +94,7 @@ - ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt`` - Added the proc ``flush`` for memory mapped files. - Added the ``MemMapFileStream``. -- Added ``macros.copyLineInfo`` to copy lineInfo from other node +- Added ``macros.copyLineInfo`` to copy lineInfo from other node. ### Library changes @@ -161,11 +164,11 @@ - The command syntax now supports keyword arguments after the first comma. - Thread-local variables can now be declared inside procs. This implies all - the effects of the `global` pragma. + the effects of the ``global`` pragma. -- Nim now supports `except` clause in the export statement. +- Nim now supports ``except`` clause in the export statement. -- Range float types, example `range[0.0 .. Inf]`. More details in language manual. +- Range float types, example ``range[0.0 .. Inf]``. More details in language manual. ### Tool changes diff --git a/compiler/options.nim b/compiler/options.nim index 7d7327d28..4931b4330 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -480,9 +480,19 @@ proc disableNimblePath*(conf: ConfigRef) = include packagehandling +proc getOsCacheDir(): string = + when defined(posix): + result = getHomeDir() / ".cache" + else: + result = getHomeDir() / genSubDir + proc getNimcacheDir*(conf: ConfigRef): string = - result = if conf.nimcacheDir.len > 0: conf.nimcacheDir - else: shortenDir(conf, conf.projectPath) / genSubDir + result = if conf.nimcacheDir.len > 0: + conf.nimcacheDir + elif conf.cmd == cmdCompileToJS: + shortenDir(conf, conf.projectPath) / genSubDir + else: getOsCacheDir() / conf.projectName & + (if isDefined(conf, "release"): "_r" else: "_d") proc pathSubs*(conf: ConfigRef; p, config: string): string = let home = removeTrailingDirSep(os.getHomeDir()) diff --git a/doc/backends.txt b/doc/backends.txt index b7f5308ab..13ef7bf4d 100644 --- a/doc/backends.txt +++ b/doc/backends.txt @@ -65,7 +65,6 @@ The JavaScript target --------------------- Nim can also generate `JavaScript`:idx: code through the ``js`` command. -However, the JavaScript code generator is experimental! Nim targets JavaScript 1.5 which is supported by any widely used browser. Since JavaScript does not have a portable means to include another module, @@ -77,7 +76,7 @@ available. This includes: * manual memory management (``alloc``, etc.) * casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.) * file management -* most modules of the Standard library +* most modules of the standard library * proper 64 bit integer arithmetic * unsigned integer arithmetic @@ -87,9 +86,8 @@ However, the modules `strutils `_, `math `_, and To compile a Nim module into a ``.js`` file use the ``js`` command; the default is a ``.js`` file that is supposed to be referenced in an ``.html`` -file. However, you can also run the code with `nodejs`:idx:, a `software -platform for easily building fast, scalable network applications -`_:: +file. However, you can also run the code with `nodejs`:idx: +(``_):: nim js -d:nodejs -r examples/hallo.nim @@ -330,8 +328,9 @@ Nimcache naming logic The `nimcache`:idx: directory is generated during compilation and will hold either temporary or final files depending on your backend target. The default -name for the directory is ``nimcache`` but you can use the ``--nimcache`` -`compiler switch `_ to change it. +name for the directory depends on the used backend and on your OS but you can +use the ``--nimcache`` `compiler switch `_ to +change it. Nimcache and C like targets ~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/nimc.rst b/doc/nimc.rst index 0939f67e8..277c88ec1 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -157,38 +157,27 @@ the first matching file is used. Generated C code directory -------------------------- The generated files that Nim produces all go into a subdirectory called -``nimcache`` in your project directory. This makes it easy to delete all +``nimcache``. Its full path is + +- ``~/.cache/$projectname(_r|_d)`` on Posix +- ``$HOME/nimcache/$projectname(_r|_d)`` on Windows. + +The ``_r`` suffix is used for release builds, ``_d`` is for debug builds. + +This makes it easy to delete all generated files. Files generated in this directory follow a naming logic which you can read about in the `Nim Backend Integration document `_. +The ``--nimcache`` +`compiler switch `_ can be used to +to change the ``nimcache`` directory. + However, the generated C code is not platform independent. C code generated for Linux does not compile on Windows, for instance. The comment on top of the C file lists the OS, CPU and CC the file has been compiled for. -Compilation cache -================= - -**Warning**: The compilation cache is still highly experimental! - -The ``nimcache`` directory may also contain so called `rod`:idx: -or `symbol files`:idx:. These files are pre-compiled modules that are used by -the compiler to perform `incremental compilation`:idx:. This means that only -modules that have changed since the last compilation (or the modules depending -on them etc.) are re-compiled. However, per default no symbol files are -generated; use the ``--symbolFiles:on`` command line switch to activate them. - -Unfortunately due to technical reasons the ``--symbolFiles:on`` needs -to *aggregate* some generated C code. This means that the resulting executable -might contain some cruft even with dead code elimination. So -the final release build should be done with ``--symbolFiles:off``. - -Due to the aggregation of C code it is also recommended that each project -resides in its own directory so that the generated ``nimcache`` directory -is not shared between different projects. - - Compiler Selection ================== From be4816f5097ce72e124e5e087ffa4d386fa17d4d Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 7 Aug 2018 08:48:52 +0200 Subject: [PATCH 015/103] Iterator over heap instances (#8548) Provide "dumpHeapInstances" for iterating over type statistics of heaps. This can be used to present structured heap information as an alternative to "dumpNumberOfInstances". --- lib/system/gc_common.nim | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index dcea0c4cc..88e150cd1 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -37,22 +37,28 @@ when defined(nimTypeNames): a[j] = v if h == 1: break - proc dumpNumberOfInstances* = - # also add the allocated strings to the list of known types: + iterator dumpHeapInstances*(): tuple[name: cstring; count: int; sizes: int] = + ## Iterate over summaries of types on heaps. + ## This data may be inaccurate if allocations + ## are made by the iterator body. if strDesc.nextType == nil: strDesc.nextType = nimTypeRoot strDesc.name = "string" nimTypeRoot = addr strDesc + var it = nimTypeRoot + while it != nil: + if (it.instances > 0 or it.sizes != 0): + yield (it.name, it.instances, it.sizes) + it = it.nextType + + proc dumpNumberOfInstances* = var a: InstancesInfo var n = 0 - var it = nimTypeRoot var totalAllocated = 0 - while it != nil: - if (it.instances > 0 or it.sizes != 0) and n < a.len: - a[n] = (it.name, it.instances, it.sizes) - inc n + for it in dumpHeapInstances(): + a[n] = it + inc n inc totalAllocated, it.sizes - it = it.nextType sortInstances(a, n) for i in 0 .. n-1: c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", a[i][0], a[i][1], a[i][2]) From c3d5ec8eadf3aa887f34231c2d7b5818923818d4 Mon Sep 17 00:00:00 2001 From: andri lim Date: Tue, 7 Aug 2018 14:07:18 +0700 Subject: [PATCH 016/103] fixes #8421, fixes #7968, Nim compiler compiles with MSVC C89 version (#8556) --- compiler/rodutils.nim | 21 +++++++++++ lib/pure/math.nim | 80 +++++++++++++++++++++++++++++------------ lib/windows/winlean.nim | 2 +- 3 files changed, 79 insertions(+), 24 deletions(-) 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 + 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: "", nodecl, varargs.} proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = diff --git a/lib/pure/math.nim b/lib/pure/math.nim index b921b1841..eb09bf4a7 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -162,9 +162,6 @@ when not defined(JS): # C proc log10*(x: float32): float32 {.importc: "log10f", header: "".} proc log10*(x: float64): float64 {.importc: "log10", header: "".} ## Computes the common logarithm (base 10) of `x` - proc log2*(x: float32): float32 {.importc: "log2f", header: "".} - proc log2*(x: float64): float64 {.importc: "log2", header: "".} - ## Computes the binary logarithm (base 2) of `x` proc exp*(x: float32): float32 {.importc: "expf", header: "".} proc exp*(x: float64): float64 {.importc: "exp", header: "".} ## Computes the exponential function of `x` (pow(E, x)) @@ -268,6 +265,8 @@ proc arcsech*[T: float32|float64](x: T): T = arccosh(1.0 / x) proc arccsch*[T: float32|float64](x: T): T = arcsinh(1.0 / x) ## Computes the inverse hyperbolic cosecant of `x` +const windowsCC89 = defined(windows) and (defined(vcc) or defined(bcc)) + when not defined(JS): # C proc hypot*(x, y: float32): float32 {.importc: "hypotf", header: "".} proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "".} @@ -280,25 +279,27 @@ when not defined(JS): # C ## ## To compute power between integers, use `^` e.g. 2 ^ 6 - proc erf*(x: float32): float32 {.importc: "erff", header: "".} - proc erf*(x: float64): float64 {.importc: "erf", header: "".} - ## The error function - proc erfc*(x: float32): float32 {.importc: "erfcf", header: "".} - proc erfc*(x: float64): float64 {.importc: "erfc", header: "".} - ## The complementary error function + # TODO: add C89 version on windows + when not windowsCC89: + proc erf*(x: float32): float32 {.importc: "erff", header: "".} + proc erf*(x: float64): float64 {.importc: "erf", header: "".} + ## The error function + proc erfc*(x: float32): float32 {.importc: "erfcf", header: "".} + proc erfc*(x: float64): float64 {.importc: "erfc", header: "".} + ## The complementary error function - proc gamma*(x: float32): float32 {.importc: "tgammaf", header: "".} - proc gamma*(x: float64): float64 {.importc: "tgamma", header: "".} - ## The gamma function - proc tgamma*(x: float32): float32 - {.deprecated: "use gamma instead", importc: "tgammaf", header: "".} - proc tgamma*(x: float64): float64 - {.deprecated: "use gamma instead", importc: "tgamma", header: "".} - ## The gamma function - ## **Deprecated since version 0.19.0**: Use ``gamma`` instead. - proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "".} - proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} - ## Natural log of the gamma function + proc gamma*(x: float32): float32 {.importc: "tgammaf", header: "".} + proc gamma*(x: float64): float64 {.importc: "tgamma", header: "".} + ## The gamma function + proc tgamma*(x: float32): float32 + {.deprecated: "use gamma instead", importc: "tgammaf", header: "".} + proc tgamma*(x: float64): float64 + {.deprecated: "use gamma instead", importc: "tgamma", header: "".} + ## The gamma function + ## **Deprecated since version 0.19.0**: Use ``gamma`` instead. + proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "".} + proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} + ## Natural log of the gamma function proc floor*(x: float32): float32 {.importc: "floorf", header: "".} proc floor*(x: float64): float64 {.importc: "floor", header: "".} @@ -314,7 +315,7 @@ when not defined(JS): # C ## .. code-block:: nim ## echo ceil(-2.1) ## -2.0 - when defined(windows) and (defined(vcc) or defined(bcc)): + when windowsCC89: # MSVC 2010 don't have trunc/truncf # this implementation was inspired by Go-lang Math.Trunc proc truncImpl(f: float64): float64 = @@ -452,6 +453,28 @@ when not defined(JS): var exp: int32 result = c_frexp(x, exp) exponent = exp + + when windowsCC89: + # taken from Go-lang Math.Log2 + const ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 + template log2Impl[T](x: T): T = + var exp: int32 + var frac = frexp(x, exp) + # Make sure exact powers of two give an exact answer. + # Don't depend on Log(0.5)*(1/Ln2)+exp being exactly exp-1. + if frac == 0.5: return T(exp - 1) + log10(frac)*(1/ln2) + T(exp) + + proc log2*(x: float32): float32 = log2Impl(x) + proc log2*(x: float64): float64 = log2Impl(x) + ## Log2 returns the binary logarithm of x. + ## The special cases are the same as for Log. + + else: + proc log2*(x: float32): float32 {.importc: "log2f", header: "".} + proc log2*(x: float64): float64 {.importc: "log2", header: "".} + ## Computes the binary logarithm (base 2) of `x` + else: proc frexp*[T: float32|float64](x: T, exponent: var int): T = if x == 0.0: @@ -564,7 +587,7 @@ proc lcm*[T](x, y: T): T = ## Computes the least common multiple of ``x`` and ``y``. x div gcd(x, y) * y -when isMainModule and not defined(JS): +when isMainModule and not defined(JS) and not windowsCC89: # Check for no side effect annotation proc mySqrt(num: float): float {.noSideEffect.} = return sqrt(num) @@ -692,3 +715,14 @@ when isMainModule: block: # log doAssert log(4.0, 3.0) == ln(4.0) / ln(3.0) + doAssert log2(8.0'f64) == 3.0'f64 + doAssert log2(4.0'f64) == 2.0'f64 + doAssert log2(2.0'f64) == 1.0'f64 + doAssert log2(1.0'f64) == 0.0'f64 + doAssert classify(log2(0.0'f64)) == fcNegInf + + doAssert log2(8.0'f32) == 3.0'f32 + doAssert log2(4.0'f32) == 2.0'f32 + doAssert log2(2.0'f32) == 1.0'f32 + doAssert log2(1.0'f32) == 0.0'f32 + doAssert classify(log2(0.0'f32)) == fcNegInf diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 3263f1d37..60a6e5d9b 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -396,7 +396,7 @@ else: proc moveFileA*(lpExistingFileName, lpNewFileName: cstring): WINBOOL {. importc: "MoveFileA", stdcall, dynlib: "kernel32".} - proc moveFileExA*(lpExistingFileName, lpNewFileName: WideCString, + proc moveFileExA*(lpExistingFileName, lpNewFileName: cstring, flags: DWORD): WINBOOL {. importc: "MoveFileExA", stdcall, dynlib: "kernel32".} From 9b9cfa7306d696961cc6fd590ca72c08f66bdcb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Nihlg=C3=A5rd?= Date: Tue, 7 Aug 2018 09:24:54 +0200 Subject: [PATCH 017/103] Stricter signature for countdown/countup (#8549) --- lib/system.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 0cfa39e19..94baf7370 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1978,7 +1978,7 @@ when sizeof(int) <= 2: else: type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16|enum -iterator countdown*[T](a, b: T, step = 1): T {.inline.} = +iterator countdown*[T](a, b: T, step: Positive = 1): T {.inline.} = ## Counts from ordinal value `a` down to `b` (inclusive) with the given ## step count. `T` may be any ordinal type, `step` may only ## be positive. **Note**: This fails to count to ``low(int)`` if T = int for @@ -2001,7 +2001,7 @@ iterator countdown*[T](a, b: T, step = 1): T {.inline.} = dec(res, step) when defined(nimNewRoof): - iterator countup*[T](a, b: T, step = 1): T {.inline.} = + iterator countup*[T](a, b: T, step: Positive = 1): T {.inline.} = ## Counts from ordinal value `a` up to `b` (inclusive) with the given ## step count. `S`, `T` may be any ordinal type, `step` may only ## be positive. **Note**: This fails to count to ``high(int)`` if T = int for @@ -2018,7 +2018,7 @@ when defined(nimNewRoof): inc(res, step) iterator `..`*[T](a, b: T): T {.inline.} = - ## An alias for `countup`. + ## An alias for `countup(a, b, 1)`. when T is IntLikeForCount: var res = int(a) while res <= int(b): From 4d5cce9882d554ada9cf737d63e40880d88ba170 Mon Sep 17 00:00:00 2001 From: andri lim Date: Tue, 7 Aug 2018 23:41:30 +0700 Subject: [PATCH 018/103] fixes #6255, add `system.ashr` arithmetic right shift (#8547) --- changelog.md | 3 ++- compiler/ast.nim | 2 +- compiler/ccgexprs.nim | 2 +- compiler/condsyms.nim | 1 + compiler/jsgen.nim | 1 + compiler/semfold.nim | 8 +++++++ compiler/sigmatch.nim | 4 ++++ compiler/vm.nim | 3 +++ compiler/vmdef.nim | 3 ++- compiler/vmgen.nim | 1 + lib/system.nim | 17 +++++++++++++++ tests/arithm/tashr.nim | 46 ++++++++++++++++++++++++++++++++++++++++ tests/concepts/t3330.nim | 16 +++++++------- 13 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 tests/arithm/tashr.nim diff --git a/changelog.md b/changelog.md index 4c19abfc0..c1e7bd09c 100644 --- a/changelog.md +++ b/changelog.md @@ -91,7 +91,8 @@ - ``parseOct`` and ``parseBin`` in parseutils now also support the ``maxLen`` argument similar to ``parseHexInt`` - Added the proc ``flush`` for memory mapped files. - Added the ``MemMapFileStream``. -- Added ``macros.copyLineInfo`` to copy lineInfo from other node +- Added ``macros.copyLineInfo`` to copy lineInfo from other node. +- Added ``system.ashr`` an arithmetic right shift for integers. ### Library changes diff --git a/compiler/ast.nim b/compiler/ast.nim index dbf1151a9..ef12e1184 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, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 3bcf2c29b..6803a9478 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -552,9 +552,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 diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 9dfe69442..5a62b46ad 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -73,3 +73,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimNotNil") defineSymbol("nimVmExportFixed") defineSymbol("nimIncrSeqV3") + defineSymbol("nimAshr") diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index ef54841ae..63100a68d 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 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/sigmatch.nim b/compiler/sigmatch.nim index 29f16b808..5afa1b031 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -858,6 +858,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) diff --git a/compiler/vm.nim b/compiler/vm.nim index d4b041dea..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 diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index a4489513a..50235c95f 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -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, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 965c75485..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) diff --git a/lib/system.nim b/lib/system.nim index 94baf7370..53605f9fd 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -971,6 +971,23 @@ else: proc `shl`*(x, y: int32): int32 {.magic: "ShlI", noSideEffect.} proc `shl`*(x, y: int64): int64 {.magic: "ShlI", noSideEffect.} +when defined(nimAshr): + proc ashr*(x: int, y: SomeInteger): int {.magic: "AshrI", noSideEffect.} + proc ashr*(x: int8, y: SomeInteger): int8 {.magic: "AshrI", noSideEffect.} + proc ashr*(x: int16, y: SomeInteger): int16 {.magic: "AshrI", noSideEffect.} + proc ashr*(x: int32, y: SomeInteger): int32 {.magic: "AshrI", noSideEffect.} + proc ashr*(x: int64, y: SomeInteger): int64 {.magic: "AshrI", noSideEffect.} + ## Shifts right by pushing copies of the leftmost bit in from the left, + ## and let the rightmost bits fall off. + ## + ## .. code-block:: Nim + ## 0b0001_0000'i8 shr 2 == 0b0000_0100'i8 + ## 0b1000_0000'i8 shr 8 == 0b1111_1111'i8 + ## 0b1000_0000'i8 shr 1 == 0b1100_0000'i8 +else: + # used for bootstrapping the compiler + proc ashr*[T](x: T, y: SomeInteger): T = discard + proc `and`*(x, y: int): int {.magic: "BitandI", noSideEffect.} proc `and`*(x, y: int8): int8 {.magic: "BitandI", noSideEffect.} proc `and`*(x, y: int16): int16 {.magic: "BitandI", noSideEffect.} diff --git a/tests/arithm/tashr.nim b/tests/arithm/tashr.nim new file mode 100644 index 000000000..aeb3b6843 --- /dev/null +++ b/tests/arithm/tashr.nim @@ -0,0 +1,46 @@ +discard """ + output: '''''' + targets: '''c js''' +""" + +# issue #6255, feature request +# arithmetic right shift + +var x1 = -123'i8 +var x2 = -123'i16 +var x3 = -123'i32 +var x4 = -123'i64 +var x5 = -123 + +block codegen_test: + doAssert ashr(x1, 1) == -62 + doAssert ashr(x2, 1) == -62 + doAssert ashr(x3, 1) == -62 + doAssert ashr(x4, 1) == -62 + doAssert ashr(x5, 1) == -62 + +block semfold_test: + doAssert ashr(-123'i8 , 1) == -62 + doAssert ashr(-123'i16, 1) == -62 + doAssert ashr(-123'i32, 1) == -62 + doAssert ashr(-123'i64, 1) == -62 + doAssert ashr(-123 , 1) == -62 + +static: # VM test + doAssert ashr(-123'i8 , 1) == -62 + doAssert ashr(-123'i16, 1) == -62 + doAssert ashr(-123'i32, 1) == -62 + doAssert ashr(-123'i64, 1) == -62 + doAssert ashr(-123 , 1) == -62 + + var y1 = -123'i8 + var y2 = -123'i16 + var y3 = -123'i32 + var y4 = -123'i64 + var y5 = -123 + + doAssert ashr(y1, 1) == -62 + doAssert ashr(y2, 1) == -62 + doAssert ashr(y3, 1) == -62 + doAssert ashr(y4, 1) == -62 + doAssert ashr(y5, 1) == -62 diff --git a/tests/concepts/t3330.nim b/tests/concepts/t3330.nim index 78dd876e2..8021db827 100644 --- a/tests/concepts/t3330.nim +++ b/tests/concepts/t3330.nim @@ -13,18 +13,14 @@ proc add(result: var string; x: float) first type mismatch at position: 1 required type: var string but expression 'k' is of type: Alias -proc add(x: var string; y: cstring) - first type mismatch at position: 1 - required type: var string - but expression 'k' is of type: Alias -proc add(x: var string; y: char) - first type mismatch at position: 1 - required type: var string - but expression 'k' is of type: Alias proc add(x: var string; y: string) first type mismatch at position: 1 required type: var string but expression 'k' is of type: Alias +proc add(x: var string; y: cstring) + first type mismatch at position: 1 + required type: var string + but expression 'k' is of type: Alias proc add[T](x: var seq[T]; y: T) first type mismatch at position: 1 required type: var seq[T] @@ -33,6 +29,10 @@ proc add(result: var string; x: int64) first type mismatch at position: 1 required type: var string but expression 'k' is of type: Alias +proc add(x: var string; y: char) + first type mismatch at position: 1 + required type: var string + but expression 'k' is of type: Alias t3330.nim(48, 8) template/generic instantiation from here t3330.nim(55, 6) Foo: 'bar.value' cannot be assigned to From ba5e2d6fcb4d1dd5fde523076dafeed77360dba5 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 7 Aug 2018 18:45:27 +0200 Subject: [PATCH 019/103] Make mapIt work on openArray's (#8543) --- lib/pure/collections/sequtils.nim | 33 ++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index db33e41af..8f81fe4f5 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -635,6 +635,28 @@ template mapIt*(s, typ, op: untyped): untyped = result.add(op) result +# This is needed in order not to break the bootstrap, the fallback +# implementation is a "dumb" let that won't work in some cases (eg. when `exp` +# is an openArray) +when declared(macros.symKind): + macro evalOnce(v, exp: untyped): untyped = + expectKind(v, nnkIdent) + var val = exp + + result = newStmtList() + + # Not a parameter we can pass as-is, evaluate and store in a temporary + # variable + if exp.kind != nnkSym or exp.symKind != nskParam: + val = genSym() + result.add(newLetStmt(val, exp)) + + result.add( + newProc(name = genSym(nskTemplate, $v), params = [getType(untyped)], + body = val, procType = nnkTemplateDef)) +else: + macro evalOnce(v, exp: untyped): untyped = + result = newLetStmt(v, exp) template mapIt*(s, op: untyped): untyped = ## Convenience template around the ``map`` proc to reduce typing. @@ -654,8 +676,8 @@ template mapIt*(s, op: untyped): untyped = var it{.inject.}: type(items(s)); op)) var result: seq[outType] - when compiles(s.len): - let t = s + evalOnce(t, s) + when compiles(t.len): var i = 0 result = newSeq[outType](t.len) for it {.inject.} in t: @@ -663,7 +685,7 @@ template mapIt*(s, op: untyped): untyped = i += 1 else: result = @[] - for it {.inject.} in s: + for it {.inject.} in t: result.add(op) result @@ -1044,5 +1066,10 @@ when isMainModule: doAssert mapLiterals((1, ("abc"), 2), float, nested=false) == (float(1), "abc", float(2)) doAssert mapLiterals(([1], ("abc"), 2), `$`, nested=true) == (["1"], "abc", "2") + block: # mapIt with openArray + when declared(macros.symKind): + proc foo(x: openArray[int]): seq[int] = x.mapIt(it + 1) + doAssert foo([1,2,3]) == @[2,3,4] + when not defined(testing): echo "Finished doc tests" From c3523297143d730b1714f4987b5622d31c5f0c07 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 7 Aug 2018 09:52:55 -0700 Subject: [PATCH 020/103] runnableExamples: keep (gitignored) generated foo_examples.nim for inspection even on success (#8544) --- compiler/lineinfos.nim | 6 +++--- compiler/sem.nim | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 261dcb44e..4f0c3a778 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", @@ -169,8 +169,8 @@ proc computeNotesVerbosity(): array[0..3, TNoteKinds] = 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[0] = result[1] - {hintSuccessX, hintSuccess, hintConf, + hintProcessing, hintPattern, hintExecuting, hintLinking} const NotesVerbosity* = computeNotesVerbosity() diff --git a/compiler/sem.nim b/compiler/sem.nim index 2c3fab5a5..5d6e54604 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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) From dd753462926430647d102d856f815f735d3f2b20 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 7 Aug 2018 22:54:45 +0200 Subject: [PATCH 021/103] fixes the new nimcache handling --- compiler/options.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/options.nim b/compiler/options.nim index 4931b4330..be9342085 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -487,11 +487,12 @@ proc getOsCacheDir(): string = result = getHomeDir() / genSubDir proc getNimcacheDir*(conf: ConfigRef): string = + # 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() / conf.projectName & + else: getOsCacheDir() / splitFile(conf.projectName).name & (if isDefined(conf, "release"): "_r" else: "_d") proc pathSubs*(conf: ConfigRef; p, config: string): string = From 817e4bb2fe0538a60f169d37e254b30e3dc3ab1d Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 7 Aug 2018 17:36:56 +0200 Subject: [PATCH 022/103] AsyncHttpClient: return from requests before body completion Store the body completion future at the client and wait for it to complete before issuing additional requests. This allows the body FutureStream reader to drain the stream and read buffers to be freed asynchronously. Fix #8109 --- lib/pure/httpclient.nim | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 8b4fb0f8c..72de72718 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -807,6 +807,7 @@ type lastProgressReport: float when SocketType is AsyncSocket: bodyStream: FutureStream[string] + parseBodyFut: Future[void] else: bodyStream: Stream getBody: bool ## When `false`, the body is never read in requestAux. @@ -1066,10 +1067,14 @@ proc parseResponse(client: HttpClient | AsyncHttpClient, if getBody: when client is HttpClient: client.bodyStream = newStringStream() + result.bodyStream = client.bodyStream + parseBody(client, result.headers, result.version) else: client.bodyStream = newFutureStream[string]("parseResponse") - await parseBody(client, result.headers, result.version) - result.bodyStream = client.bodyStream + result.bodyStream = client.bodyStream + assert(client.parseBodyFut.isNil or client.parseBodyFut.finished) + client.parseBodyFut = parseBody(client, result.headers, result.version) + # do not wait here for the body request to complete proc newConnection(client: HttpClient | AsyncHttpClient, url: Uri) {.multisync.} = @@ -1159,6 +1164,12 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url: string, # Helper that actually makes the request. Does not handle redirects. let requestUrl = parseUri(url) + when client is AsyncHttpClient: + if not client.parseBodyFut.isNil: + # let the current operation finish before making another request + await client.parseBodyFut + client.parseBodyFut = nil + await newConnection(client, requestUrl) let effectiveHeaders = client.headers.override(headers) From a377c5cce4d1e4e70e9cdcaf9ad589e2016b6677 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Aug 2018 19:58:48 +0200 Subject: [PATCH 023/103] introduce the --define 'osx' as an alias for 'macosx' --- compiler/options.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/options.nim b/compiler/options.nim index 598adf27d..7d7327d28 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -354,6 +354,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 From 5b6b73f2a2b0087a800842e790e83b37be938b74 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Aug 2018 20:00:26 +0200 Subject: [PATCH 024/103] use slashes instead of dots for paths --- compiler/lookups.nim | 2 +- compiler/sem.nim | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 87694988a..bab631e6f 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) diff --git a/compiler/sem.nim b/compiler/sem.nim index 5d6e54604..427b44e04 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 From ef9dd464668d08520bdcd549836b4a7551e3b601 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 6 Aug 2018 23:38:29 +0200 Subject: [PATCH 025/103] 'nimcache' defaults to ~/.cache on Posix; cleaned up documentation --- changelog.md | 11 +++++++---- compiler/options.nim | 14 ++++++++++++-- doc/backends.txt | 13 ++++++------- doc/nimc.rst | 35 ++++++++++++----------------------- 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/changelog.md b/changelog.md index c1e7bd09c..9ab7a0b72 100644 --- a/changelog.md +++ b/changelog.md @@ -20,7 +20,7 @@ - The parser now warns about inconsistent spacing around binary operators as these can easily be confused with unary operators. This warning will likely become an error in the future. -- The ``'c`` and ``'C'`` prefix for octal literals is now deprecated to +- The ``'c`` and ``'C'`` suffix for octal literals is now deprecated to bring the language in line with the standard library (e.g. ``parseOct``). - The dot style for import paths (e.g ``import path.to.module`` instead of ``import path/to/module``) has been deprecated. @@ -67,6 +67,9 @@ - The undocumented ``#? braces`` parsing mode was removed. - The undocumented PHP backend was removed. +- The default location of ``nimcache`` for the native code targets was + changed. Read [the compiler user guide](https://nim-lang.org/docs/nimc.html#generated-c-code-directory) + for more information. ### Library additions @@ -162,11 +165,11 @@ - The command syntax now supports keyword arguments after the first comma. - Thread-local variables can now be declared inside procs. This implies all - the effects of the `global` pragma. + the effects of the ``global`` pragma. -- Nim now supports `except` clause in the export statement. +- Nim now supports ``except`` clause in the export statement. -- Range float types, example `range[0.0 .. Inf]`. More details in language manual. +- Range float types, example ``range[0.0 .. Inf]``. More details in language manual. ### Tool changes diff --git a/compiler/options.nim b/compiler/options.nim index 7d7327d28..4931b4330 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -480,9 +480,19 @@ proc disableNimblePath*(conf: ConfigRef) = include packagehandling +proc getOsCacheDir(): string = + when defined(posix): + result = getHomeDir() / ".cache" + else: + result = getHomeDir() / genSubDir + proc getNimcacheDir*(conf: ConfigRef): string = - result = if conf.nimcacheDir.len > 0: conf.nimcacheDir - else: shortenDir(conf, conf.projectPath) / genSubDir + result = if conf.nimcacheDir.len > 0: + conf.nimcacheDir + elif conf.cmd == cmdCompileToJS: + shortenDir(conf, conf.projectPath) / genSubDir + else: getOsCacheDir() / conf.projectName & + (if isDefined(conf, "release"): "_r" else: "_d") proc pathSubs*(conf: ConfigRef; p, config: string): string = let home = removeTrailingDirSep(os.getHomeDir()) diff --git a/doc/backends.txt b/doc/backends.txt index b7f5308ab..13ef7bf4d 100644 --- a/doc/backends.txt +++ b/doc/backends.txt @@ -65,7 +65,6 @@ The JavaScript target --------------------- Nim can also generate `JavaScript`:idx: code through the ``js`` command. -However, the JavaScript code generator is experimental! Nim targets JavaScript 1.5 which is supported by any widely used browser. Since JavaScript does not have a portable means to include another module, @@ -77,7 +76,7 @@ available. This includes: * manual memory management (``alloc``, etc.) * casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.) * file management -* most modules of the Standard library +* most modules of the standard library * proper 64 bit integer arithmetic * unsigned integer arithmetic @@ -87,9 +86,8 @@ However, the modules `strutils `_, `math `_, and To compile a Nim module into a ``.js`` file use the ``js`` command; the default is a ``.js`` file that is supposed to be referenced in an ``.html`` -file. However, you can also run the code with `nodejs`:idx:, a `software -platform for easily building fast, scalable network applications -`_:: +file. However, you can also run the code with `nodejs`:idx: +(``_):: nim js -d:nodejs -r examples/hallo.nim @@ -330,8 +328,9 @@ Nimcache naming logic The `nimcache`:idx: directory is generated during compilation and will hold either temporary or final files depending on your backend target. The default -name for the directory is ``nimcache`` but you can use the ``--nimcache`` -`compiler switch `_ to change it. +name for the directory depends on the used backend and on your OS but you can +use the ``--nimcache`` `compiler switch `_ to +change it. Nimcache and C like targets ~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/nimc.rst b/doc/nimc.rst index 0939f67e8..277c88ec1 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -157,38 +157,27 @@ the first matching file is used. Generated C code directory -------------------------- The generated files that Nim produces all go into a subdirectory called -``nimcache`` in your project directory. This makes it easy to delete all +``nimcache``. Its full path is + +- ``~/.cache/$projectname(_r|_d)`` on Posix +- ``$HOME/nimcache/$projectname(_r|_d)`` on Windows. + +The ``_r`` suffix is used for release builds, ``_d`` is for debug builds. + +This makes it easy to delete all generated files. Files generated in this directory follow a naming logic which you can read about in the `Nim Backend Integration document `_. +The ``--nimcache`` +`compiler switch `_ can be used to +to change the ``nimcache`` directory. + However, the generated C code is not platform independent. C code generated for Linux does not compile on Windows, for instance. The comment on top of the C file lists the OS, CPU and CC the file has been compiled for. -Compilation cache -================= - -**Warning**: The compilation cache is still highly experimental! - -The ``nimcache`` directory may also contain so called `rod`:idx: -or `symbol files`:idx:. These files are pre-compiled modules that are used by -the compiler to perform `incremental compilation`:idx:. This means that only -modules that have changed since the last compilation (or the modules depending -on them etc.) are re-compiled. However, per default no symbol files are -generated; use the ``--symbolFiles:on`` command line switch to activate them. - -Unfortunately due to technical reasons the ``--symbolFiles:on`` needs -to *aggregate* some generated C code. This means that the resulting executable -might contain some cruft even with dead code elimination. So -the final release build should be done with ``--symbolFiles:off``. - -Due to the aggregation of C code it is also recommended that each project -resides in its own directory so that the generated ``nimcache`` directory -is not shared between different projects. - - Compiler Selection ================== From a45faf2dd60f6474aa01b7cddd35d09ce329d6ce Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 7 Aug 2018 22:54:45 +0200 Subject: [PATCH 026/103] fixes the new nimcache handling --- compiler/options.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/options.nim b/compiler/options.nim index 4931b4330..be9342085 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -487,11 +487,12 @@ proc getOsCacheDir(): string = result = getHomeDir() / genSubDir proc getNimcacheDir*(conf: ConfigRef): string = + # 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() / conf.projectName & + else: getOsCacheDir() / splitFile(conf.projectName).name & (if isDefined(conf, "release"): "_r" else: "_d") proc pathSubs*(conf: ConfigRef; p, config: string): string = From de263a43c615199f66440d8d27fe4fb7da3435e3 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 8 Aug 2018 11:21:56 +0200 Subject: [PATCH 027/103] deprecate isNil for strings and seqs --- lib/system.nim | 8 ++++---- tests/system/tnilconcats.nim | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 53605f9fd..3a82299ac 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2321,9 +2321,9 @@ iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} = inc(i) -proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".} +proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil", deprecated.} proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".} -proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".} +proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil", deprecated.} proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".} proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".} proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".} @@ -2520,7 +2520,7 @@ proc `$`*[T: tuple|object](x: T): string = result.add(name) result.add(": ") when compiles($value): - when compiles(value.isNil): + when value isnot string and value isnot seq and compiles(value.isNil): if value.isNil: result.add "nil" else: result.addQuoted(value) else: @@ -2539,7 +2539,7 @@ proc collectionToString[T](x: T, prefix, separator, suffix: string): string = else: result.add(separator) - when compiles(value.isNil): + when value isnot string and value isnot seq and compiles(value.isNil): # this branch should not be necessary if value.isNil: result.add "nil" diff --git a/tests/system/tnilconcats.nim b/tests/system/tnilconcats.nim index ce059b7b0..5e4a1b317 100644 --- a/tests/system/tnilconcats.nim +++ b/tests/system/tnilconcats.nim @@ -1,5 +1,5 @@ discard """ - output: '''@[nil, nil, nil, nil, nil, nil, nil, "meh"]''' + output: '''@["", "", "", "", "", "", "", "meh"]''' exitcode: "0" """ From 00d718b1dbe9cf767f2d57cecbb175a92b99233e Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 8 Aug 2018 12:01:17 +0200 Subject: [PATCH 028/103] strutils: minor code cleanup --- lib/pure/strutils.nim | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index f8c5f9a91..4aede541a 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -358,9 +358,6 @@ proc isNilOrEmpty*(s: string): bool {.noSideEffect, procvar, rtl, proc isNilOrWhitespace*(s: string): bool {.noSideEffect, procvar, rtl, extern: "nsuIsNilOrWhitespace".} = ## Checks if `s` is nil or consists entirely of whitespace characters. - if len(s) == 0: - return true - result = true for c in s: if not c.isSpaceAscii(): @@ -908,7 +905,7 @@ proc parseOctInt*(s: string): int {.noSideEffect, ## `s` are ignored. let L = parseutils.parseOct(s, result, 0) if L != s.len or L == 0: - raise newException(ValueError, "invalid oct integer: " & s) + raise newException(ValueError, "invalid oct integer: " & s) proc parseHexInt*(s: string): int {.noSideEffect, procvar, rtl, extern: "nsuParseHexInt".} = From 05121d84b33c1fd765d6998d01ef530592590ea6 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 8 Aug 2018 12:05:29 +0200 Subject: [PATCH 029/103] fixes a long standing nil bug in substr --- lib/system/sysstr.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 19c2c62ad..77f2ca040 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -95,6 +95,7 @@ proc mnewString(len: int): NimString {.compilerProc.} = proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} = let start = max(start, 0) + if s == nil: return nil let len = min(last, s.len-1) - start + 1 if len > 0: result = rawNewStringNoInit(len) From 640b30a47f89cc488d3fdea9ea1a936c18538b8e Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 8 Aug 2018 12:06:00 +0200 Subject: [PATCH 030/103] codegen improvement: map the empty string to 'nil' since it's now allowed to do that --- compiler/ccgexprs.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 6803a9478..e8bb70f13 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -65,9 +65,9 @@ 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: 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) From 32b62097a2636c5053d842939d34e2a0fa3f9e33 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 8 Aug 2018 15:34:21 +0200 Subject: [PATCH 031/103] Fix regression for mapIt (#8567) Don't try to be too smart and limit the use of `evalOnce` where strictly needed as not every value can be assigned with a `let`. Fixes #8566 --- lib/pure/collections/sequtils.nim | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 8f81fe4f5..99ce91979 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -676,8 +676,8 @@ template mapIt*(s, op: untyped): untyped = var it{.inject.}: type(items(s)); op)) var result: seq[outType] - evalOnce(t, s) - when compiles(t.len): + when compiles(s.len): + evalOnce(t, s) var i = 0 result = newSeq[outType](t.len) for it {.inject.} in t: @@ -685,7 +685,7 @@ template mapIt*(s, op: untyped): untyped = i += 1 else: result = @[] - for it {.inject.} in t: + for it {.inject.} in s: result.add(op) result @@ -1071,5 +1071,10 @@ when isMainModule: proc foo(x: openArray[int]): seq[int] = x.mapIt(it + 1) doAssert foo([1,2,3]) == @[2,3,4] + block: # mapIt with invalid RHS for `let` (#8566) + type X = enum + A, B + doAssert mapIt(X, $it) == @["A", "B"] + when not defined(testing): echo "Finished doc tests" From 00ef2d6693cdb927bbdcbf20664beb6905effa7f Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 8 Aug 2018 15:43:05 +0200 Subject: [PATCH 032/103] make test green again --- tests/generics/tobjecttyperel.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/generics/tobjecttyperel.nim b/tests/generics/tobjecttyperel.nim index 8c8f90098..6c2184cc2 100644 --- a/tests/generics/tobjecttyperel.nim +++ b/tests/generics/tobjecttyperel.nim @@ -2,8 +2,8 @@ discard """ output: '''(peel: 0, color: 15) (color: 15) 17 -(width: 0.0, taste: nil, color: 13) -(width: 0.0, taste: nil, color: 15) +(width: 0.0, taste: "", color: 13) +(width: 0.0, taste: "", color: 15) cool''' """ @@ -11,16 +11,16 @@ cool''' type BaseFruit[T] = object of RootObj color: T - + MidLevel[T] = object of BaseFruit[T] - + Mango = object of MidLevel[int] peel: int - + Peach[X, T, Y] = object of T width: X taste: Y - + proc setColor[T](self: var BaseFruit[T]) = self.color = 15 From b07d1f1dc38bdf073f0036095ff120f1d72d53de Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 8 Aug 2018 16:18:30 +0200 Subject: [PATCH 033/103] make async tests green for Linux --- lib/pure/asyncnet.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index e7552e3e3..da7c3473c 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -493,8 +493,6 @@ proc recvLineInto*(socket: AsyncSocket, resString: FutureVar[string], ## **Warning**: ``recvLineInto`` on unbuffered sockets assumes that the ## protocol uses ``\r\L`` to delimit a new line. assert SocketFlag.Peek notin flags ## TODO: - assert(not resString.mget.isNil(), - "String inside resString future needs to be initialised") result = newFuture[void]("asyncnet.recvLineInto") # TODO: Make the async transformation check for FutureVar params and complete From 506418ef539a9142307235c0cd0183f0d7aec749 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 8 Aug 2018 07:47:17 -0700 Subject: [PATCH 034/103] add build_all.sh to allow 1-liner to build development version of the compiler (#8546) --- build_all.sh | 22 ++++++++++++++++++++++ readme.md | 25 +++++++++++++++++-------- 2 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 build_all.sh diff --git a/build_all.sh b/build_all.sh new file mode 100644 index 000000000..cd5ea3d59 --- /dev/null +++ b/build_all.sh @@ -0,0 +1,22 @@ +#! /bin/sh + +# build development version of the compiler; can be rerun safely + +set -u # error on undefined variables +set -e # exit on first error + +echo_run(){ + echo "\n$@" + "$@" +} + +[ -d csources ] || echo_run git clone --depth 1 https://github.com/nim-lang/csources.git +( + ## avoid changing dir in case of failure + echo_run cd csources + echo_run sh build.sh +) + +echo_run bin/nim c koch +echo_run ./koch boot -d:release +echo_run ./koch tools # Compile Nimble and other tools. diff --git a/readme.md b/readme.md index bdc7c7549..e4fb52bd0 100644 --- a/readme.md +++ b/readme.md @@ -50,24 +50,33 @@ Next, to build from source you will need: other distros as well). Then, if you are on a \*nix system or Windows, the following steps should compile -Nim from source using ``gcc``, ``git`` and the ``koch`` build tool (in the place -of ``sh build.sh`` you should substitute ``build.bat`` on x86 Windows or -``build64.bat`` on x86_64 Windows): +Nim from source using ``gcc``, ``git`` and the ``koch`` build tool. **Note: The following commands are for the development version of the compiler.** For most users, installing the latest stable version is enough. Check out the installation instructions on the website to do so: https://nim-lang.org/install.html. ``` +# step 1: git clone https://github.com/nim-lang/Nim.git cd Nim + +# step 2 (posix) clones `csources.git`, bootstraps Nim compiler and compiles tools +sh build_all.sh + +# step 2 (windows) git clone --depth 1 https://github.com/nim-lang/csources.git + cd csources -sh build.sh -cd ../ -bin/nim c koch -./koch boot -d:release -./koch tools # Compile Nimble and other tools. +# requires `gcc` in your PATH, see also https://nim-lang.org/install_windows.html +build.bat # x86 Windows +build64.bat # x86_64 Windows +cd .. + +bin\nim c koch +koch boot -d:release +koch tools # Compile Nimble and other tools +# end of step 2 (windows) ``` Finally, once you have finished the build steps (on Windows, Mac or Linux) you From bccaa36aba64d2424ceedc9723d5ec01534dde94 Mon Sep 17 00:00:00 2001 From: Mamy Ratsimbazafy Date: Wed, 8 Aug 2018 17:49:33 +0200 Subject: [PATCH 035/103] Tests for v1 closed generics/static issues (#8572) * Add tests to confirm https://github.com/nim-lang/Nim/issues/7231 is fixed. * Add test for closed https://github.com/nim-lang/Nim/issues/6137 * Add test for https://github.com/nim-lang/Nim/issues/7141 --- tests/generics/t6137.nim | 29 +++++++++++++++++++++++++++++ tests/generics/t7141.nim | 10 ++++++++++ tests/metatype/ttypeselectors.nim | 12 ++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 tests/generics/t6137.nim create mode 100644 tests/generics/t7141.nim diff --git a/tests/generics/t6137.nim b/tests/generics/t6137.nim new file mode 100644 index 000000000..639675f35 --- /dev/null +++ b/tests/generics/t6137.nim @@ -0,0 +1,29 @@ +discard """ + action: "reject" + line: 29 + errormsg: "\'vectFunc\' doesn't have a concrete type, due to unspecified generic parameters." +""" + +type + # simple vector of declared fixed length + vector[N : static[int]] = array[0..N-1, float] + +proc `*`[T](x: float, a: vector[T]): vector[T] = + # multiplication by scalar + for ii in 0..high(a): + result[ii] = a[ii]*x + +let + # define a vector of length 3 + x: vector[3] = [1.0, 3.0, 5.0] + +proc vectFunc[T](x: vector[T]): vector[T] {.procvar.} = + # Define a vector function + result = 2.0*x + +proc passVectFunction[T](g: proc(x: vector[T]): vector[T], x: vector[T]): vector[T] = + # pass a vector function as input in another procedure + result = g(x) + +let + xNew = passVectFunction(vectFunc,x) diff --git a/tests/generics/t7141.nim b/tests/generics/t7141.nim new file mode 100644 index 000000000..8a128d828 --- /dev/null +++ b/tests/generics/t7141.nim @@ -0,0 +1,10 @@ +discard """ + action: "reject" + line: 7 + errormsg: "cannot instantiate: \'T\'" +""" + +proc foo[T](x: T) = + discard + +var fun = if true: foo else: foo diff --git a/tests/metatype/ttypeselectors.nim b/tests/metatype/ttypeselectors.nim index 2a2455adb..eb857271d 100644 --- a/tests/metatype/ttypeselectors.nim +++ b/tests/metatype/ttypeselectors.nim @@ -99,3 +99,15 @@ echo sizeof(a) echo sizeof(b) echo sizeof(c) +# This is the same example but using a proc instead of a macro +# Instead of type mismatch for macro, proc just failed with internal error: getTypeDescAux(tyNone) +# https://github.com/nim-lang/Nim/issues/7231 + +proc getBase2*(bits: static[int]): typedesc = + if bits == 128: + result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint64")) + else: + result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint32")) + +type + MpUint2*[bits: static[int]] = getbase2(bits) From babd31360a93b1c17d33240c82391761e8419a95 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 8 Aug 2018 18:22:48 +0200 Subject: [PATCH 036/103] fixes more nil string bugs --- lib/packages/docutils/rstgen.nim | 7 +++---- lib/pure/strutils.nim | 10 ++++++---- lib/system/sysstr.nim | 1 + 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 43a429a17..db9a83755 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -312,7 +312,6 @@ proc setIndexTerm*(d: var RstGenerator, id, term: string, ## The index won't be written to disk unless you call `writeIndexFile() ## <#writeIndexFile>`_. The purpose of the index is documented in the `docgen ## tools guide `_. - assert(not d.theIndex.isNil) var entry = term isTitle = false @@ -337,7 +336,7 @@ proc hash(n: PRstNode): int = result = hash(n.text) elif n.len > 0: result = hash(n.sons[0]) - for i in 1 .. $2 """, [url, text, desc]) else: - result.addf("""
  • $2
  • """, [url, text]) inc j @@ -524,7 +523,7 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string = titleTag = levels[L].text else: result.add(level.indentToLevel(levels[L].level)) - result.addf("""
  • + result.addf("""
  • $3
  • """, [titleTag & " : " & levels[L].text, link, levels[L].text]) inc L diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 4aede541a..989a832cf 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1366,9 +1366,11 @@ proc find*(s: string, sub: char, start: Natural = 0, last: Natural = 0): int {.n if sub == s[i]: return i else: when hasCStringBuiltin: - let found = c_memchr(s[start].unsafeAddr, sub, last-start+1) - if not found.isNil: - return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) + let L = last-start+1 + if L > 0: + let found = c_memchr(s[start].unsafeAddr, sub, L) + if not found.isNil: + return cast[ByteAddress](found) -% cast[ByteAddress](s.cstring) else: for i in start..last: if sub == s[i]: return i @@ -1515,7 +1517,7 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect, elif subLen == 1: # when the pattern is a single char, we use a faster # char-based search that doesn't need a skip table: - var c = sub[0] + let c = sub[0] let last = s.high var i = 0 while true: diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 77f2ca040..0e690d832 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -110,6 +110,7 @@ proc nimToCStringConv(s: NimString): cstring {.compilerProc, inline.} = else: result = cstring(addr s.data) proc copyStr(s: NimString, start: int): NimString {.compilerProc.} = + if s == nil: return nil result = copyStrLast(s, start, s.len-1) proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} = From 98225ca207e4057c1da7966430d0699c0151e3e7 Mon Sep 17 00:00:00 2001 From: Grant Date: Thu, 9 Aug 2018 00:40:21 -0700 Subject: [PATCH 037/103] Update channels.nim (#8583) Fix typo in channels.nim --- lib/system/channels.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/channels.nim b/lib/system/channels.nim index 254b87dfc..14d3a3005 100644 --- a/lib/system/channels.nim +++ b/lib/system/channels.nim @@ -233,7 +233,7 @@ proc send*[TMsg](c: var Channel[TMsg], msg: TMsg) {.inline.} = proc trySend*[TMsg](c: var Channel[TMsg], msg: TMsg): bool {.inline.} = ## Tries to send a message to a thread. `msg` is deeply copied. Doesn't block. ## Returns `false` if the message was not sent because number of pending items - ## in the cannel exceeded `maxItems`. + ## in the channel exceeded `maxItems`. sendImpl(cast[PRawChannel](addr c), cast[PNimType](getTypeInfo(msg)), unsafeAddr(msg), true) proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) = From a2c5ffba0cd82b5677fa57612f7dcb7af2348f45 Mon Sep 17 00:00:00 2001 From: alaviss Date: Thu, 9 Aug 2018 15:50:36 +0700 Subject: [PATCH 038/103] Uses XDG_CACHE_HOME if available (#8585) * compiler/options: use XDG_CACHE_HOME if set * doc/nimc: update documentation --- compiler/options.nim | 2 +- doc/nimc.rst | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index be9342085..44519ea22 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -482,7 +482,7 @@ include packagehandling proc getOsCacheDir(): string = when defined(posix): - result = getHomeDir() / ".cache" + result = string getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache") else: result = getHomeDir() / genSubDir diff --git a/doc/nimc.rst b/doc/nimc.rst index 277c88ec1..fca5b273c 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -159,7 +159,8 @@ Generated C code directory The generated files that Nim produces all go into a subdirectory called ``nimcache``. Its full path is -- ``~/.cache/$projectname(_r|_d)`` on Posix +- ``$XDG_CACHE_HOME/$projectname(_r|_d)`` or ``~/.cache/$projectname(_r|_d)`` + on Posix - ``$HOME/nimcache/$projectname(_r|_d)`` on Windows. The ``_r`` suffix is used for release builds, ``_d`` is for debug builds. From 730ce53b71a207edf93abe09c14c150b9c360028 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 9 Aug 2018 01:56:05 -0700 Subject: [PATCH 039/103] save a backup of csources-built nim to bin/nim_csources to avoid recompiling from csources (#8582) --- build_all.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/build_all.sh b/build_all.sh index cd5ea3d59..701d7d204 100644 --- a/build_all.sh +++ b/build_all.sh @@ -11,11 +11,20 @@ echo_run(){ } [ -d csources ] || echo_run git clone --depth 1 https://github.com/nim-lang/csources.git -( + +nim_csources=bin/nim_csources +build_nim_csources(){ ## avoid changing dir in case of failure - echo_run cd csources - echo_run sh build.sh -) + ( + echo_run cd csources + echo_run sh build.sh + ) + # keep $nim_csources in case needed to investigate bootstrap issues + # without having to rebuild from csources + echo_run cp bin/nim $nim_csources +} + +[ -f $nim_csources ] || echo_run build_nim_csources echo_run bin/nim c koch echo_run ./koch boot -d:release From b4e5c9d075d9c2ef6192749b02738966b3dc943d Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 9 Aug 2018 20:31:40 +0200 Subject: [PATCH 040/103] deprecate the .this pragma --- changelog.md | 4 +++ compiler/idents.nim | 37 ++++++++++----------------- compiler/modulegraphs.nim | 54 +++++++++++++++++++-------------------- compiler/pragmas.nim | 2 ++ doc/manual.rst | 2 ++ 5 files changed, 48 insertions(+), 51 deletions(-) diff --git a/changelog.md b/changelog.md index 9ab7a0b72..426b63b7e 100644 --- a/changelog.md +++ b/changelog.md @@ -170,6 +170,10 @@ - Nim now supports ``except`` clause in the export statement. - Range float types, example ``range[0.0 .. Inf]``. More details in language manual. +- The ``{.this.}`` pragma has been deprecated. It never worked within generics and + we found the resulting code harder to read than the more explicit ``obj.field`` + syntax. + ### Tool changes 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/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.. Date: Fri, 10 Aug 2018 01:20:14 +0200 Subject: [PATCH 041/103] deprecated regionized pointers --- changelog.md | 3 ++ compiler/semtypes.nim | 2 + doc/manual.rst | 62 ----------------------------- lib/pure/concurrency/threadpool.nim | 6 +-- tests/parallel/tptr_to_ref.nim | 4 +- 5 files changed, 9 insertions(+), 68 deletions(-) diff --git a/changelog.md b/changelog.md index 426b63b7e..a77c57631 100644 --- a/changelog.md +++ b/changelog.md @@ -173,6 +173,9 @@ - The ``{.this.}`` pragma has been deprecated. It never worked within generics and we found the resulting code harder to read than the more explicit ``obj.field`` syntax. +- "Memory regions" for pointer types have been deprecated, they were hardly used + anywhere. Note that this has **nothing** to do with the ``--gc:regions`` switch + of managing memory. ### Tool changes diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 972c8c709..99f2cf20d 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -193,6 +193,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/doc/manual.rst b/doc/manual.rst index 460468fe5..7aeec7390 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1507,68 +1507,6 @@ non nilable pointers. The details of this analysis are still to be specified here. -Memory regions --------------- - -The types ``ref`` and ``ptr`` can get an optional ``region`` annotation. -A region has to be an object type. - -Regions are very useful to separate user space and kernel memory in the -development of OS kernels: - -.. code-block:: nim - type - Kernel = object - Userspace = object - - var a: Kernel ptr Stat - var b: Userspace ptr Stat - - # the following does not compile as the pointer types are incompatible: - a = b - -As the example shows ``ptr`` can also be used as a binary -operator, ``region ptr T`` is a shortcut for ``ptr[region, T]``. - -In order to make generic code easier to write ``ptr T`` is a subtype -of ``ptr[R, T]`` for any ``R``. - -Furthermore the subtype relation of the region object types is lifted to -the pointer types: If ``A <: B`` then ``ptr[A, T] <: ptr[B, T]``. This can be -used to model subregions of memory. As a special typing rule ``ptr[R, T]`` is -not compatible to ``pointer`` to prevent the following from compiling: - -.. code-block:: nim - # from system - proc dealloc(p: pointer) - - # wrap some scripting language - type - PythonsHeap = object - PyObjectHeader = object - rc: int - typ: pointer - PyObject = ptr[PythonsHeap, PyObjectHeader] - - proc createPyObject(): PyObject {.importc: "...".} - proc destroyPyObject(x: PyObject) {.importc: "...".} - - var foo = createPyObject() - # type error here, how convenient: - dealloc(foo) - - -Future directions: - -* Memory regions might become available for ``string`` and ``seq`` too. -* Builtin regions like ``private``, ``global`` and ``local`` might be - useful for an OpenCL target. -* Builtin "regions" can model ``lent`` and ``unique`` pointers. -* An assignment operator can be attached to a region so that proper write - barriers can be generated. This would imply that the GC can be implemented - completely in user-space. - - Procedural type --------------- A procedural type is internally a pointer to a procedure. ``nil`` is diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 6ec71e912..826e42b6c 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -89,8 +89,6 @@ proc closeBarrier(b: ptr Barrier) {.compilerProc.} = # ---------------------------------------------------------------------------- type - foreign* = object ## a region that indicates the pointer comes from a - ## foreign thread heap. AwaitInfo = object cv: Semaphore idx: int @@ -231,10 +229,10 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) = action(fv.blob) finished(fv) -proc unsafeRead*[T](fv: FlowVar[ref T]): foreign ptr T = +proc unsafeRead*[T](fv: FlowVar[ref T]): ptr T = ## blocks until the value is available and then returns this value. await(fv) - result = cast[foreign ptr T](fv.data) + result = cast[ptr T](fv.data) proc `^`*[T](fv: FlowVar[ref T]): ref T = ## blocks until the value is available and then returns this value. diff --git a/tests/parallel/tptr_to_ref.nim b/tests/parallel/tptr_to_ref.nim index fee210dcd..ae02c16e5 100644 --- a/tests/parallel/tptr_to_ref.nim +++ b/tests/parallel/tptr_to_ref.nim @@ -11,7 +11,7 @@ type Killer* = object lock: Lock bailed {.guard: lock.}: bool - processes {.guard: lock.}: array[0..MAX_WORKERS-1, foreign ptr Process] + processes {.guard: lock.}: array[0..MAX_WORKERS-1, ptr Process] # Hold a lock for a statement. template hold(lock: Lock, body: untyped) = @@ -32,7 +32,7 @@ proc initKiller*(): Killer = var killer = initKiller() # remember that a process has been launched, killing it if we have bailed. -proc launched*(process: foreign ptr Process): int {.gcsafe.} = +proc launched*(process: ptr Process): int {.gcsafe.} = result = killer.processes.high + 1 killer.lock.hold: if killer.bailed: From 864d24d70e51bb27d5789f4e4d7845576bdf33da Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Aug 2018 08:42:13 +0200 Subject: [PATCH 042/103] change the VM's max instruction count to 3_000_000 --- changelog.md | 2 +- compiler/vmdef.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index a77c57631..f06041b34 100644 --- a/changelog.md +++ b/changelog.md @@ -185,7 +185,7 @@ ### Compiler changes -- The VM's instruction count limit was raised to 1 billion instructions in +- The VM's instruction count limit was raised to 3 million instructions in order to support more complex computations at compile-time. - Support for hot code reloading has been implemented for the JavaScript diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 50235c95f..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 From 43f634db8dfac4fb13c8454958d35e776410dac1 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 10 Aug 2018 00:20:14 -0700 Subject: [PATCH 043/103] fixes #8519; implements T.distinctBase to reverse T = distinct A (#8531) --- doc/manual.rst | 3 ++- lib/pure/sugar.nim | 38 ++++++++++++++++++++++++++++++++++++++ tests/stdlib/tsugar.nim | 29 +++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tests/stdlib/tsugar.nim diff --git a/doc/manual.rst b/doc/manual.rst index abdc4ce69..de0a13143 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -1673,7 +1673,8 @@ A ``distinct`` type is new type derived from a `base type`:idx: that is incompatible with its base type. In particular, it is an essential property of a distinct type that it **does not** imply a subtype relation between it and its base type. Explicit type conversions from a distinct type to its -base type and vice versa are allowed. +base type and vice versa are allowed. See also ``distinctBase`` to get the +reverse operation. Modelling currencies diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 258b40191..8ded552d9 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -198,3 +198,41 @@ macro dump*(x: typed): untyped = let r = quote do: debugEcho `s`, " = ", `x` return r + +# TODO: consider exporting this in macros.nim +proc freshIdentNodes(ast: NimNode): NimNode = + # Replace NimIdent and NimSym by a fresh ident node + # see also https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458 + proc inspect(node: NimNode): NimNode = + case node.kind: + of nnkIdent, nnkSym: + result = ident($node) + of nnkEmpty, nnkLiterals: + result = node + else: + result = node.kind.newTree() + for child in node: + result.add inspect(child) + result = inspect(ast) + +macro distinctBase*(T: typedesc): untyped = + ## reverses ``type T = distinct A``; works recursively. + runnableExamples: + type T = distinct int + doAssert distinctBase(T) is int + doAssert: not compiles(distinctBase(int)) + type T2 = distinct T + doAssert distinctBase(T2) is int + + let typeNode = getTypeImpl(T) + expectKind(typeNode, nnkBracketExpr) + if typeNode[0].typeKind != ntyTypeDesc: + error "expected typeDesc, got " & $typeNode[0] + var typeSym = typeNode[1] + typeSym = getTypeImpl(typeSym) + if typeSym.typeKind != ntyDistinct: + error "type is not distinct" + typeSym = typeSym[0] + while typeSym.typeKind == ntyDistinct: + typeSym = getTypeImpl(typeSym)[0] + typeSym.freshIdentNodes diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim new file mode 100644 index 000000000..a870bf6fe --- /dev/null +++ b/tests/stdlib/tsugar.nim @@ -0,0 +1,29 @@ +discard """ + file: "tsugar.nim" + output: "" +""" +import sugar +import macros + +block distinctBase: + block: + type + Foo[T] = distinct seq[T] + var a: Foo[int] + doAssert a.type.distinctBase is seq[int] + + block: + # simplified from https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458 + macro uintImpl(bits: static[int]): untyped = + if bits >= 128: + let inner = getAST(uintImpl(bits div 2)) + result = newTree(nnkBracketExpr, ident("UintImpl"), inner) + else: + result = ident("uint64") + + type + BaseUint = UintImpl or SomeUnsignedInt + UintImpl[Baseuint] = object + Uint[bits: static[int]] = distinct uintImpl(bits) + + doAssert Uint[128].distinctBase is UintImpl[uint64] From 1d63a8fe4a21d71ab2d8cfb7d1540bdc09d02c29 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Aug 2018 09:21:46 +0200 Subject: [PATCH 044/103] update the 'float' spec; refs #8589 --- doc/manual.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 7aeec7390..c0cde5140 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -769,8 +769,8 @@ Pre-defined floating point types The following floating point types are pre-defined: ``float`` - the generic floating point type; its size is platform dependent - (the compiler chooses the processor's fastest floating point type). + the generic floating point type; its size used to be platform dependent, + but now it is always mapped to ``float64``. This type should be used in general. floatXX From 7e2418bd224add065bb1245a0602b8d75dd2ca03 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Aug 2018 09:37:17 +0200 Subject: [PATCH 045/103] make nimsuggest go up in the directory tree in order to determine the main .nim file --- compiler/options.nim | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index be9342085..ff3e70800 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -600,18 +600,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 = From 28c709fa8422af6faa1f48c37d0ddd62e20deb7d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Aug 2018 09:37:41 +0200 Subject: [PATCH 046/103] cleanup nimsuggest tests a bit --- nimsuggest/tester.nim | 12 ++++++------ nimsuggest/tests/tdot4.nim | 2 +- nimsuggest/tests/tinclude.nim | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/nimsuggest/tester.nim b/nimsuggest/tester.nim index 4cda272af..b962a9f83 100644 --- a/nimsuggest/tester.nim +++ b/nimsuggest/tester.nim @@ -70,22 +70,22 @@ proc parseCmd(c: string): seq[string] = result = @[] var i = 0 var a = "" - while true: + while i < c.len: setLen(a, 0) # eat all delimiting whitespace - while c[i] in {' ', '\t', '\l', '\r'}: inc(i) + while i < c.len and c[i] in {' ', '\t', '\l', '\r'}: inc(i) + if i >= c.len: break case c[i] of '"': raise newException(ValueError, "double quotes not yet supported: " & c) of '\'': var delim = c[i] inc(i) # skip ' or " - while c[i] != '\0' and c[i] != delim: + while i < c.len and c[i] != delim: add a, c[i] inc(i) - if c[i] != '\0': inc(i) - of '\0': break + if i < c.len: inc(i) else: - while c[i] > ' ': + while i < c.len and c[i] > ' ': add(a, c[i]) inc(i) add(result, a) diff --git a/nimsuggest/tests/tdot4.nim b/nimsuggest/tests/tdot4.nim index 25e77ed04..8510162ac 100644 --- a/nimsuggest/tests/tdot4.nim +++ b/nimsuggest/tests/tdot4.nim @@ -2,7 +2,7 @@ discard """ $nimsuggest --tester --maxresults:2 $file >sug $1 sug;;skProc;;tdot4.main;;proc (inp: string): string;;$file;;10;;5;;"";;100;;None -sug;;skProc;;strutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;$lib/pure/strutils.nim;;1575;;5;;"Replaces `sub` in `s` by the string `by`.";;100;;None +sug;;skProc;;strutils.replace;;proc (s: string, sub: string, by: string): string{.noSideEffect, gcsafe, locks: 0.};;$lib/pure/strutils.nim;;1506;;5;;"Replaces `sub` in `s` by the string `by`.";;100;;None """ import strutils diff --git a/nimsuggest/tests/tinclude.nim b/nimsuggest/tests/tinclude.nim index 12d40d1e7..0616b7164 100644 --- a/nimsuggest/tests/tinclude.nim +++ b/nimsuggest/tests/tinclude.nim @@ -1,7 +1,7 @@ discard """ $nimsuggest --tester compiler/nim.nim ->def compiler/semexprs.nim:13:50 -def;;skType;;ast.PSym;;PSym;;*ast.nim;;691;;2;;"";;100 ->def compiler/semexprs.nim:13:50 -def;;skType;;ast.PSym;;PSym;;*ast.nim;;691;;2;;"";;100 +>def compiler/semexprs.nim:25:50 +def;;skType;;ast.PSym;;PSym;;*ast.nim;;707;;2;;"";;100 +>def compiler/semexprs.nim:25:50 +def;;skType;;ast.PSym;;PSym;;*ast.nim;;707;;2;;"";;100 """ From 1d78ba64b4761de88817a2e5748a456679cb2bab Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Aug 2018 11:40:01 +0200 Subject: [PATCH 047/103] rework the exception hierarchy; refs #8363 --- changelog.md | 4 ++ doc/exception_hierarchy_fragment.txt | 28 -------- doc/manual.rst | 9 ++- lib/pure/smtp.nim | 6 +- lib/system.nim | 104 +++++++++------------------ 5 files changed, 45 insertions(+), 106 deletions(-) delete mode 100644 doc/exception_hierarchy_fragment.txt diff --git a/changelog.md b/changelog.md index f06041b34..5a28fc7ff 100644 --- a/changelog.md +++ b/changelog.md @@ -177,6 +177,10 @@ anywhere. Note that this has **nothing** to do with the ``--gc:regions`` switch of managing memory. +- The exception hierarchy was slightly reworked, ``SystemError`` was renamed to + ``Error`` and is the new base class for any exception that is guaranteed to + be catchable. This change should have minimal impact on most existing Nim code. + ### Tool changes diff --git a/doc/exception_hierarchy_fragment.txt b/doc/exception_hierarchy_fragment.txt deleted file mode 100644 index a02d9ccef..000000000 --- a/doc/exception_hierarchy_fragment.txt +++ /dev/null @@ -1,28 +0,0 @@ -* `Exception `_ - * `AccessViolationError `_ - * `ArithmeticError `_ - * `DivByZeroError `_ - * `OverflowError `_ - * `AssertionError `_ - * `DeadThreadError `_ - * `FloatingPointError `_ - * `FloatDivByZeroError `_ - * `FloatInexactError `_ - * `FloatInvalidOpError `_ - * `FloatOverflowError `_ - * `FloatUnderflowError `_ - * `FieldError `_ - * `IndexError `_ - * `ObjectAssignmentError `_ - * `ObjectConversionError `_ - * `ValueError `_ - * `KeyError `_ - * `ReraiseError `_ - * `RangeError `_ - * `OutOfMemoryError `_ - * `ResourceExhaustedError `_ - * `StackOverflowError `_ - * `SystemError `_ - * `IOError `_ - * `OSError `_ - * `LibraryError `_ diff --git a/doc/manual.rst b/doc/manual.rst index c0cde5140..6ce72e2e1 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3968,9 +3968,12 @@ exception. Exception hierarchy ------------------- -The exception tree is defined in the `system `_ module: - -.. include:: exception_hierarchy_fragment.txt +The exception tree is defined in the `system `_ module. +Every exception inherits from ``system.Exception``. Exceptions that indicate +programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``) +and are stricly speaking not catchable as they can also be mapped to an operation +that terminates the whole process. Exceptions that indicate any other runtime error +that can be caught inherit from ``system.Error`` (which is a subtype of ``Exception``). Imported exceptions diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index c2c674b84..d9b863a52 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -119,8 +119,7 @@ proc newSmtp*(useSsl = false, debug=false, when compiledWithSsl: sslContext.wrapSocket(result.sock) else: - raise newException(SystemError, - "SMTP module compiled without SSL support") + {.error: "SMTP module compiled without SSL support".} proc newAsyncSmtp*(useSsl = false, debug=false, sslContext = defaultSslContext): AsyncSmtp = @@ -133,8 +132,7 @@ proc newAsyncSmtp*(useSsl = false, debug=false, when compiledWithSsl: sslContext.wrapSocket(result.sock) else: - raise newException(SystemError, - "SMTP module compiled without SSL support") + {.error: "SMTP module compiled without SSL support".} proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] = var retFuture = newFuture[void]() diff --git a/lib/system.nim b/lib/system.nim index 3a82299ac..531363eb1 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -484,141 +484,103 @@ type raise_id: uint # set when exception is raised up: ref Exception # used for stacking exceptions. Not exported! - SystemError* = object of Exception ## \ - ## Abstract class for exceptions that the runtime system raises. - ## - ## See the full `exception hierarchy `_. - IOError* = object of SystemError ## \ + Defect* = object of Exception ## \ + ## Abstract base class for all exceptions that Nim's runtime raises + ## but that are strictly uncatchable as they can also be mapped to + ## a ``quit`` / ``trap`` / ``exit`` operation. + + Error* = object of Exception ## \ + ## Abstract class for all exceptions that are catchable. + IOError* = object of Error ## \ ## Raised if an IO error occurred. - ## - ## See the full `exception hierarchy `_. EOFError* = object of IOError ## \ ## Raised if an IO "end of file" error occurred. - ## - ## See the full `exception hierarchy `_. - OSError* = object of SystemError ## \ + OSError* = object of Error ## \ ## Raised if an operating system service failed. - ## - ## See the full `exception hierarchy `_. errorCode*: int32 ## OS-defined error code describing this error. LibraryError* = object of OSError ## \ ## Raised if a dynamic library could not be loaded. - ## - ## See the full `exception hierarchy `_. - ResourceExhaustedError* = object of SystemError ## \ + ResourceExhaustedError* = object of Error ## \ ## Raised if a resource request could not be fulfilled. - ## - ## See the full `exception hierarchy `_. - ArithmeticError* = object of Exception ## \ + ArithmeticError* = object of Defect ## \ ## Raised if any kind of arithmetic error occurred. - ## - ## See the full `exception hierarchy `_. DivByZeroError* = object of ArithmeticError ## \ ## Raised for runtime integer divide-by-zero errors. - ## - ## See the full `exception hierarchy `_. OverflowError* = object of ArithmeticError ## \ ## Raised for runtime integer overflows. ## ## This happens for calculations whose results are too large to fit in the - ## provided bits. See the full `exception hierarchy `_. - AccessViolationError* = object of Exception ## \ + ## provided bits. + AccessViolationError* = object of Defect ## \ ## Raised for invalid memory access errors - ## - ## See the full `exception hierarchy `_. - AssertionError* = object of Exception ## \ + AssertionError* = object of Defect ## \ ## Raised when assertion is proved wrong. ## - ## Usually the result of using the `assert() template <#assert>`_. See the - ## full `exception hierarchy `_. - ValueError* = object of Exception ## \ + ## Usually the result of using the `assert() template <#assert>`_. + ValueError* = object of Defect ## \ ## Raised for string and object conversion errors. KeyError* = object of ValueError ## \ ## Raised if a key cannot be found in a table. ## ## Mostly used by the `tables `_ module, it can also be raised ## by other collection modules like `sets `_ or `strtabs - ## `_. See the full `exception hierarchy `_. - OutOfMemError* = object of SystemError ## \ + ## `_. + OutOfMemError* = object of Defect ## \ ## Raised for unsuccessful attempts to allocate memory. - ## - ## See the full `exception hierarchy `_. - IndexError* = object of Exception ## \ + IndexError* = object of Defect ## \ ## Raised if an array index is out of bounds. - ## - ## See the full `exception hierarchy `_. - FieldError* = object of Exception ## \ + FieldError* = object of Defect ## \ ## Raised if a record field is not accessible because its dicriminant's ## value does not fit. - ## - ## See the full `exception hierarchy `_. - RangeError* = object of Exception ## \ + RangeError* = object of Defect ## \ ## Raised if a range check error occurred. - ## - ## See the full `exception hierarchy `_. - StackOverflowError* = object of SystemError ## \ + StackOverflowError* = object of Defect ## \ ## Raised if the hardware stack used for subroutine calls overflowed. - ## - ## See the full `exception hierarchy `_. - ReraiseError* = object of Exception ## \ + ReraiseError* = object of Defect ## \ ## Raised if there is no exception to reraise. - ## - ## See the full `exception hierarchy `_. - ObjectAssignmentError* = object of Exception ## \ + ObjectAssignmentError* = object of Defect ## \ ## Raised if an object gets assigned to its parent's object. - ## - ## See the full `exception hierarchy `_. - ObjectConversionError* = object of Exception ## \ + ObjectConversionError* = object of Defect ## \ ## Raised if an object is converted to an incompatible object type. ## You can use ``of`` operator to check if conversion will succeed. - ## - ## See the full `exception hierarchy `_. - FloatingPointError* = object of Exception ## \ + FloatingPointError* = object of Defect ## \ ## Base class for floating point exceptions. - ## - ## See the full `exception hierarchy `_. FloatInvalidOpError* = object of FloatingPointError ## \ ## Raised by invalid operations according to IEEE. ## - ## Raised by ``0.0/0.0``, for example. See the full `exception - ## hierarchy `_. + ## Raised by ``0.0/0.0``, for example. FloatDivByZeroError* = object of FloatingPointError ## \ ## Raised by division by zero. ## - ## Divisor is zero and dividend is a finite nonzero number. See the full - ## `exception hierarchy `_. + ## Divisor is zero and dividend is a finite nonzero number. FloatOverflowError* = object of FloatingPointError ## \ ## Raised for overflows. ## ## The operation produced a result that exceeds the range of the exponent. - ## See the full `exception hierarchy `_. FloatUnderflowError* = object of FloatingPointError ## \ ## Raised for underflows. ## ## The operation produced a result that is too small to be represented as a - ## normal number. See the full `exception hierarchy `_. + ## normal number. FloatInexactError* = object of FloatingPointError ## \ ## Raised for inexact results. ## ## The operation produced a result that cannot be represented with infinite ## precision -- for example: ``2.0 / 3.0, log(1.1)`` ## - ## **NOTE**: Nim currently does not detect these! See the full - ## `exception hierarchy `_. - DeadThreadError* = object of Exception ## \ + ## **NOTE**: Nim currently does not detect these! + DeadThreadError* = object of Defect ## \ ## Raised if it is attempted to send a message to a dead thread. - ## - ## See the full `exception hierarchy `_. - NilAccessError* = object of SystemError ## \ + NilAccessError* = object of Defect ## \ ## Raised on dereferences of ``nil`` pointers. ## ## This is only raised if the ``segfaults.nim`` module was imported! when defined(nimNewRuntime): type - MoveError* = object of SystemError ## \ + MoveError* = object of Defect ## \ ## Raised on attempts to re-sink an already consumed ``sink`` parameter. when defined(js) or defined(nimdoc): From ba6601b149e77be52973209fbcea5a799f1ebf24 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Aug 2018 12:09:51 +0200 Subject: [PATCH 048/103] fixes #8599 --- compiler/options.nim | 2 +- doc/nimc.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/options.nim b/compiler/options.nim index ef2b6023a..537a550f8 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -482,7 +482,7 @@ include packagehandling proc getOsCacheDir(): string = when defined(posix): - result = string getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache") + result = getEnv("XDG_CACHE_HOME", getHomeDir() / ".cache") / "nim" else: result = getHomeDir() / genSubDir diff --git a/doc/nimc.rst b/doc/nimc.rst index fca5b273c..a33be39e6 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -159,7 +159,7 @@ Generated C code directory The generated files that Nim produces all go into a subdirectory called ``nimcache``. Its full path is -- ``$XDG_CACHE_HOME/$projectname(_r|_d)`` or ``~/.cache/$projectname(_r|_d)`` +- ``$XDG_CACHE_HOME/nim/$projectname(_r|_d)`` or ``~/.cache/nim/$projectname(_r|_d)`` on Posix - ``$HOME/nimcache/$projectname(_r|_d)`` on Windows. From 4cf1e3eb4b77e4afd5047397b05726756c2de598 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 10 Aug 2018 15:31:53 +0200 Subject: [PATCH 049/103] rename SystemError to CatchableError in order to avoid breaking Nimble and probably lots of other code --- changelog.md | 2 +- doc/manual.rst | 3 ++- lib/system.nim | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index 5a28fc7ff..f48f7e024 100644 --- a/changelog.md +++ b/changelog.md @@ -178,7 +178,7 @@ of managing memory. - The exception hierarchy was slightly reworked, ``SystemError`` was renamed to - ``Error`` and is the new base class for any exception that is guaranteed to + ``CatchableError`` and is the new base class for any exception that is guaranteed to be catchable. This change should have minimal impact on most existing Nim code. diff --git a/doc/manual.rst b/doc/manual.rst index 6ce72e2e1..6ea82b78c 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3973,7 +3973,8 @@ Every exception inherits from ``system.Exception``. Exceptions that indicate programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``) and are stricly speaking not catchable as they can also be mapped to an operation that terminates the whole process. Exceptions that indicate any other runtime error -that can be caught inherit from ``system.Error`` (which is a subtype of ``Exception``). +that can be caught inherit from ``system.CatchableError`` +(which is a subtype of ``Exception``). Imported exceptions diff --git a/lib/system.nim b/lib/system.nim index 531363eb1..b92dd58d6 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -489,18 +489,18 @@ type ## but that are strictly uncatchable as they can also be mapped to ## a ``quit`` / ``trap`` / ``exit`` operation. - Error* = object of Exception ## \ + CatchableError* = object of Exception ## \ ## Abstract class for all exceptions that are catchable. - IOError* = object of Error ## \ + IOError* = object of CatchableError ## \ ## Raised if an IO error occurred. EOFError* = object of IOError ## \ ## Raised if an IO "end of file" error occurred. - OSError* = object of Error ## \ + OSError* = object of CatchableError ## \ ## Raised if an operating system service failed. errorCode*: int32 ## OS-defined error code describing this error. LibraryError* = object of OSError ## \ ## Raised if a dynamic library could not be loaded. - ResourceExhaustedError* = object of Error ## \ + ResourceExhaustedError* = object of CatchableError ## \ ## Raised if a resource request could not be fulfilled. ArithmeticError* = object of Defect ## \ ## Raised if any kind of arithmetic error occurred. From 32afc1a562579d38e82ebb385186767dfb1bc3c8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 10 Aug 2018 17:27:30 +0200 Subject: [PATCH 050/103] make tests green again --- examples/tunit.nim | 2 +- tests/exprs/tstmtexprs.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tunit.nim b/examples/tunit.nim index 26bcafda1..785b9aa5e 100644 --- a/examples/tunit.nim +++ b/examples/tunit.nim @@ -42,6 +42,6 @@ test "arithmetic failure": expect(ArithmeticError): err() - expect(ArithmeticError, SystemError): + expect(ArithmeticError, CatchableError): discard foo() diff --git a/tests/exprs/tstmtexprs.nim b/tests/exprs/tstmtexprs.nim index 61089b694..615c36024 100644 --- a/tests/exprs/tstmtexprs.nim +++ b/tests/exprs/tstmtexprs.nim @@ -87,7 +87,7 @@ proc parseResponse(): JsonNode = var excMsg = key & "(" if (var n=result["key2"]; n != nil): excMsg &= n.str - raise newException(SystemError, excMsg) + raise newException(CatchableError, excMsg) From 089529c16aa45926eb64395e27b8e56b46f4aa92 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 11 Aug 2018 05:03:42 +0200 Subject: [PATCH 051/103] Preliminary check for test category folder existence (#8579) Warn the user if nothing is executed. --- tests/testament/categories.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index f7cd0815c..95521449a 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -523,5 +523,9 @@ proc processCategory(r: var TResults, cat: Category, options: string) = # We can't test it because it depends on a third party. discard # TODO: Move untestable tests to someplace else, i.e. nimble repo. else: + var testsRun = 0 for name in os.walkFiles("tests" & DirSep &.? cat.string / "t*.nim"): testSpec r, makeTest(name, options, cat) + inc testsRun + if testsRun == 0: + echo "[Warning] - Invalid category specified \"", cat.string, "\", no tests were run" From ba7c874a7df6e96dee2d7647a3f554d7476d3ae6 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 12 Aug 2018 20:41:48 +0200 Subject: [PATCH 052/103] Mysterious fix for #8550 (#8561) Replacing the `for` body with a nkEmpty node is not the right thing to do. --- compiler/transf.nim | 7 ++----- tests/closure/t8550.nim | 12 ++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 tests/closure/t8550.nim diff --git a/compiler/transf.nim b/compiler/transf.nim index dae8d1ee6..c3bc29891 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -539,11 +539,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/tests/closure/t8550.nim b/tests/closure/t8550.nim new file mode 100644 index 000000000..153246f08 --- /dev/null +++ b/tests/closure/t8550.nim @@ -0,0 +1,12 @@ +discard """ + output: "@[\"42\"]" +""" + +proc chk_fail(): seq[string] = + iterator x(): int {.closure.} = yield 42 + proc f(cl: iterator(): int {.closure.}): seq[string] = + result = @[] + for i in cl(): result.add($i) + result = f(x) + +echo(chk_fail()) From 3cb963f1147b79a96f98373fe4db9c7da5717919 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 12 Aug 2018 20:43:30 +0200 Subject: [PATCH 053/103] Fixes 8616 (#8617) * Don't leave dangling forward references to types Fixes #8616 * Add a test case for #8616 --- compiler/ccgstmts.nim | 2 +- tests/ccgbugs/pkg8616/rtarray.nim | 2 ++ tests/ccgbugs/pkg8616/scheduler.nim | 10 ++++++++++ tests/ccgbugs/t8616.nim | 4 ++++ 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/ccgbugs/pkg8616/rtarray.nim create mode 100644 tests/ccgbugs/pkg8616/scheduler.nim create mode 100644 tests/ccgbugs/t8616.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 54759edb3..81e3fe4a7 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1130,8 +1130,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/tests/ccgbugs/pkg8616/rtarray.nim b/tests/ccgbugs/pkg8616/rtarray.nim new file mode 100644 index 000000000..286dbb8cd --- /dev/null +++ b/tests/ccgbugs/pkg8616/rtarray.nim @@ -0,0 +1,2 @@ +proc head*[T](pp: var array[1,T]): var T = + result = pp[0] diff --git a/tests/ccgbugs/pkg8616/scheduler.nim b/tests/ccgbugs/pkg8616/scheduler.nim new file mode 100644 index 000000000..0730000c4 --- /dev/null +++ b/tests/ccgbugs/pkg8616/scheduler.nim @@ -0,0 +1,10 @@ +import rtarray + +type + T = tuple[x:int] + +var + arr: array[1,T] + +proc init*() = + discard head(arr) diff --git a/tests/ccgbugs/t8616.nim b/tests/ccgbugs/t8616.nim new file mode 100644 index 000000000..54068652a --- /dev/null +++ b/tests/ccgbugs/t8616.nim @@ -0,0 +1,4 @@ +import pkg8616 / scheduler + +when isMainModule: + init() From e839c01f5b8b9fbe0d297be9d9bf8a429b49a1b1 Mon Sep 17 00:00:00 2001 From: Naveen Arunachalam Date: Sun, 12 Aug 2018 16:10:06 -0400 Subject: [PATCH 054/103] Clarify usage of "Test" argument in Koch (#8613) Minor change to help people (e.g. like myself) who are starting out :) Currently, the readme mentions the use of `./koch tests cat async`, but the help text for koch doesn't mention it. Helptexts are modified accordingly. --- koch.nim | 3 ++- tests/testament/tester.nim | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/koch.nim b/koch.nim index ad6a774e8..aa36d94a1 100644 --- a/koch.nim +++ b/koch.nim @@ -57,7 +57,8 @@ Commands for core developers: zip builds the installation zip package xz builds the installation tar.xz package testinstall test tar.xz package; Unix only! - tests [options] run the testsuite + tests [options] run the testsuite (run a subset of tests by + specifying a category, e.g. `tests cat async`) temp options creates a temporary compiler for testing winrelease creates a Windows release pushcsource push generated C sources to its repo diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index 136a509e4..9558257a6 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -22,7 +22,7 @@ const Command: all run all tests - c|category run all the tests of a certain category + c|cat|category run all the tests of a certain category r|run run single test file html generate $1 from the database Arguments: From 6a0751e81a31d08d8b31a434018176adcdd989d7 Mon Sep 17 00:00:00 2001 From: DrSlump Date: Mon, 13 Aug 2018 11:24:58 +0200 Subject: [PATCH 055/103] Fixes #7586: Adds documentation for hints --- doc/nimc.rst | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/doc/nimc.rst b/doc/nimc.rst index fca5b273c..9c81d912f 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -68,6 +68,46 @@ User Some user defined warning. ========================== ============================================ +List of hints +------------- + +Each hint can be activated individually with ``--hint[NAME]:on|off`` or in a +``push`` pragma. + +========================== ============================================ +Name Description +========================== ============================================ +CC Shows when the C compiler is called. +CodeBegin +CodeEnd +CondTrue +Conf A config file was loaded. +ConvToBaseNotNeeded +ConvFromXtoItselfNotNeeded +Dependency +Exec Program is executed. +ExprAlwaysX +ExtendedContext +GCStats Dumps statistics about the Garbage Collector. +GlobalVar Shows global variables declarations. +LineTooLong Line exceeds the maximum length. +Link Linking phase. +Name +Path Search paths modifications. +Pattern +Performance +Processing Artifact being compiled. +QuitCalled +Source The source line that triggered a diagnostic + message. +StackTrace +Success, SuccessX Successful compilation of a library or a binary. +User +UserRaw +XDeclaredButNotUsed Unused symbols in the code. +========================== ============================================ + + Verbosity levels ---------------- From dae5450947e93e2e5222ae2710874186bf27bf39 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 13 Aug 2018 11:41:33 +0200 Subject: [PATCH 056/103] WIP: disallow 'nil' for strings and seqs --- compiler/ast.nim | 12 ++++++-- compiler/ccgcalls.nim | 4 +-- compiler/ccgexprs.nim | 3 +- compiler/ccgmerge.nim | 2 +- compiler/commands.nim | 1 + compiler/condsyms.nim | 1 + compiler/docgen.nim | 15 +++++----- compiler/jsgen.nim | 4 +-- compiler/lineinfos.nim | 14 +++++----- compiler/lookups.nim | 2 +- compiler/msgs.nim | 8 +++--- compiler/options.nim | 3 +- compiler/parser.nim | 3 +- compiler/patterns.nim | 5 +++- compiler/renderer.nim | 16 +++++------ compiler/ropes.nim | 26 ++++++----------- compiler/scriptconfig.nim | 2 +- compiler/sem.nim | 2 +- compiler/semcall.nim | 6 ++-- compiler/semdata.nim | 7 +++-- compiler/seminst.nim | 7 ++--- compiler/semobjconstr.nim | 4 +-- compiler/semstmts.nim | 5 +++- compiler/semtypinst.nim | 4 +-- compiler/sigmatch.nim | 22 +++++++++++---- compiler/types.nim | 9 +++--- lib/impure/re.nim | 8 ++---- lib/packages/docutils/rstast.nim | 4 +-- lib/packages/docutils/rstgen.nim | 9 +++--- lib/pure/asyncfutures.nim | 4 +-- lib/pure/asyncnet.nim | 4 +-- lib/pure/collections/intsets.nim | 24 ++++++++++------ lib/pure/net.nim | 48 ++++++++++++++++---------------- lib/pure/parseopt2.nim | 6 ++-- lib/pure/parsexml.nim | 10 +++++-- lib/pure/pegs.nim | 2 +- lib/pure/streams.nim | 5 +++- lib/pure/unittest.nim | 13 ++++----- lib/pure/xmldom.nim | 24 ++++++++-------- lib/pure/xmldomparser.nim | 4 +-- lib/system.nim | 21 ++++++++++---- tests/async/tasync_misc.nim | 3 +- tests/async/tasyncssl.nim | 4 +-- 43 files changed, 207 insertions(+), 173 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index ef12e1184..7d8d098e3 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1150,7 +1150,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 @@ -1367,7 +1370,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 @@ -1592,7 +1595,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") diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 9712d5dce..2621574a6 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -431,7 +431,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: @@ -480,7 +480,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 e8bb70f13..dd1c72ab6 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -65,7 +65,8 @@ 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) + if n.strVal.len == 0 and optNilSeqs notin p.options: + result = genNilStringLiteral(p.module, n.info) else: result = genStringLiteral(p.module, n) else: 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/commands.nim b/compiler/commands.nim index 866405f9f..aae976038 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -496,6 +496,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 5a62b46ad..1f147b4a8 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -74,3 +74,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimVmExportFixed") defineSymbol("nimIncrSeqV3") defineSymbol("nimAshr") + defineSymbol("nimNoNilSeqs") 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/jsgen.nim b/compiler/jsgen.nim index 63100a68d..462c622aa 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1267,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) @@ -1350,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 4f0c3a778..c5a641713 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -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, hintSuccess, 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 bab631e6f..1e9d963fa 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -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/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/options.nim b/compiler/options.nim index 537a550f8..6de32bfad 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** 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..aa06342f9 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -209,7 +209,10 @@ 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 = @[] + else: + if not isNil(c.mapping): c.mapping = nil return false result = true 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/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..f3d6ccfdd 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: diff --git a/compiler/sem.nim b/compiler/sem.nim index 427b44e04..6128c02d1 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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)) 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/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/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 6ef03456e..b1e39d2db 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -970,7 +970,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/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 5afa1b031..b26d94c90 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 @@ -1253,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): @@ -1338,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: @@ -1349,7 +1355,11 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType, else: result = isEqual of tyNil: result = f.allowsNil - of tyString: result = isConvertible + of tyString: + if optNilSeqs in c.c.config.options or c.magic != mEqCString: + result = isConvertible + else: + result = isNone of tyPtr: # ptr[Tag, char] is not convertible to 'cstring' for now: if a.len == 1: @@ -1612,7 +1622,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: diff --git a/compiler/types.nim b/compiler/types.nim index 23fbc9f1b..8a120b609 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -428,7 +428,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: @@ -1528,10 +1528,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/lib/impure/re.nim b/lib/impure/re.nim index 201c490f3..50a5441e8 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -113,7 +113,7 @@ proc matchOrFind(buf: cstring, pattern: Regex, matches: var openArray[string], var b = rawMatches[i * 2 + 1] if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b)) - else: matches[i-1] = nil + else: matches[i-1] = "" return rawMatches[1] - rawMatches[0] proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string], @@ -133,7 +133,7 @@ proc findBounds*(buf: cstring, pattern: Regex, matches: var openArray[string], var a = rawMatches[i * 2] var b = rawMatches[i * 2 + 1] if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b)) - else: matches[i-1] = nil + else: matches[i-1] = "" return (rawMatches[0].int, rawMatches[1].int - 1) proc findBounds*(s: string, pattern: Regex, matches: var openArray[string], @@ -287,7 +287,7 @@ proc find*(buf: cstring, pattern: Regex, matches: var openArray[string], var a = rawMatches[i * 2] var b = rawMatches[i * 2 + 1] if a >= 0'i32: matches[i-1] = bufSubstr(buf, int(a), int(b)) - else: matches[i-1] = nil + else: matches[i-1] = "" return rawMatches[0] proc find*(s: string, pattern: Regex, matches: var openArray[string], @@ -456,8 +456,6 @@ proc replacef*(s: string, sub: Regex, by: string): string = while true: var match = findBounds(s, sub, caps, prev) if match.first < 0: break - assert result != nil - assert s != nil add(result, substr(s, prev, match.first-1)) addf(result, by, caps) prev = match.last + 1 diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index f3596b571..4a77b4f34 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -293,9 +293,9 @@ proc renderRstToJsonNode(node: PRstNode): JsonNode = (key: "kind", val: %($node.kind)), (key: "level", val: %BiggestInt(node.level)) ] - if node.text != nil: + if node.text.len > 0: result.add("text", %node.text) - if node.sons != nil and len(node.sons) > 0: + if len(node.sons) > 0: var accm = newSeq[JsonNode](len(node.sons)) for i, son in node.sons: accm[i] = renderRstToJsonNode(son) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index db9a83755..5b0b6c6ee 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -397,9 +397,9 @@ proc hash(x: IndexEntry): Hash = proc `<-`(a: var IndexEntry, b: IndexEntry) = shallowCopy a.keyword, b.keyword shallowCopy a.link, b.link - if b.linkTitle.isNil: a.linkTitle = nil + if b.linkTitle.isNil: a.linkTitle = "" else: shallowCopy a.linkTitle, b.linkTitle - if b.linkDesc.isNil: a.linkDesc = nil + if b.linkDesc.isNil: a.linkDesc = "" else: shallowCopy a.linkDesc, b.linkDesc proc sortIndex(a: var openArray[IndexEntry]) = @@ -607,8 +607,8 @@ proc readIndexDir(dir: string): fileEntries[F].linkTitle = extraCols[1].unquoteIndexColumn fileEntries[F].linkDesc = extraCols[2].unquoteIndexColumn else: - fileEntries[F].linkTitle = nil - fileEntries[F].linkDesc = nil + fileEntries[F].linkTitle = "" + fileEntries[F].linkDesc = "" inc F # Depending on type add this to the list of symbols or table of APIs. if title.keyword.isNil: @@ -656,7 +656,6 @@ proc mergeIndexes*(dir: string): string = ## Returns the merged and sorted indices into a single HTML block which can ## be further embedded into nimdoc templates. var (modules, symbols, docs) = readIndexDir(dir) - assert(not symbols.isNil) result = "" # Generate a quick jump list of documents. diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim index 863a6843b..5bf9183ed 100644 --- a/lib/pure/asyncfutures.nim +++ b/lib/pure/asyncfutures.nim @@ -219,10 +219,10 @@ proc getHint(entry: StackTraceEntry): string = ## We try to provide some hints about stack trace entries that the user ## may not be familiar with, in particular calls inside the stdlib. result = "" - if entry.procname == "processPendingCallbacks": + if entry.procname == cstring"processPendingCallbacks": if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0: return "Executes pending callbacks" - elif entry.procname == "poll": + elif entry.procname == cstring"poll": if cmpIgnoreStyle(entry.filename, "asyncdispatch.nim") == 0: return "Processes asynchronous completion events" diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index da7c3473c..71a1600dc 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -655,7 +655,7 @@ when defineSsl: proc wrapConnectedSocket*(ctx: SslContext, socket: AsyncSocket, handshake: SslHandshakeType, - hostname: string = nil) = + hostname: string = "") = ## Wraps a connected socket in an SSL context. This function effectively ## turns ``socket`` into an SSL socket. ## ``hostname`` should be specified so that the client knows which hostname @@ -670,7 +670,7 @@ when defineSsl: case handshake of handshakeAsClient: - if not hostname.isNil and not isIpAddress(hostname): + if hostname.len > 0 and not isIpAddress(hostname): # Set the SNI address for this connection. This call can fail if # we're not using TLSv1+. discard SSL_set_tlsext_host_name(socket.sslHandle, hostname) diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index bfecfe447..545958977 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -184,7 +184,7 @@ proc missingOrExcl*(s: var IntSet, key: int) : bool = ## `key` is removed from `s` and false is returned. var count = s.elems exclImpl(s, key) - result = count == s.elems + result = count == s.elems proc containsOrIncl*(s: var IntSet, key: int): bool = ## returns true if `s` contains `key`, otherwise `key` is included in `s` @@ -212,7 +212,10 @@ proc initIntSet*: IntSet = #newSeq(result.data, InitIntSetSize) #result.max = InitIntSetSize-1 - result.data = nil + when defined(nimNoNilSeqs): + result.data = @[] + else: + result.data = nil result.max = 0 result.counter = 0 result.head = nil @@ -222,7 +225,10 @@ proc clear*(result: var IntSet) = #setLen(result.data, InitIntSetSize) #for i in 0..InitIntSetSize-1: result.data[i] = nil #result.max = InitIntSetSize-1 - result.data = nil + when defined(nimNoNilSeqs): + result.data = @[] + else: + result.data = nil result.max = 0 result.counter = 0 result.head = nil @@ -234,7 +240,10 @@ proc assign*(dest: var IntSet, src: IntSet) = ## copies `src` to `dest`. `dest` does not need to be initialized by ## `initIntSet`. if src.elems <= src.a.len: - dest.data = nil + when defined(nimNoNilSeqs): + dest.data = @[] + else: + dest.data = nil dest.max = 0 dest.counter = src.counter dest.head = nil @@ -247,11 +256,9 @@ proc assign*(dest: var IntSet, src: IntSet) = var it = src.head while it != nil: - var h = it.key and dest.max while dest.data[h] != nil: h = nextTry(h, dest.max) assert(dest.data[h] == nil) - var n: PTrunk new(n) n.next = dest.head @@ -259,7 +266,6 @@ proc assign*(dest: var IntSet, src: IntSet) = n.bits = it.bits dest.head = n dest.data[h] = n - it = it.next proc union*(s1, s2: IntSet): IntSet = @@ -315,7 +321,7 @@ proc len*(s: IntSet): int {.inline.} = for _ in s: inc(result) -proc card*(s: IntSet): int {.inline.} = +proc card*(s: IntSet): int {.inline.} = ## alias for `len() <#len>` _. result = s.len() @@ -361,7 +367,7 @@ when isMainModule: x.incl(1056) x.incl(1044) - x.excl(1044) + x.excl(1044) assert x.containsOrIncl(888) == false assert 888 in x diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 771e7de10..0e56100d9 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -231,7 +231,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, raiseOSError(osLastError()) result = newSocket(fd, domain, sockType, protocol, buffered) -proc parseIPv4Address(address_str: string): IpAddress = +proc parseIPv4Address(addressStr: string): IpAddress = ## Parses IPv4 adresses ## Raises EInvalidValue on errors var @@ -241,15 +241,15 @@ proc parseIPv4Address(address_str: string): IpAddress = result.family = IpAddressFamily.IPv4 - for i in 0 .. high(address_str): - if address_str[i] in strutils.Digits: # Character is a number + for i in 0 .. high(addressStr): + if addressStr[i] in strutils.Digits: # Character is a number currentByte = currentByte * 10 + - cast[uint16](ord(address_str[i]) - ord('0')) + cast[uint16](ord(addressStr[i]) - ord('0')) if currentByte > 255'u16: raise newException(ValueError, "Invalid IP Address. Value is out of range") seperatorValid = true - elif address_str[i] == '.': # IPv4 address separator + elif addressStr[i] == '.': # IPv4 address separator if not seperatorValid or byteCount >= 3: raise newException(ValueError, "Invalid IP Address. The address consists of too many groups") @@ -265,11 +265,11 @@ proc parseIPv4Address(address_str: string): IpAddress = raise newException(ValueError, "Invalid IP Address") result.address_v4[byteCount] = cast[uint8](currentByte) -proc parseIPv6Address(address_str: string): IpAddress = +proc parseIPv6Address(addressStr: string): IpAddress = ## Parses IPv6 adresses ## Raises EInvalidValue on errors result.family = IpAddressFamily.IPv6 - if address_str.len < 2: + if addressStr.len < 2: raise newException(ValueError, "Invalid IP Address") var @@ -282,7 +282,7 @@ proc parseIPv6Address(address_str: string): IpAddress = v4StartPos = -1 byteCount = 0 - for i,c in address_str: + for i,c in addressStr: if c == ':': if not seperatorValid: raise newException(ValueError, @@ -293,7 +293,7 @@ proc parseIPv6Address(address_str: string): IpAddress = "Invalid IP Address. Address contains more than one \"::\" seperator") dualColonGroup = groupCount seperatorValid = false - elif i != 0 and i != high(address_str): + elif i != 0 and i != high(addressStr): if groupCount >= 8: raise newException(ValueError, "Invalid IP Address. The address consists of too many groups") @@ -303,11 +303,11 @@ proc parseIPv6Address(address_str: string): IpAddress = groupCount.inc() if dualColonGroup != -1: seperatorValid = false elif i == 0: # only valid if address starts with :: - if address_str[1] != ':': + if addressStr[1] != ':': raise newException(ValueError, "Invalid IP Address. Address may not start with \":\"") - else: # i == high(address_str) - only valid if address ends with :: - if address_str[high(address_str)-1] != ':': + else: # i == high(addressStr) - only valid if address ends with :: + if addressStr[high(addressStr)-1] != ':': raise newException(ValueError, "Invalid IP Address. Address may not end with \":\"") lastWasColon = true @@ -345,7 +345,7 @@ proc parseIPv6Address(address_str: string): IpAddress = result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF) groupCount.inc() else: # Must parse IPv4 address - for i,c in address_str[v4StartPos..high(address_str)]: + for i,c in addressStr[v4StartPos..high(addressStr)]: if c in strutils.Digits: # Character is a number currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0')) if currentShort > 255'u32: @@ -386,21 +386,21 @@ proc parseIPv6Address(address_str: string): IpAddress = raise newException(ValueError, "Invalid IP Address. The address consists of too many groups") -proc parseIpAddress*(address_str: string): IpAddress = +proc parseIpAddress*(addressStr: string): IpAddress = ## Parses an IP address ## Raises EInvalidValue on error - if address_str == nil: - raise newException(ValueError, "IP Address string is nil") - if address_str.contains(':'): - return parseIPv6Address(address_str) + if addressStr.len == 0: + raise newException(ValueError, "IP Address string is empty") + if addressStr.contains(':'): + return parseIPv6Address(addressStr) else: - return parseIPv4Address(address_str) + return parseIPv4Address(addressStr) -proc isIpAddress*(address_str: string): bool {.tags: [].} = +proc isIpAddress*(addressStr: string): bool {.tags: [].} = ## Checks if a string is an IP address ## Returns true if it is, false otherwise try: - discard parseIpAddress(address_str) + discard parseIpAddress(addressStr) except ValueError: return false return true @@ -587,7 +587,7 @@ when defineSsl: proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar; max_psk_len: cuint): cuint {.cdecl.} = let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX) - let hintString = if hint == nil: nil else: $hint + let hintString = if hint == nil: "" else: $hint let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString) if psk.len.cuint > max_psk_len: return 0 @@ -657,7 +657,7 @@ when defineSsl: proc wrapConnectedSocket*(ctx: SSLContext, socket: Socket, handshake: SslHandshakeType, - hostname: string = nil) = + hostname: string = "") = ## Wraps a connected socket in an SSL context. This function effectively ## turns ``socket`` into an SSL socket. ## ``hostname`` should be specified so that the client knows which hostname @@ -671,7 +671,7 @@ when defineSsl: wrapSocket(ctx, socket) case handshake of handshakeAsClient: - if not hostname.isNil and not isIpAddress(hostname): + if hostname.len > 0 and not isIpAddress(hostname): # Discard result in case OpenSSL version doesn't support SNI, or we're # not using TLSv1+ discard SSL_set_tlsext_host_name(socket.sslHandle, hostname) diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim index b54a56c0c..51a70b6d1 100644 --- a/lib/pure/parseopt2.nim +++ b/lib/pure/parseopt2.nim @@ -44,10 +44,10 @@ type proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} = ## Initalizes option parses with cmdline. cmdline should not contain ## argument 0 - program name. - ## If cmdline == nil default to current command line arguments. + ## If cmdline.len == 0 default to current command line arguments. result.remainingShortOptions = "" when not defined(createNimRtl): - if cmdline == nil: + if cmdline.len == 0: result.cmd = commandLineParams() return else: @@ -60,7 +60,7 @@ proc initOptParser*(cmdline: string): OptParser {.rtl, deprecated.} = ## and calls initOptParser(openarray[string]) ## Do not use. if cmdline == "": # backward compatibility - return initOptParser(seq[string](nil)) + return initOptParser(@[]) else: return initOptParser(cmdline.split) diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index e0000aad3..fe933fb79 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -95,6 +95,7 @@ type kind: XmlEventKind err: XmlErrorKind state: ParserState + cIsEmpty: bool filename: string options: set[XmlParseOption] @@ -125,7 +126,8 @@ proc open*(my: var XmlParser, input: Stream, filename: string, my.kind = xmlError my.a = "" my.b = "" - my.c = nil + my.c = "" + my.cIsEmpty = true my.options = options proc close*(my: var XmlParser) {.inline.} = @@ -482,6 +484,7 @@ proc parseTag(my: var XmlParser) = my.kind = xmlElementOpen my.state = stateAttr my.c = my.a # save for later + my.cIsEmpty = false else: my.kind = xmlElementStart let slash = my.buf[my.bufpos] == '/' @@ -490,7 +493,8 @@ proc parseTag(my: var XmlParser) = if slash and my.buf[my.bufpos] == '>': inc(my.bufpos) my.state = stateEmptyElementTag - my.c = nil + my.c = "" + my.cIsEmpty = true elif my.buf[my.bufpos] == '>': inc(my.bufpos) else: @@ -678,7 +682,7 @@ proc next*(my: var XmlParser) = of stateEmptyElementTag: my.state = stateNormal my.kind = xmlElementEnd - if not my.c.isNil: + if not my.cIsEmpty: my.a = my.c of stateError: my.kind = xmlError diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index d16527a56..b22016a3a 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -765,7 +765,7 @@ template fillMatches(s, caps, c) = if startIdx != -1: caps[k] = substr(s, startIdx, endIdx) else: - caps[k] = nil + caps[k] = "" proc matchLen*(s: string, pattern: Peg, matches: var openArray[string], start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} = diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 1ab73faea..09626136f 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -377,7 +377,10 @@ when not defined(js): proc ssClose(s: Stream) = var s = StringStream(s) - s.data = nil + when defined(nimNoNilSeqs): + s.data = "" + else: + s.data = nil proc newStringStream*(s: string = ""): StringStream = ## creates a new stream from the string `s`. diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index aa07a4fa6..f4b89b2d0 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -176,10 +176,7 @@ method suiteEnded*(formatter: OutputFormatter) {.base, gcsafe.} = discard proc addOutputFormatter*(formatter: OutputFormatter) = - if formatters == nil: - formatters = @[formatter] - else: - formatters.add(formatter) + formatters.add(formatter) proc newConsoleOutputFormatter*(outputLevel: OutputLevel = PRINT_ALL, colorOutput = true): ConsoleOutputFormatter = @@ -225,7 +222,7 @@ method testStarted*(formatter: ConsoleOutputFormatter, testName: string) = formatter.isInTest = true method failureOccurred*(formatter: ConsoleOutputFormatter, checkpoints: seq[string], stackTrace: string) = - if stackTrace != nil: + if stackTrace.len > 0: echo stackTrace let prefix = if formatter.isInSuite: " " else: "" for msg in items(checkpoints): @@ -236,7 +233,7 @@ method testEnded*(formatter: ConsoleOutputFormatter, testResult: TestResult) = if formatter.outputLevel != PRINT_NONE and (formatter.outputLevel == PRINT_ALL or testResult.status == FAILED): - let prefix = if testResult.suiteName != nil: " " else: "" + let prefix = if testResult.suiteName.len > 0: " " else: "" template rawPrint() = echo(prefix, "[", $testResult.status, "] ", testResult.testName) when not defined(ECMAScript): if formatter.colorOutput and not defined(ECMAScript): @@ -301,7 +298,7 @@ method failureOccurred*(formatter: JUnitOutputFormatter, checkpoints: seq[string ## ``stackTrace`` is provided only if the failure occurred due to an exception. ## ``checkpoints`` is never ``nil``. formatter.testErrors.add(checkpoints) - if stackTrace != nil: + if stackTrace.len > 0: formatter.testStackTrace = stackTrace method testEnded*(formatter: JUnitOutputFormatter, testResult: TestResult) = @@ -392,7 +389,7 @@ proc shouldRun(currentSuiteName, testName: string): bool = return false proc ensureInitialized() = - if formatters == nil: + if formatters.len == 0: formatters = @[OutputFormatter(defaultConsoleFormatter())] if not disabledParamFiltering and not testsFilters.isValid: diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim index 8cd47aa39..1a9e4ae26 100644 --- a/lib/pure/xmldom.nim +++ b/lib/pure/xmldom.nim @@ -217,9 +217,9 @@ proc createAttribute*(doc: PDocument, name: string): PAttr = new(attrNode) attrNode.fName = name attrNode.fNodeName = name - attrNode.fLocalName = nil - attrNode.prefix = nil - attrNode.fNamespaceURI = nil + attrNode.fLocalName = "" + attrNode.prefix = "" + attrNode.fNamespaceURI = "" attrNode.value = "" attrNode.fSpecified = false return attrNode @@ -254,7 +254,7 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str attrNode.prefix = qualifiedName.split(':')[0] attrNode.fLocalName = qualifiedName.split(':')[1] else: - attrNode.prefix = nil + attrNode.prefix = "" attrNode.fLocalName = qualifiedName attrNode.value = "" @@ -298,9 +298,9 @@ proc createElement*(doc: PDocument, tagName: string): PElement = new(elNode) elNode.fTagName = tagName elNode.fNodeName = tagName - elNode.fLocalName = nil - elNode.prefix = nil - elNode.fNamespaceURI = nil + elNode.fLocalName = "" + elNode.prefix = "" + elNode.fNamespaceURI = "" elNode.childNodes = @[] elNode.attributes = @[] @@ -332,7 +332,7 @@ proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: strin elNode.prefix = qualifiedName.split(':')[0] elNode.fLocalName = qualifiedName.split(':')[1] else: - elNode.prefix = nil + elNode.prefix = "" elNode.fLocalName = qualifiedName elNode.fNamespaceURI = namespaceURI elNode.childNodes = @[] @@ -893,22 +893,22 @@ proc tagName*(el: PElement): string = proc getAttribute*(el: PNode, name: string): string = ## Retrieves an attribute value by ``name`` if isNil(el.attributes): - return nil + return "" var attribute = el.attributes.getNamedItem(name) if not isNil(attribute): return attribute.value else: - return nil + return "" proc getAttributeNS*(el: PNode, namespaceURI: string, localName: string): string = ## Retrieves an attribute value by ``localName`` and ``namespaceURI`` if isNil(el.attributes): - return nil + return "" var attribute = el.attributes.getNamedItemNS(namespaceURI, localName) if not isNil(attribute): return attribute.value else: - return nil + return "" proc getAttributeNode*(el: PElement, name: string): PAttr = ## Retrieves an attribute node by ``name`` diff --git a/lib/pure/xmldomparser.nim b/lib/pure/xmldomparser.nim index 7c7f7b99c..8d995102e 100644 --- a/lib/pure/xmldomparser.nim +++ b/lib/pure/xmldomparser.nim @@ -119,7 +119,7 @@ proc loadXMLStream*(stream: Stream): PDocument = ## a ``PDocument`` var x: XmlParser - open(x, stream, nil, {reportComments}) + open(x, stream, "", {reportComments}) var xmlDoc: PDocument var dom: PDOMImplementation = getDOM() @@ -161,7 +161,7 @@ when not defined(testing) and isMainModule: #echo(xml.getElementsByTagName("bla:test")[0].namespaceURI) #echo(xml.getElementsByTagName("test")[0].namespaceURI) for i in items(xml.getElementsByTagName("*")): - if i.namespaceURI != nil: + if i.namespaceURI.len > 0: echo(i.nodeName, "=", i.namespaceURI) diff --git a/lib/system.nim b/lib/system.nim index b92dd58d6..4b69a8067 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -3963,19 +3963,28 @@ when hasAlloc: proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect, deprecated.} = ## Adds ``y`` to ``x`` unless ``x`` is not yet initialized; in that case, ## ``x`` becomes ``@[y]`` - if x == nil: x = @[y] - else: x.add(y) + when defined(nimNoNilSeqs): + x.add(y) + else: + if x == nil: x = @[y] + else: x.add(y) proc safeAdd*(x: var string, y: char) {.noSideEffect, deprecated.} = ## Adds ``y`` to ``x``. If ``x`` is ``nil`` it is initialized to ``""`` - if x == nil: x = "" - x.add(y) + when defined(nimNoNilSeqs): + x.add(y) + else: + if x == nil: x = "" + x.add(y) proc safeAdd*(x: var string, y: string) {.noSideEffect, deprecated.} = ## Adds ``y`` to ``x`` unless ``x`` is not yet initalized; in that ## case, ``x`` becomes ``y`` - if x == nil: x = y - else: x.add(y) + when defined(nimNoNilSeqs): + x.add(y) + else: + if x == nil: x = y + else: x.add(y) proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} = ## generates a tuple constructor expression listing all the local variables diff --git a/tests/async/tasync_misc.nim b/tests/async/tasync_misc.nim index 695dcd98a..dbc2ea434 100644 --- a/tests/async/tasync_misc.nim +++ b/tests/async/tasync_misc.nim @@ -37,8 +37,7 @@ block: #8399 case line[0] of '+', '-': @[] of '$': (let x = await bar(); @[""]) - else: - nil + else: @[] doAssert(res == @[""]) diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim index 3dc131036..0607cf3c6 100644 --- a/tests/async/tasyncssl.nim +++ b/tests/async/tasyncssl.nim @@ -15,11 +15,11 @@ when defined(ssl): var clientCount = 0 proc sendMessages(client: AsyncSocket) {.async.} = - for i in 0 .. Date: Mon, 13 Aug 2018 11:42:50 +0200 Subject: [PATCH 057/103] Fixed 7478: splitLines keepEol option (#8621) --- lib/pure/strutils.nim | 33 +++++++++++++++++++++------------ tests/stdlib/tstrutil.nim | 9 ++++++++- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index f8c5f9a91..be7ff60a2 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -624,12 +624,13 @@ iterator rsplit*(s: string, sep: string, maxsplit: int = -1, ## Substrings are separated from the right by the string `sep` rsplitCommon(s, sep, maxsplit, sep.len) -iterator splitLines*(s: string): string = +iterator splitLines*(s: string, keepEol = false): string = ## Splits the string `s` into its containing lines. ## ## Every `character literal `_ newline ## combination (CR, LF, CR-LF) is supported. The result strings contain no - ## trailing ``\n``. + ## trailing end of line characters unless parameter ``keepEol`` is set to + ## ``true``. ## ## Example: ## @@ -649,22 +650,30 @@ iterator splitLines*(s: string): string = ## "" var first = 0 var last = 0 + var eolpos = 0 while true: while last < s.len and s[last] notin {'\c', '\l'}: inc(last) - yield substr(s, first, last-1) - # skip newlines: - if last >= s.len: break - if s[last] == '\l': inc(last) - elif s[last] == '\c': - inc(last) - if last < s.len and s[last] == '\l': inc(last) + + eolpos = last + if last < s.len: + if s[last] == '\l': inc(last) + elif s[last] == '\c': + inc(last) + if last < s.len and s[last] == '\l': inc(last) + + yield substr(s, first, if keepEol: last-1 else: eolpos-1) + + # no eol characters consumed means that the string is over + if eolpos == last: + break + first = last -proc splitLines*(s: string): seq[string] {.noSideEffect, +proc splitLines*(s: string, keepEol = false): seq[string] {.noSideEffect, rtl, extern: "nsuSplitLines".} = ## The same as the `splitLines <#splitLines.i,string>`_ iterator, but is a ## proc that returns a sequence of substrings. - accumulateResult(splitLines(s)) + accumulateResult(splitLines(s, keepEol=keepEol)) proc countLines*(s: string): int {.noSideEffect, rtl, extern: "nsuCountLines".} = @@ -908,7 +917,7 @@ proc parseOctInt*(s: string): int {.noSideEffect, ## `s` are ignored. let L = parseutils.parseOct(s, result, 0) if L != s.len or L == 0: - raise newException(ValueError, "invalid oct integer: " & s) + raise newException(ValueError, "invalid oct integer: " & s) proc parseHexInt*(s: string): int {.noSideEffect, procvar, rtl, extern: "nsuParseHexInt".} = diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index 4d4081d39..f0ee755f7 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -199,6 +199,12 @@ proc testRFind = assert "0123456789ABCDEFGAH".rfind({'A'..'C'}, 13) == 12 assert "0123456789ABCDEFGAH".rfind({'G'..'H'}, 13) == -1 +proc testSplitLines() = + let fixture = "a\nb\rc\r\nd" + assert len(fixture.splitLines) == 4 + assert splitLines(fixture) == @["a", "b", "c", "d"] + assert splitLines(fixture, keepEol=true) == @["a\n", "b\r", "c\r\n", "d"] + proc testCountLines = proc assertCountLines(s: string) = assert s.countLines == s.splitLines.len assertCountLines("") @@ -229,7 +235,7 @@ proc testParseInts = assert "72".parseHexInt == 114 assert "FF".parseHexInt == 255 assert "ff".parseHexInt == 255 - assert "fF".parseHexInt == 255 + assert "fF".parseHexInt == 255 assert "0x7_2".parseHexInt == 114 rejectParse "".parseHexInt rejectParse "_".parseHexInt @@ -252,6 +258,7 @@ proc testParseInts = testDelete() testFind() testRFind() +testSplitLines() testCountLines() testParseInts() From 7f49364fd073072c4db42428b1f67873a6e26d24 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 13 Aug 2018 12:29:03 +0200 Subject: [PATCH 058/103] make more tests green --- lib/impure/nre.nim | 12 ++-- lib/impure/nre/private/util.nim | 6 +- lib/pure/httpclient.nim | 2 +- lib/pure/json.nim | 2 +- lib/pure/pegs.nim | 2 +- lib/pure/ropes.nim | 69 ++----------------- lib/pure/unittest.nim | 4 +- lib/system/jssys.nim | 2 +- nimsuggest/nimsuggest.nim | 6 +- .../argument_parser/argument_parser.nim | 10 +-- tests/manyloc/keineschweine/lib/sg_assets.nim | 4 +- tests/manyloc/keineschweine/lib/sg_gui.nim | 4 +- tests/stdlib/nre/captures.nim | 6 +- tests/stdlib/nre/replace.nim | 4 +- tests/stdlib/tjsonmacro.nim | 4 +- tests/stdlib/tnilecho.nim | 4 +- 16 files changed, 39 insertions(+), 102 deletions(-) diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim index 889210f62..32b1d0255 100644 --- a/lib/impure/nre.nim +++ b/lib/impure/nre.nim @@ -267,7 +267,7 @@ proc `[]`*(pattern: Captures, i: int): string = let bounds = bounds.get return pattern.str.substr(bounds.a, bounds.b) else: - return nil + return "" proc match*(pattern: RegexMatch): string = return pattern.captures[-1] @@ -291,9 +291,9 @@ template toTableImpl(cond: untyped) {.dirty.} = else: result[key] = nextVal -proc toTable*(pattern: Captures, default: string = nil): Table[string, string] = +proc toTable*(pattern: Captures, default: string = ""): Table[string, string] = result = initTable[string, string]() - toTableImpl(nextVal == nil) + toTableImpl(nextVal.len == 0) proc toTable*(pattern: CaptureBounds, default = none(HSlice[int, int])): Table[string, Option[HSlice[int, int]]] = @@ -312,13 +312,13 @@ template itemsImpl(cond: untyped) {.dirty.} = iterator items*(pattern: CaptureBounds, default = none(HSlice[int, int])): Option[HSlice[int, int]] = itemsImpl(nextVal.isNone) -iterator items*(pattern: Captures, default: string = nil): string = - itemsImpl(nextVal == nil) +iterator items*(pattern: Captures, default: string = ""): string = + itemsImpl(nextVal.len == 0) proc toSeq*(pattern: CaptureBounds, default = none(HSlice[int, int])): seq[Option[HSlice[int, int]]] = accumulateResult(pattern.items(default)) -proc toSeq*(pattern: Captures, default: string = nil): seq[string] = +proc toSeq*(pattern: Captures, default: string = ""): seq[string] = accumulateResult(pattern.items(default)) proc `$`*(pattern: RegexMatch): string = diff --git a/lib/impure/nre/private/util.nim b/lib/impure/nre/private/util.nim index 12d2506ea..a3ae84007 100644 --- a/lib/impure/nre/private/util.nim +++ b/lib/impure/nre/private/util.nim @@ -10,11 +10,7 @@ proc fget*[K, V](self: Table[K, V], key: K): V = const Ident = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'} const StartIdent = Ident - {'0'..'9'} -proc checkNil(arg: string): string = - if arg == nil: - raise newException(ValueError, "Cannot use nil capture") - else: - return arg +template checkNil(arg: string): string = arg template formatStr*(howExpr, namegetter, idgetter): untyped = let how = howExpr diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 72de72718..a98779db3 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -457,7 +457,7 @@ proc `[]=`*(p: var MultipartData, name: string, p.add(name, file.content, file.name, file.contentType) proc format(p: MultipartData): tuple[contentType, body: string] = - if p == nil or p.content == nil or p.content.len == 0: + if p == nil or p.content.len == 0: return ("", "") # Create boundary that is not in the data to be formatted diff --git a/lib/pure/json.nim b/lib/pure/json.nim index b9279b18c..69ffb1796 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1144,7 +1144,7 @@ proc processType(typeName: NimNode, obj: NimNode, result = quote do: ( verifyJsonKind(`jsonNode`, {JString, JNull}, astToStr(`jsonNode`)); - if `jsonNode`.kind == JNull: nil else: `jsonNode`.str + if `jsonNode`.kind == JNull: "" else: `jsonNode`.str ) of "biggestint": result = quote do: diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index b22016a3a..02a2d6900 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -1854,7 +1854,7 @@ when isMainModule: assert match("prefix/start", peg"^start$", 7) if "foo" =~ peg"{'a'}?.*": - assert matches[0] == nil + assert matches[0].len == 0 else: assert false if "foo" =~ peg"{''}.*": diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 9b9cdb52a..fb371cdce 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -37,7 +37,7 @@ type length: int data: string # != nil if a leaf -proc isConc(r: Rope): bool {.inline.} = return isNil(r.data) +proc isConc(r: Rope): bool {.inline.} = return r.length > 0 # Note that the left and right pointers are not needed for leafs. # Leaves have relatively high memory overhead (~30 bytes on a 32 @@ -50,12 +50,12 @@ proc isConc(r: Rope): bool {.inline.} = return isNil(r.data) proc len*(a: Rope): int {.rtl, extern: "nro$1".} = ## the rope's length if a == nil: result = 0 - else: result = a.length + else: result = abs a.length proc newRope(): Rope = new(result) proc newRope(data: string): Rope = new(result) - result.length = len(data) + result.length = -len(data) result.data = data var @@ -129,7 +129,7 @@ proc insertInCache(s: string, tree: Rope): Rope = result.left = t t.right = nil -proc rope*(s: string = nil): Rope {.rtl, extern: "nro$1Str".} = +proc rope*(s: string = ""): Rope {.rtl, extern: "nro$1Str".} = ## Converts a string to a rope. if s.len == 0: result = nil @@ -170,17 +170,7 @@ proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} = result = a else: result = newRope() - result.length = a.length + b.length - when false: - # XXX rebalancing would be nice, but is too expensive. - result.left = a.left - var x = newRope() - x.left = a.right - x.right = b - result.right = x - else: - result.left = a - result.right = b + result.length = abs(a.length) + abs(b.length) proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} = ## the concatenation operator for ropes. @@ -229,7 +219,6 @@ iterator leaves*(r: Rope): string = stack.add(it.right) it = it.left assert(it != nil) - assert(it.data != nil) yield it.data iterator items*(r: Rope): char = @@ -250,54 +239,6 @@ proc `$`*(r: Rope): string {.rtl, extern: "nroToString".}= result = newStringOfCap(r.len) for s in leaves(r): add(result, s) -when false: - # Format string caching seems reasonable: All leaves can be shared and format - # string parsing has to be done only once. A compiled format string is stored - # as a rope. A negative length is used for the index into the args array. - proc compiledArg(idx: int): Rope = - new(result) - result.length = -idx - - proc compileFrmt(frmt: string): Rope = - var i = 0 - var length = len(frmt) - result = nil - var num = 0 - while i < length: - if frmt[i] == '$': - inc(i) - case frmt[i] - of '$': - add(result, "$") - inc(i) - of '#': - inc(i) - add(result, compiledArg(num+1)) - inc(num) - of '0'..'9': - var j = 0 - while true: - j = j * 10 + ord(frmt[i]) - ord('0') - inc(i) - if frmt[i] notin {'0'..'9'}: break - add(s, compiledArg(j)) - of '{': - inc(i) - var j = 0 - while frmt[i] in {'0'..'9'}: - j = j * 10 + ord(frmt[i]) - ord('0') - inc(i) - if frmt[i] == '}': inc(i) - else: raise newException(EInvalidValue, "invalid format string") - add(s, compiledArg(j)) - else: raise newException(EInvalidValue, "invalid format string") - var start = i - while i < length: - if frmt[i] != '$': inc(i) - else: break - if i - 1 >= start: - add(result, substr(frmt, start, i-1)) - proc `%`*(frmt: string, args: openArray[Rope]): Rope {. rtl, extern: "nroFormat".} = ## `%` substitution operator for ropes. Does not support the ``$identifier`` diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index f4b89b2d0..757bf4745 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -504,7 +504,7 @@ template test*(name, body) {.dirty.} = if testStatusIMPL == FAILED: programResult += 1 let testResult = TestResult( - suiteName: when declared(testSuiteName): testSuiteName else: nil, + suiteName: when declared(testSuiteName): testSuiteName else: "", testName: name, status: testStatusIMPL ) @@ -552,7 +552,7 @@ template fail* = when declared(stackTrace): formatter.failureOccurred(checkpoints, stackTrace) else: - formatter.failureOccurred(checkpoints, nil) + formatter.failureOccurred(checkpoints, "") when not defined(ECMAScript): if abortOnError: quit(programResult) diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index e12bab184..8d4a2e482 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -110,7 +110,7 @@ proc getStackTrace*(e: ref Exception): string = e.trace proc unhandledException(e: ref Exception) {. compilerproc, asmNoStackFrame.} = var buf = "" - if e.msg != nil and e.msg[0] != '\0': + if e.msg.len != 0: add(buf, "Error: unhandled exception: ") add(buf, e.msg) else: diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 3ba1120b2..4b5ce0a57 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -109,7 +109,7 @@ proc sexp(s: IdeCmd|TSymKind|PrefixMatch): SexpNode = sexp($s) proc sexp(s: Suggest): SexpNode = # If you change the order here, make sure to change it over in # nim-mode.el too. - let qp = if s.qualifiedPath.isNil: @[] else: s.qualifiedPath + let qp = if s.qualifiedPath.len == 0: @[] else: s.qualifiedPath result = convertSexp([ s.section, TSymKind s.symkind, @@ -176,7 +176,7 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int; let dirtyIdx = fileInfoIdx(conf, file, isKnownFile) if dirtyfile.len != 0: msgs.setDirtyFile(conf, dirtyIdx, dirtyfile) - else: msgs.setDirtyFile(conf, dirtyIdx, nil) + else: msgs.setDirtyFile(conf, dirtyIdx, "") conf.m.trackPos = newLineInfo(dirtyIdx, line, col) conf.m.trackPosAttached = false @@ -209,7 +209,7 @@ proc executeEpc(cmd: IdeCmd, args: SexpNode; column = args[2].getNum var dirtyfile = "" if len(args) > 3: - dirtyfile = args[3].getStr(nil) + dirtyfile = args[3].getStr("") execute(cmd, file, dirtyfile, int(line), int(column), graph) proc returnEpc(socket: Socket, uid: BiggestInt, s: SexpNode|string, diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index 1095a893e..985139f0a 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -74,14 +74,14 @@ type ## nothing prevents you from accessing directly the type of field you want ## if you expect only one kind. case kind*: Tparam_kind - of PK_EMPTY: nil + of PK_EMPTY: discard of PK_INT: int_val*: int of PK_BIGGEST_INT: big_int_val*: BiggestInt of PK_FLOAT: float_val*: float of PK_BIGGEST_FLOAT: big_float_val*: BiggestFloat of PK_STRING: str_val*: string of PK_BOOL: bool_val*: bool - of PK_HELP: nil + of PK_HELP: discard Tcommandline_results* = object of RootObj ## \ ## Contains the results of the parsing. @@ -319,7 +319,7 @@ proc echo_help*(expected: seq[Tparameter_specification] = @[], proc parse*(expected: seq[Tparameter_specification] = @[], - type_of_positional_parameters = PK_STRING, args: seq[TaintedString] = nil, + type_of_positional_parameters = PK_STRING, args: seq[TaintedString] = @[], bad_prefixes = @["-", "--"], end_of_options = "--", quit_on_failure = true): Tcommandline_results = ## Parses parameters and returns results. @@ -339,7 +339,7 @@ proc parse*(expected: seq[Tparameter_specification] = @[], ## ## The args sequence should be the list of parameters passed to your program ## without the program binary (usually OSes provide the path to the binary as - ## the zeroth parameter). If args is nil, the list will be retrieved from the + ## the zeroth parameter). If args is empty, the list will be retrieved from the ## OS. ## ## If there is any kind of error and quit_on_failure is true, the quit proc @@ -358,7 +358,7 @@ proc parse*(expected: seq[Tparameter_specification] = @[], # Prepare the input parameter list, maybe get it from the OS if not available. var args = args - if args == nil: + if args.len == 0: let total_params = paramCount() #echo "Got no explicit args, retrieving from OS. Count: ", total_params newSeq(args, total_params) diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim index 1e8a99c83..90f0a54e9 100644 --- a/tests/manyloc/keineschweine/lib/sg_assets.nim +++ b/tests/manyloc/keineschweine/lib/sg_assets.nim @@ -145,7 +145,7 @@ proc importHandling(data: JsonNode): THandlingRecord proc importBullet(data: JsonNode; errors: var seq[string]): PBulletRecord proc importSoul(data: JsonNode): TSoulRecord proc importExplosion(data: JsonNode; errors: var seq[string]): TExplosionRecord -proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord +proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = ""): PSoundRecord ## this is the only pipe between lobby and main.nim proc getActiveState*(): TGameState = @@ -514,7 +514,7 @@ proc importExplosion(data: JsonNode; errors: var seq[string]): TExplosionRecord let expl = data["explode"] result.anim = importAnim(expl, errors) result.sound = importSound(expl, errors, "sound") -proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord = +proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = ""): PSoundRecord = if data.kind == JObject: checkKey(data, fieldName) result = newSound(data[fieldName].str, errors) diff --git a/tests/manyloc/keineschweine/lib/sg_gui.nim b/tests/manyloc/keineschweine/lib/sg_gui.nim index 95cef1b24..074e0604c 100644 --- a/tests/manyloc/keineschweine/lib/sg_gui.nim +++ b/tests/manyloc/keineschweine/lib/sg_gui.nim @@ -92,8 +92,8 @@ proc newGuiContainer*(pos: TVector2f): PGuiContainer = result = newGuiContainer() result.setPosition pos proc free*(container: PGuiContainer) = - container.widgets = nil - container.buttons = nil + container.widgets = @[] + container.buttons = @[] proc add*(container: PGuiContainer; widget: PGuiObject) = container.widgets.add(widget) proc add*(container: PGuiContainer; button: PButton) = diff --git a/tests/stdlib/nre/captures.nim b/tests/stdlib/nre/captures.nim index 19c344a8d..31de71154 100644 --- a/tests/stdlib/nre/captures.nim +++ b/tests/stdlib/nre/captures.nim @@ -27,7 +27,7 @@ suite "captures": let ex2 = "foo".find(re("(?foo)(?bar)?")) check(ex2.captures["foo"] == "foo") - check(ex2.captures["bar"] == nil) + check(ex2.captures["bar"] == "") test "named capture bounds": let ex1 = "foo".find(re("(?foo)(?bar)?")) @@ -41,7 +41,7 @@ suite "captures": test "named capture table": let ex1 = "foo".find(re("(?foo)(?bar)?")) - check(ex1.captures.toTable == {"foo" : "foo", "bar" : nil}.toTable()) + check(ex1.captures.toTable == {"foo" : "foo", "bar" : ""}.toTable()) check(ex1.captureBounds.toTable == {"foo" : some(0..2), "bar" : none(Slice[int])}.toTable()) check(ex1.captures.toTable("") == {"foo" : "foo", "bar" : ""}.toTable()) @@ -50,7 +50,7 @@ suite "captures": test "capture sequence": let ex1 = "foo".find(re("(?foo)(?bar)?")) - check(ex1.captures.toSeq == @["foo", nil]) + check(ex1.captures.toSeq == @["foo", ""]) check(ex1.captureBounds.toSeq == @[some(0..2), none(Slice[int])]) check(ex1.captures.toSeq("") == @["foo", ""]) diff --git a/tests/stdlib/nre/replace.nim b/tests/stdlib/nre/replace.nim index 516fd4328..b762271a2 100644 --- a/tests/stdlib/nre/replace.nim +++ b/tests/stdlib/nre/replace.nim @@ -16,5 +16,5 @@ suite "replace": check("123".replace(re"(?\d)(\d)", "${foo}$#$#") == "1123") test "replacing missing captures should throw instead of segfaulting": - expect ValueError: discard "ab".replace(re"(a)|(b)", "$1$2") - expect ValueError: discard "b".replace(re"(a)?(b)", "$1$2") + discard "ab".replace(re"(a)|(b)", "$1$2") + discard "b".replace(re"(a)?(b)", "$1$2") diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index c0b4d5f78..bf0bb3ea7 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -40,7 +40,7 @@ when isMainModule: test: 18827361, test2: "hello world", test3: true, - testNil: nil + testNil: "nil" ) let node = %x @@ -53,7 +53,7 @@ when isMainModule: doAssert y.test == 18827361 doAssert y.test2 == "hello world" doAssert y.test3 - doAssert y.testNil.isNil + doAssert y.testNil == "nil" # Test for custom object variants (without an enum) and with an else branch. block: diff --git a/tests/stdlib/tnilecho.nim b/tests/stdlib/tnilecho.nim index 147b5e492..0f8a38438 100644 --- a/tests/stdlib/tnilecho.nim +++ b/tests/stdlib/tnilecho.nim @@ -1,2 +1,2 @@ -var x = @["1", nil, "3"] -doAssert $x == "@[1, nil, 3]" +var x = @["1", "", "3"] +doAssert $x == """@["1", "", "3"]""" From 81645deb871d1ff869c0c7b289d8a851ee3b4214 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 13 Aug 2018 12:51:19 +0200 Subject: [PATCH 059/103] testament: change how JS tests are disable for travis on OSX --- tests/testament/categories.nim | 4 +++- tests/testament/specs.nim | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index f7cd0815c..8731848cf 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -484,7 +484,9 @@ proc processCategory(r: var TResults, cat: Category, options: string) = of "js": # only run the JS tests on Windows or Linux because Travis is bad # and other OSes like Haiku might lack nodejs: - when defined(linux) or defined(windows): + if not defined(linux) and isTravis: + discard + else: jsTests(r, cat, options) of "dll": dllTests(r, cat, options) diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim index ac79e3942..fbe930a4f 100644 --- a/tests/testament/specs.nim +++ b/tests/testament/specs.nim @@ -12,8 +12,8 @@ import parseutils, strutils, os, osproc, streams, parsecfg var compilerPrefix* = "compiler" / "nim " -let isTravis = existsEnv("TRAVIS") -let isAppVeyor = existsEnv("APPVEYOR") +let isTravis* = existsEnv("TRAVIS") +let isAppVeyor* = existsEnv("APPVEYOR") proc cmdTemplate*(): string = compilerPrefix & "$target --lib:lib --hints:on -d:testing $options $file" From 9f31096870103e93b23e17c4a68aa7dcdcc7889e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 13 Aug 2018 12:51:31 +0200 Subject: [PATCH 060/103] make JS tests green --- tests/js/tclosures.nim | 2 +- tests/js/testobjs.nim | 2 +- tests/js/tjsffi.nim | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/js/tclosures.nim b/tests/js/tclosures.nim index 67243c937..659c60092 100644 --- a/tests/js/tclosures.nim +++ b/tests/js/tclosures.nim @@ -48,4 +48,4 @@ for i in 1 .. 10: let results = runCallbacks() -doAssert(expected == results) +doAssert(expected == $results) diff --git a/tests/js/testobjs.nim b/tests/js/testobjs.nim index dd66825ec..78f0b4766 100644 --- a/tests/js/testobjs.nim +++ b/tests/js/testobjs.nim @@ -34,7 +34,7 @@ var recurse1 = Recurse[int](data: 1, next: recurse2) -doAssert test.name == "Jorden" +doAssert test.name == cstring"Jorden" doAssert knight.age == 19 doAssert knight.item.price == 50 doAssert recurse1.next.next.data == 3 diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim index 325ab6366..156ca89e3 100644 --- a/tests/js/tjsffi.nim +++ b/tests/js/tjsffi.nim @@ -64,7 +64,7 @@ block: proc test(): bool = let obj = newJsObject() obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z) - obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == "Result is: 6" + obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == cstring"Result is: 6" echo test() # Test JsObject []() From 96e0b56a55ba893c69ef9add60b1dfaa493ffb0e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 13 Aug 2018 12:54:02 +0200 Subject: [PATCH 061/103] make generic tests green again --- tests/generics/tgeneric3.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim index d014eb998..6897d9de2 100644 --- a/tests/generics/tgeneric3.nim +++ b/tests/generics/tgeneric3.nim @@ -103,7 +103,7 @@ proc DeleteItem[T,D] (n: PNode[T,D], x: int): PNode[T,D] {.inline.} = else : result = n.left - n.slots = nil + n.slots = @[] n.left = nil proc internalDelete[T,D] (ANode: PNode[T,D], key: T, Avalue: var D): PNode[T,D] = @@ -200,7 +200,7 @@ proc traceTree[T,D](root: PNode[T,D]) = traceln(space) write stdout, "left: " doTrace(n.left, level+1) - for i, el in n.slots : + for i, el in n.slots: if el != nil and not isClean(el): traceln(space) traceX(i) From 975114e114c53601287393359c0d823b2c53a315 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 13 Aug 2018 13:02:52 +0200 Subject: [PATCH 062/103] make more tests green --- .../template/mgensym_generic_cross_module.nim | 4 ++-- tests/template/tdefault_nil.nim | 2 +- tests/vm/meta.nim | 22 +++++++++---------- tests/vm/tcomponent.nim | 2 +- tests/vm/tstringnil.nim | 8 +++---- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/template/mgensym_generic_cross_module.nim b/tests/template/mgensym_generic_cross_module.nim index 80b681db4..ea88f67e6 100644 --- a/tests/template/mgensym_generic_cross_module.nim +++ b/tests/template/mgensym_generic_cross_module.nim @@ -1,6 +1,6 @@ -template makeDomElement(x: untyped, name: string = nil) = - const tag {.gensym.} = if name == nil: astToStr(x) else: name +template makeDomElement(x: untyped, name: string = "") = + const tag {.gensym.} = if name.len == 0: astToStr(x) else: name proc x*(p: int|float) = echo tag, p diff --git a/tests/template/tdefault_nil.nim b/tests/template/tdefault_nil.nim index c5c372d9e..311a6c090 100644 --- a/tests/template/tdefault_nil.nim +++ b/tests/template/tdefault_nil.nim @@ -2,7 +2,7 @@ # bug #2629 import sequtils, os -template glob_rst(basedir: string = nil): untyped = +template glob_rst(basedir: string = ""): untyped = if baseDir.isNil: to_seq(walk_files("*.rst")) else: diff --git a/tests/vm/meta.nim b/tests/vm/meta.nim index 2aa01b5b3..32a441f27 100644 --- a/tests/vm/meta.nim +++ b/tests/vm/meta.nim @@ -39,7 +39,7 @@ proc newIdent*(node: NimNode): Ident = raise newException(ValueError, msg) proc render*(i: Ident): NimNode {.compileTime.} = - if i.name == nil: + if i.name == "": return newNimNode(nnkEmpty) if i.exported: @@ -67,7 +67,7 @@ proc newBracket*(node: NimNode): Bracket = raise newException(ValueError, msg) # Field procs -proc newField*(identifier: Ident, type_name: string, default: string = nil): Field = +proc newField*(identifier: Ident, type_name: string, default: string = ""): Field = result.identifier = identifier result.type_name = type_name result.default = default @@ -84,7 +84,7 @@ proc newField*(node: NimNode): Field = of nnkIdent: result.default = $(node[2]) else: - result.default = nil + result.default = "" else: let msg = "newField cannot initialize from node kind: " & $(node.kind) raise newException(ValueError, msg) @@ -102,7 +102,7 @@ proc newFieldSeq*(node: NimNode): FieldSeq = of nnkIdent: default = $(default_node) else: - default = nil + default = "" for i in 0..node.len - 3: let name = newIdent(node[i]) result.add(newField(name, type_name, default)) @@ -115,8 +115,8 @@ proc newFieldSeq*(node: NimNode): FieldSeq = proc render*(f: Field): NimNode {.compileTime.} = let identifier = f.identifier.render() - let type_name = if f.type_name != nil: ident(f.type_name) else: newEmptyNode() - let default = if f.default != nil: ident(f.default) else: newEmptyNode() + let type_name = if f.type_name != "": ident(f.type_name) else: newEmptyNode() + let default = if f.default != "": ident(f.default) else: newEmptyNode() newIdentDefs(identifier, type_name, default) proc render*(fs: FieldSeq): NimNode {.compileTime.} = @@ -127,7 +127,7 @@ proc render*(fs: FieldSeq): NimNode {.compileTime.} = # TypeDef procs proc newTypeDef*(identifier: Ident, is_ref = false, object_type = "object", - base_type: string = nil): TypeDef {.compileTime.} = + base_type: string = ""): TypeDef {.compileTime.} = result.identifier = identifier result.fields = @[] result.is_ref = is_ref @@ -165,7 +165,7 @@ proc render*(typedef: TypeDef): NimNode {.compileTime.} = result.add(newEmptyNode()) let object_node = newNimNode(nnkObjectTy) object_node.add(newEmptyNode()) - if typedef.base_type == nil: + if typedef.base_type == "": object_node.add(newEmptyNode()) else: var base_type = newNimNode(nnkOfInherit) @@ -195,8 +195,8 @@ proc render*(typeseq: TypeDefSeq): NimNode {.compileTime.} = for typedef in typeseq: result.add(typedef.render()) -proc newProc*(identifier: Ident, params: FieldSeq = nil, - returns: Ident, generics: FieldSeq = nil): Proc = +proc newProc*(identifier: Ident, params: FieldSeq = @[], + returns: Ident, generics: FieldSeq = @[]): Proc = result.identifier = identifier result.params = params result.returns = returns @@ -209,7 +209,7 @@ proc newProc*(node: NimNode): Proc = case node[2].kind: of nnkGenericParams: result.generics = newFieldSeq(node[2]) - else: result.generics = nil + else: result.generics = @[] let formal_params = node[3] case formal_params[0].kind: of nnkIdent: diff --git a/tests/vm/tcomponent.nim b/tests/vm/tcomponent.nim index e7962e7ab..b509bc5d7 100644 --- a/tests/vm/tcomponent.nim +++ b/tests/vm/tcomponent.nim @@ -11,7 +11,7 @@ FOO: blah''' import macros, sequtils, tables import strutils -import future, meta +import sugar, meta type Component = object diff --git a/tests/vm/tstringnil.nim b/tests/vm/tstringnil.nim index 39e4040dc..df408910e 100644 --- a/tests/vm/tstringnil.nim +++ b/tests/vm/tstringnil.nim @@ -20,16 +20,16 @@ proc buildSuiteContents(suiteName, suiteDesc, suiteBloc: NimNode): tuple[tests: var testObj = SuiteTest() if suiteName.kind == nnkNilLit: - testObj.suiteName = nil + testObj.suiteName = "" else: testObj.suiteName = $suiteName if suiteDesc.kind == nnkNilLit: - testObj.suiteDesc = nil + testObj.suiteDesc = "" else: testObj.suiteDesc = suiteDesc.strVal testObj.testName = $child[1] # should not ever be nil if child[2].kind == nnkNilLit: - testObj.testDesc = nil + testObj.testDesc = "" else: testObj.testDesc = child[2].strVal testObj.testBlock = child[1] @@ -46,5 +46,5 @@ macro suite(suiteName, suiteDesc, suiteBloc: untyped): typed = # Test above suite basics, "Description of such": - test(t5, nil): + test(t5, ""): assert false From aa1cdebdc206857902081b4862dad2c2990179e8 Mon Sep 17 00:00:00 2001 From: cooldome Date: Mon, 13 Aug 2018 15:02:20 +0200 Subject: [PATCH 063/103] Converters to take into account constraints. Fixes #7520 (#8593) --- compiler/sigmatch.nim | 4 ++++ .../converter/tconverter_with_constraint.nim | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/converter/tconverter_with_constraint.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 5afa1b031..c665aad7f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1809,6 +1809,10 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, # see tests/tgenericconverter: 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: diff --git a/tests/converter/tconverter_with_constraint.nim b/tests/converter/tconverter_with_constraint.nim new file mode 100644 index 000000000..793264434 --- /dev/null +++ b/tests/converter/tconverter_with_constraint.nim @@ -0,0 +1,20 @@ + +discard """ + file: "tconverter_with_constraint.nim" + line: 20 + errormsg: "type mismatch: got " +""" + +type + MyType = distinct int + +converter to_mytype(m: int{lit}): MyType = + m.MyType + +proc myproc(m: MyType) = + echo m.int, ".MyType" + +myproc(1) # call by literal is ok + +var x: int = 12 +myproc(x) # should fail \ No newline at end of file From 46204eba1f2eb1840b6543958c9a5306f707b3d6 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 13 Aug 2018 15:42:20 +0200 Subject: [PATCH 064/103] make the vccexe helper tool compile again --- tools/vccenv/vccenv.nim | 2 +- tools/vccenv/vccexe.nim | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/vccenv/vccenv.nim b/tools/vccenv/vccenv.nim index a335efd10..a5af7994e 100644 --- a/tools/vccenv/vccenv.nim +++ b/tools/vccenv/vccenv.nim @@ -19,7 +19,7 @@ proc getVsComnToolsPath*(): TaintedString = return vsComnToolsEnvVal proc getVccEnv*(platform: string, windowsStoreSdk: bool = false, - sdkVersion: string = nil): StringTableRef = + sdkVersion: string = ""): StringTableRef = var comSpecCommandString = getEnv comSpecEnvKey if comSpecCommandString.len == 0: comSpecCommandString = "cmd" diff --git a/tools/vccenv/vccexe.nim b/tools/vccenv/vccexe.nim index 892246830..e86e14c0f 100644 --- a/tools/vccenv/vccexe.nim +++ b/tools/vccenv/vccexe.nim @@ -5,14 +5,14 @@ when defined(release): else: let vccOptions = {poEchoCmd, poParentStreams} -const +const platformPrefix = "--platform" winstorePrefix = "--winstore" sdkversionPrefix = "--sdkversion" platformSepIdx = platformPrefix.len sdkversionSepIdx = sdkversionPrefix.len - + HelpText = """ +-----------------------------------------------------------------+ | Microsoft C/C++ compiler wrapper for Nim | @@ -26,7 +26,7 @@ Options: : x86 | amd64 | arm | x86_amd64 | x86_arm | amd64_x86 | amd64_arm --winstore Use Windows Store (rather than desktop) development tools --sdkversion: Use a specific Windows SDK version: - is either the full Windows 10 SDK version number or + is either the full Windows 10 SDK version number or "8.1" to use the windows 8.1 SDK Other command line arguments are passed on to the @@ -34,8 +34,8 @@ Microsoft C/C++ compiler for the specified SDK toolset """ when isMainModule: - var platformArg: string = nil - var sdkVersionArg: string = nil + var platformArg: string = "" + var sdkVersionArg: string = "" var storeArg: bool = false var clArgs: seq[TaintedString] = @[] @@ -54,7 +54,7 @@ when isMainModule: echo HelpText clArgs.add(wargv) - var vccEnvStrTab = getVccEnv(platformArg, storeArg, sdkVersionArg) + var vccEnvStrTab = getVccEnv(platformArg, storeArg, sdkVersionArg) if vccEnvStrTab != nil: for vccEnvKey, vccEnvVal in vccEnvStrTab: putEnv(vccEnvKey, vccEnvVal) From d60bb1b289c7914443a20b78bfb6c69f05184937 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 13 Aug 2018 16:07:23 +0200 Subject: [PATCH 065/103] build Nimble with --nilseqs:on until Nimble is fixed --- koch.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/koch.nim b/koch.nim index ad6a774e8..2f4c8d567 100644 --- a/koch.nim +++ b/koch.nim @@ -182,7 +182,7 @@ proc bundleNimbleExe() = bundleNimbleSrc() # now compile Nimble and copy it to $nim/bin for the installer.ini # to pick it up: - nimexec("c -d:release dist/nimble/src/nimble.nim") + nimexec("c -d:release --nilseqs:on dist/nimble/src/nimble.nim") copyExe("dist/nimble/src/nimble".exe, "bin/nimble".exe) proc buildNimble(latest: bool) = @@ -209,7 +209,7 @@ proc buildNimble(latest: bool) = else: exec("git checkout -f stable") exec("git pull") - nimexec("c --noNimblePath -p:compiler -d:release " & installDir / "src/nimble.nim") + nimexec("c --noNimblePath -p:compiler --nilseqs:on -d:release " & installDir / "src/nimble.nim") copyExe(installDir / "src/nimble".exe, "bin/nimble".exe) proc bundleNimsuggest(buildExe: bool) = From 420ed0596b8114c67275c4702fa3524ebd76e5eb Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 13 Aug 2018 17:27:44 +0200 Subject: [PATCH 066/103] fixes more nil handling regressions --- compiler/ast.nim | 4 ++-- compiler/patterns.nim | 8 +++++-- lib/deprecated/pure/actors.nim | 3 +-- lib/pure/httpclient.nim | 14 ++++++------ tests/casestmt/tcasestm.nim | 18 +++++++-------- tests/exception/tdont_overwrite_typename.nim | 4 ++-- tests/notnil/tnotnil.nim | 12 +--------- tests/pragmas/custom_pragma.nim | 2 +- tests/system/tostring.nim | 10 +++----- tests/threads/tactors.nim | 4 ++-- tests/tuples/tuple_with_nil.nim | 24 ++++++++++---------- tests/tuples/tuple_with_seq.nim | 4 ++-- tests/types/temptyseqs.nim | 2 +- 13 files changed, 49 insertions(+), 60 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 7d8d098e3..e294eccc2 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -971,8 +971,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} diff --git a/compiler/patterns.nim b/compiler/patterns.nim index aa06342f9..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 @@ -211,6 +214,7 @@ proc matchStmtList(c: PPatternContext, p, n: PNode): PNode = # we need to undo any bindings: when defined(nimNoNilSeqs): c.mapping = @[] + c.mappingIsFull = false else: if not isNil(c.mapping): c.mapping = nil return false diff --git a/lib/deprecated/pure/actors.nim b/lib/deprecated/pure/actors.nim index 17321cc0e..451668825 100644 --- a/lib/deprecated/pure/actors.nim +++ b/lib/deprecated/pure/actors.nim @@ -43,7 +43,6 @@ type t: Thread[ptr Actor[In, Out]] PActor*[In, Out] = ptr Actor[In, Out] ## an actor -{.deprecated: [TTask: Task, TActor: Actor].} proc spawn*[In, Out](action: proc( self: PActor[In, Out]){.thread.}): PActor[In, Out] = @@ -168,7 +167,7 @@ proc terminate*[In, Out](a: var ActorPool[In, Out]) = for i in 0.. 0: str.add("; filename=\"" & filename & "\"") str.add("\c\L") - if contentType != nil: + if contentType.len > 0: str.add("Content-Type: " & contentType & "\c\L") str.add("\c\L" & content & "\c\L") @@ -434,7 +434,7 @@ proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]): var contentType: string let (_, fName, ext) = splitFile(file) if ext.len > 0: - contentType = m.getMimetype(ext[1..ext.high], nil) + contentType = m.getMimetype(ext[1..ext.high], "") p.add(name, readFile(file), fName & ext, contentType) result = p diff --git a/tests/casestmt/tcasestm.nim b/tests/casestmt/tcasestm.nim index 4d32d023f..ff912ffab 100644 --- a/tests/casestmt/tcasestm.nim +++ b/tests/casestmt/tcasestm.nim @@ -41,16 +41,16 @@ let str2 = "NN" let a = case str1: of "Y": true of "N": false - else: + else: echo "no good" quit("quiting") -proc toBool(s: string): bool = +proc toBool(s: string): bool = case s: - of nil, "": raise newException(ValueError, "Invalid boolean") - elif s[0] == 'Y': true - elif s[0] == 'N': false - else: "error".quit(2) + of "": raise newException(ValueError, "Invalid boolean") + elif s[0] == 'Y': true + elif s[0] == 'N': false + else: "error".quit(2) let b = "NN".toBool() @@ -66,7 +66,7 @@ static: var bb: bool doassert(not compiles( bb = case str2: - of nil, "": raise newException(ValueError, "Invalid boolean") + of "": raise newException(ValueError, "Invalid boolean") elif str.startsWith("Y"): true elif str.startsWith("N"): false )) @@ -94,7 +94,7 @@ doassert(not compiles( bb = case str2: of "Y": raise newException(ValueError, "Invalid Y") - true + true else: raise newException(ValueError, "Invalid") )) @@ -103,6 +103,6 @@ doassert(not compiles( bb = case str2: of "Y": "invalid Y".quit(3) - true + true else: raise newException(ValueError, "Invalid") )) \ No newline at end of file diff --git a/tests/exception/tdont_overwrite_typename.nim b/tests/exception/tdont_overwrite_typename.nim index 6e3ff816f..d6dca0990 100644 --- a/tests/exception/tdont_overwrite_typename.nim +++ b/tests/exception/tdont_overwrite_typename.nim @@ -7,10 +7,10 @@ Check passed''' # bug #5628 proc checkException(ex: ref Exception) = - doAssert(ex.name == "ValueError") + doAssert(ex.name == cstring"ValueError") doAssert(ex.msg == "SecondException") doAssert(ex.parent != nil) - doAssert(ex.parent.name == "KeyError") + doAssert(ex.parent.name == cstring"KeyError") doAssert(ex.parent.msg == "FirstException") echo "Check passed" diff --git a/tests/notnil/tnotnil.nim b/tests/notnil/tnotnil.nim index e392b155c..aff3f8959 100644 --- a/tests/notnil/tnotnil.nim +++ b/tests/notnil/tnotnil.nim @@ -1,5 +1,5 @@ discard """ - line: 22 + line: 13 errormsg: "type mismatch" """ {.experimental: "notnil".} @@ -8,16 +8,6 @@ type TObj = object x: int - MyString = string not nil - -#var x: PObj = nil - -proc p(x: string not nil): int = - result = 45 - -proc q(x: MyString) = discard proc q2(x: string) = discard q2(nil) -q(nil) - diff --git a/tests/pragmas/custom_pragma.nim b/tests/pragmas/custom_pragma.nim index 9e8f51deb..d2fc969d0 100644 --- a/tests/pragmas/custom_pragma.nim +++ b/tests/pragmas/custom_pragma.nim @@ -2,4 +2,4 @@ template serializationKey*(s: string) {.pragma.} template defaultValue*(V: typed) {.pragma.} -template alternativeKey*(s: string = nil, V: typed) {.pragma.} \ No newline at end of file +template alternativeKey*(s: string = "", V: typed) {.pragma.} diff --git a/tests/system/tostring.nim b/tests/system/tostring.nim index 9a6b83f95..99299f203 100644 --- a/tests/system/tostring.nim +++ b/tests/system/tostring.nim @@ -26,8 +26,8 @@ doAssert "nan" == $(0.0/0.0) var x: seq[string] doAssert "nil" == $(x) -var y: string = nil -doAssert nil == $(y) +var y: string +doAssert "" == $(y) type Foo = object @@ -54,7 +54,7 @@ doAssert $arr == "['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', ' doAssert $cstring(unsafeAddr arr) == "Hello World!" proc takes(c: cstring) = - doAssert c == "" + doAssert c == cstring"" proc testm() = var x: string @@ -90,12 +90,8 @@ proc stringCompare() = doAssert e == "" doAssert "" == e - doAssert nil == e - doAssert e == nil doAssert f == g doAssert "" == "" - doAssert "" == nil - doAssert nil == "" g.setLen(10) doAssert g == "\0\0\0\0\0\0\0\0\0\0" diff --git a/tests/threads/tactors.nim b/tests/threads/tactors.nim index 45a03ebb7..ea052b9bd 100644 --- a/tests/threads/tactors.nim +++ b/tests/threads/tactors.nim @@ -5,9 +5,9 @@ discard """ import actors var - pool: TActorPool[int, void] + pool: ActorPool[int, void] createActorPool(pool) -for i in 0 .. < 300: +for i in 0 ..< 300: pool.spawn(i, proc (x: int) {.thread.} = echo x) pool.join() diff --git a/tests/tuples/tuple_with_nil.nim b/tests/tuples/tuple_with_nil.nim index ec48337bd..e09c53407 100644 --- a/tests/tuples/tuple_with_nil.nim +++ b/tests/tuples/tuple_with_nil.nim @@ -73,7 +73,7 @@ type const DefaultPrec = 6 ## Default precision for floating point numbers. - DefaultFmt: Format = (ftDefault, -1, -1, nil, faDefault, fsMinus, false, false, false, nil) + DefaultFmt: Format = (ftDefault, -1, -1, "", faDefault, fsMinus, false, false, false, "") ## Default format corresponding to the empty format string, i.e. ## `x.format("") == x.format(DefaultFmt)`. round_nums = [0.5, 0.05, 0.005, 0.0005, 0.00005, 0.000005, 0.0000005, 0.00000005] @@ -124,7 +124,7 @@ proc parse(fmt: string): Format {.nosideeffect.} = if fmt.rawmatch(p, 0, caps) < 0: raise newException(FormatError, "Invalid format string") - result.fill = fmt.get(caps, 0, nil) + result.fill = fmt.get(caps, 0, "") case fmt.get(caps, 1, 0.char) of '<': result.align = faLeft @@ -144,7 +144,7 @@ proc parse(fmt: string): Format {.nosideeffect.} = result.width = fmt.get(caps, 4, -1) if caps.has(4) and fmt[caps.bounds(4).first] == '0': - if result.fill != nil: + if result.fill != "": raise newException(FormatError, "Leading 0 in with not allowed with explicit fill character") if result.align != faDefault: raise newException(FormatError, "Leading 0 in with not allowed with explicit alignment") @@ -171,7 +171,7 @@ proc parse(fmt: string): Format {.nosideeffect.} = of '%': result.typ = ftPercent else: result.typ = ftDefault - result.arysep = fmt.get(caps, 8, nil, 1) + result.arysep = fmt.get(caps, 8, "", 1) proc getalign(fmt: Format; defalign: FmtAlign; slen: int) : tuple[left, right:int] {.nosideeffect.} = ## Returns the number of left and right padding characters for a @@ -218,7 +218,7 @@ proc writefill(o: var Writer; fmt: Format; n: int; signum: int = 0) = elif fmt.sign == fsPlus: write(o, '+') elif fmt.sign == fsSpace: write(o, ' ') - if fmt.fill == nil: + if fmt.fill.len == 0: for i in 1..n: write(o, ' ') else: for i in 1..n: @@ -626,19 +626,19 @@ proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} = else: lvl.dec let clpos = pos - var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: nil, index: int.high, nested: nested) + var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: "", index: int.high, nested: nested) if fmtpart.fmt.len > 0: var m: array[0..3, string] if not fmtpart.fmt.match(subpeg, m): error("invalid format string") - if m[1] != nil and m[1].len > 0: + if m[1].len > 0: fmtpart.field = m[1].substr(1) - if m[2] != nil and m[2].len > 0: + if m[2].len > 0: discard parseInt(m[2].substr(1, m[2].len-2), fmtpart.index) if m[0].len > 0: discard parseInt(m[0], fmtpart.arg) - if m[3] == nil or m[3].len == 0: + if m[3].len == 0: fmtpart.fmt = "" elif m[3][0] == ':': fmtpart.fmt = m[3].substr(1) @@ -650,7 +650,7 @@ proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} = proc literal(s: string): NimNode {.compiletime, nosideeffect.} = ## Return the nim literal of string `s`. This handles the case if ## `s` is nil. - result = if s == nil: newNilLit() else: newLit(s) + result = newLit(s) proc literal(b: bool): NimNode {.compiletime, nosideeffect.} = ## Return the nim literal of boolean `b`. This is either `true` @@ -713,7 +713,7 @@ proc generatefmt(fmtstr: string; args[arg].cnt = args[arg].cnt + 1 arg.inc # possible field access - if part.field != nil and part.field.len > 0: + if part.field.len > 0: argexpr = newDotExpr(argexpr, part.field.ident) # possible array access if part.index < int.high: @@ -724,7 +724,7 @@ proc generatefmt(fmtstr: string; # nested format string. Compute the format string by # concatenating the parts of the substring. for e in generatefmt(part.fmt, args, arg): - var newexpr = if part.fmt == nil: e.val else: newCall(bindsym"format", e.val, e.fmt) + var newexpr = if part.fmt.len == 0: e.val else: newCall(bindsym"format", e.val, e.fmt) if fmtexpr != nil and fmtexpr.kind != nnkNilLit: fmtexpr = infix(fmtexpr, "&", newexpr) else: diff --git a/tests/tuples/tuple_with_seq.nim b/tests/tuples/tuple_with_seq.nim index 39edb500f..00b07dd2c 100644 --- a/tests/tuples/tuple_with_seq.nim +++ b/tests/tuples/tuple_with_seq.nim @@ -3,8 +3,8 @@ discard """ @[1, 2, 3]''' """ -template foo(s: string = nil) = - if isNil(s): +template foo(s: string = "") = + if s.len == 0: echo "it's nil" else: echo s diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim index 834f63729..28c3b87b8 100644 --- a/tests/types/temptyseqs.nim +++ b/tests/types/temptyseqs.nim @@ -22,7 +22,7 @@ when true: import os type - In_out = tuple[src, dest, options: string] + In_out = tuple[src, dest: string, options: ref int] let nil_var: In_out = ("hey"/"there", "something", nil) From 99384c0234f552d38bbb36cf46cf7ec4b1845ac7 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 13 Aug 2018 20:12:00 +0200 Subject: [PATCH 067/103] make NimInAction tests green --- tests/testament/categories.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 8731848cf..fc2f0d25f 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -256,6 +256,8 @@ proc jsTests(r: var TResults, cat: Category, options: string) = # ------------------------- nim in action ----------- proc testNimInAction(r: var TResults, cat: Category, options: string) = + let options = options & " --nilseqs:on" + template test(filename: untyped, action: untyped) = testSpec r, makeTest(filename, options, cat, action) From f960523b466f3e32ab29968a18c51e3843abc3c9 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 13 Aug 2018 20:12:13 +0200 Subject: [PATCH 068/103] document the new --nilseqs:on switch --- changelog.md | 2 +- doc/advopt.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index f48f7e024..b84cf16a1 100644 --- a/changelog.md +++ b/changelog.md @@ -155,7 +155,7 @@ More details in language manual. - ``nil`` for strings/seqs is finally gone. Instead the default value for - these is ``"" / @[]``. + these is ``"" / @[]``. Use ``--nilseqs:on`` for a transition period. - Accessing the binary zero terminator in Nim's native strings is now invalid. Internally a Nim string still has the trailing zero for diff --git a/doc/advopt.txt b/doc/advopt.txt index 685c8127d..150025509 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -68,6 +68,8 @@ Advanced options: --oldNewlines:on|off turn on|off the old behaviour of "\n" --laxStrings:on|off when turned on, accessing the zero terminator in strings is allowed; only for backwards compatibility + --nilseqs:on|off allow 'nil' for strings/seqs for + backwards compatibility --skipCfg do not read the general configuration file --skipUserCfg do not read the user's configuration file --skipParentCfg do not read the parent dirs' configuration files From f91a181f58acfa7c75e4683e582455c98bc8693d Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 13 Aug 2018 23:16:03 +0200 Subject: [PATCH 069/103] make tests green again --- compiler/semmacrosanity.nim | 2 +- lib/system.nim | 8 ++++++-- tests/cpp/tasync_cpp.nim | 1 + tests/distinct/tnil.nim | 15 --------------- tests/notnil/tmust_compile.nim | 20 +++----------------- tests/notnil/tnotnil1.nim | 15 +-------------- tests/notnil/tnotnil_in_objconstr.nim | 8 ++++---- tests/vm/tseq_badinit.nim | 4 ++-- 8 files changed, 18 insertions(+), 55 deletions(-) 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/lib/system.nim b/lib/system.nim index 4b69a8067..c730167ed 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2344,8 +2344,12 @@ proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} = ## Generic equals operator for sequences: relies on a equals operator for ## the element type `T`. when nimvm: - if x.isNil and y.isNil: - return true + when not defined(nimNoNil): + if x.isNil and y.isNil: + return true + else: + if x.len == 0 and y.len == 0: + return true else: when not defined(JS): proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} = diff --git a/tests/cpp/tasync_cpp.nim b/tests/cpp/tasync_cpp.nim index a5e3374b6..50bc1853c 100644 --- a/tests/cpp/tasync_cpp.nim +++ b/tests/cpp/tasync_cpp.nim @@ -1,6 +1,7 @@ discard """ targets: "cpp" output: "hello" + cmd: "nim cpp --nilseqs:on $file" """ # bug #3299 diff --git a/tests/distinct/tnil.nim b/tests/distinct/tnil.nim index 759a14657..16de38f60 100644 --- a/tests/distinct/tnil.nim +++ b/tests/distinct/tnil.nim @@ -9,7 +9,6 @@ discard """ type MyPointer = distinct pointer MyString = distinct string - MyStringNotNil = distinct (string not nil) MyInt = distinct int proc foo(a: MyPointer) = @@ -26,20 +25,6 @@ p = cast[MyPointer](nil) p = nil.MyPointer p = nil -var c: MyString -c = "Test".MyString -c = nil.MyString -c = nil - -p = nil -doAssert(compiles(c = p) == false) - -var n: MyStringNotNil = "Test".MyStringNotNil # Cannot prove warning ... -n = "Test".MyStringNotNil -doAssert(compiles(n = nil.MyStringNotNil) == false) -doAssert(compiles(n = nil.MyStringNotNil) == false) -doAssert(compiles(n = nil) == false) - var i: MyInt i = 1.MyInt doAssert(compiles(i = nil) == false) diff --git a/tests/notnil/tmust_compile.nim b/tests/notnil/tmust_compile.nim index a32c6c7ec..d09dda057 100644 --- a/tests/notnil/tmust_compile.nim +++ b/tests/notnil/tmust_compile.nim @@ -44,16 +44,16 @@ import json type foo = object - thing: string not nil + thing: ptr int not nil CTS = ref object subs_by_sid: Table[int, foo] proc parse(cts: CTS, jn: JsonNode) = - + var y = jn.getInt(4523) let ces = foo( - thing: jn.getStr("thing") + thing: addr y ) cts.subs_by_sid[0] = ces @@ -63,17 +63,3 @@ proc parse(cts: CTS, jn: JsonNode) = proc p(x: proc(){.closure.} not nil) = discard p(proc(){.closure.} = discard) - -# bug #3993 - -type - List[T] = seq[T] not nil - -proc `^^`[T](v: T, lst: List[T]): List[T] = - result = @[v] - result.add(lst) - -proc Nil[T](): List[T] = @[] - -when isMainModule: - let lst = 1 ^^ 2 ^^ Nil[int]() diff --git a/tests/notnil/tnotnil1.nim b/tests/notnil/tnotnil1.nim index 7f9d02295..60666d64d 100644 --- a/tests/notnil/tnotnil1.nim +++ b/tests/notnil/tnotnil1.nim @@ -1,6 +1,6 @@ discard """ errormsg: "'y' is provably nil" - line:38 + line:25 """ import strutils @@ -10,19 +10,6 @@ type TObj = object x, y: int -type - superstring = string not nil - - -proc q(s: superstring) = - echo s - -proc p2() = - var a: string = "I am not nil" - q(a) # but this should and does not - -p2() - proc q(x: pointer not nil) = discard diff --git a/tests/notnil/tnotnil_in_objconstr.nim b/tests/notnil/tnotnil_in_objconstr.nim index d33709906..f0d5c1ae2 100644 --- a/tests/notnil/tnotnil_in_objconstr.nim +++ b/tests/notnil/tnotnil_in_objconstr.nim @@ -6,9 +6,9 @@ discard """ # bug #2355 type Foo = object - foo: string not nil - bar: string not nil - + foo: ref int + bar: ref int not nil +var x: ref int = new(int) # Create instance without initializaing the `bar` field -var f = Foo(foo: "foo") +var f = Foo(foo: x) echo f.bar.isNil # true diff --git a/tests/vm/tseq_badinit.nim b/tests/vm/tseq_badinit.nim index 15889d60e..5fa223c85 100644 --- a/tests/vm/tseq_badinit.nim +++ b/tests/vm/tseq_badinit.nim @@ -22,14 +22,14 @@ template test(typename, default: untyped) = result = newSeq[typename]() result.add(default) result.setLen(3) - for i in 0 .. <2: + for i in 0 ..< 2: result[i] = default const constval = `abc typename`() doAssert(constval == `abc typename`()) proc `arr typename`(): array[4, typename] = - for i in 0 .. <2: + for i in 0 ..< 2: result[i] = default const constarr = `arr typename`() doAssert(constarr == `arr typename`()) From 741f95e2d63746af8542f4679656a6e345120265 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 14 Aug 2018 00:09:46 +0200 Subject: [PATCH 070/103] make dochack.nim compile again --- tools/dochack/dochack.nim | 28 ++++++++++++++-------------- tools/dochack/karax.nim | 5 +++-- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/tools/dochack/dochack.nim b/tools/dochack/dochack.nim index 8cc27b6eb..61c61225d 100644 --- a/tools/dochack/dochack.nim +++ b/tools/dochack/dochack.nim @@ -28,7 +28,7 @@ proc parentWith(x: Element; tag: cstring): Element = proc extractItems(x: Element; items: var seq[Element]) = if x == nil: return - if x.nodeName == "A": + if x.nodeName == cstring"A": items.add x else: for i in 0.. Date: Tue, 14 Aug 2018 01:33:56 +0300 Subject: [PATCH 071/103] Small documentation typo in math --- lib/pure/math.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index eb09bf4a7..641f07c43 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -529,8 +529,8 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} = {.pop.} proc `^`*[T](x: T, y: Natural): T = - ## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use - ## `pow <#pow,float,float>` for negative exponents. + ## Computes ``x`` to the power ``y``. ``x`` must be non-negative, use + ## `pow <#pow,float,float>`_ for negative exponents. when compiles(y >= T(0)): assert y >= T(0) else: From feda366d86e723ff1877a1751cb3eadde8b00cb0 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 14 Aug 2018 00:09:08 +0100 Subject: [PATCH 072/103] Adds get for Option[T]. (#8462) --- lib/pure/options.nim | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/pure/options.nim b/lib/pure/options.nim index ce58943f9..b547c722a 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -129,7 +129,7 @@ proc get*[T](self: Option[T]): T = ## Returns contents of the Option. If it is none, then an exception is ## thrown. if self.isNone: - raise UnpackError(msg : "Can't obtain a value from a `none`") + raise UnpackError(msg: "Can't obtain a value from a `none`") self.val proc get*[T](self: Option[T], otherwise: T): T = @@ -139,6 +139,13 @@ proc get*[T](self: Option[T], otherwise: T): T = else: otherwise +proc get*[T](self: var Option[T]): var T = + ## Returns contents of the Option. If it is none, then an exception is + ## thrown. + if self.isNone: + raise UnpackError(msg: "Can't obtain a value from a `none`") + return self.val + proc map*[T](self: Option[T], callback: proc (input: T)) = ## Applies a callback to the value in this Option if self.isSome: From 83c89197f3fda783819cd0c5de06561c3e6f3616 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 14 Aug 2018 01:28:04 +0200 Subject: [PATCH 073/103] renames threadpool.await to blockUntil; refs #7853 --- changelog.md | 4 +++ doc/manual.rst | 6 ++-- doc/spawn.txt | 6 ++-- lib/pure/concurrency/threadpool.nim | 48 ++++++++++++++--------------- tests/parallel/twaitany.nim | 4 +-- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/changelog.md b/changelog.md index b84cf16a1..e2203e602 100644 --- a/changelog.md +++ b/changelog.md @@ -63,6 +63,10 @@ - ``lineInfoObj`` now returns absolute path instead of project path. It's used by ``lineInfo``, ``check``, ``expect``, ``require``, etc. +- `threadpool`'s `await` and derivatives have been renamed to `blockUntil` + to avoid confusions with `await` from the `async` macro. + + #### Breaking changes in the compiler - The undocumented ``#? braces`` parsing mode was removed. diff --git a/doc/manual.rst b/doc/manual.rst index ea2b74a75..db610f8f8 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -7877,7 +7877,7 @@ that ``spawn`` takes is restricted: ``spawn`` executes the passed expression on the thread pool and returns a `data flow variable`:idx: ``FlowVar[T]`` that can be read from. The reading -with the ``^`` operator is **blocking**. However, one can use ``awaitAny`` to +with the ``^`` operator is **blocking**. However, one can use ``blockUntilAny`` to wait on multiple flow variables at the same time: .. code-block:: nim @@ -7888,10 +7888,10 @@ wait on multiple flow variables at the same time: var responses = newSeq[FlowVarBase](3) for i in 0..2: responses[i] = spawn tellServer(Update, "key", "value") - var index = awaitAny(responses) + var index = blockUntilAny(responses) assert index >= 0 responses.del(index) - discard awaitAny(responses) + discard blockUntilAny(responses) Data flow variables ensure that no data races are possible. Due to technical limitations not every type ``T`` is possible in diff --git a/doc/spawn.txt b/doc/spawn.txt index 522c94464..ab667ff48 100644 --- a/doc/spawn.txt +++ b/doc/spawn.txt @@ -25,7 +25,7 @@ Spawn statement A standalone ``spawn`` statement is a simple construct. It executes the passed expression on the thread pool and returns a `data flow variable`:idx: ``FlowVar[T]`` that can be read from. The reading with the ``^`` operator is -**blocking**. However, one can use ``awaitAny`` to wait on multiple flow +**blocking**. However, one can use ``blockUntilAny`` to wait on multiple flow variables at the same time: .. code-block:: nim @@ -36,10 +36,10 @@ variables at the same time: var responses = newSeq[FlowVarBase](3) for i in 0..2: responses[i] = spawn tellServer(Update, "key", "value") - var index = awaitAny(responses) + var index = blockUntilAny(responses) assert index >= 0 responses.del(index) - discard awaitAny(responses) + discard blockUntilAny(responses) Data flow variables ensure that no data races are possible. Due to technical limitations not every type ``T`` is possible in diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 826e42b6c..f3b13fac5 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -30,7 +30,7 @@ proc destroySemaphore(cv: var Semaphore) {.inline.} = deinitCond(cv.c) deinitLock(cv.L) -proc await(cv: var Semaphore) = +proc blockUntil(cv: var Semaphore) = acquire(cv.L) while cv.counter <= 0: wait(cv.c, cv.L) @@ -81,7 +81,7 @@ proc closeBarrier(b: ptr Barrier) {.compilerProc.} = fence() b.interest = true fence() - while b.left != b.entered: await(b.cv) + while b.left != b.entered: blockUntil(b.cv) destroySemaphore(b.cv) {.pop.} @@ -97,7 +97,7 @@ type FlowVarBaseObj = object of RootObj ready, usesSemaphore, awaited: bool cv: Semaphore #\ - # for 'awaitAny' support + # for 'blockUntilAny' support ai: ptr AwaitInfo idx: int data: pointer # we incRef and unref it to keep it alive; note this MUST NOT @@ -128,12 +128,12 @@ type q: ToFreeQueue readyForTask: Semaphore -proc await*(fv: FlowVarBase) = +proc blockUntil*(fv: FlowVarBase) = ## waits until the value for the flowVar arrives. Usually it is not necessary ## to call this explicitly. if fv.usesSemaphore and not fv.awaited: fv.awaited = true - await(fv.cv) + blockUntil(fv.cv) destroySemaphore(fv.cv) proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool = @@ -141,7 +141,7 @@ proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool = w.data = data w.f = fn signal(w.taskArrived) - await(w.taskStarted) + blockUntil(w.taskStarted) result = true proc cleanFlowVars(w: ptr Worker) = @@ -176,11 +176,11 @@ proc attach(fv: FlowVarBase; i: int): bool = release(fv.cv.L) proc finished(fv: FlowVarBase) = - doAssert fv.ai.isNil, "flowVar is still attached to an 'awaitAny'" + doAssert fv.ai.isNil, "flowVar is still attached to an 'blockUntilAny'" # we have to protect against the rare cases where the owner of the flowVar # simply disregards the flowVar and yet the "flowVar" has not yet written # anything to it: - await(fv) + blockUntil(fv) if fv.data.isNil: return let owner = cast[ptr Worker](fv.owner) let q = addr(owner.q) @@ -189,7 +189,7 @@ proc finished(fv: FlowVarBase) = #echo "EXHAUSTED!" release(q.lock) wakeupWorkerToProcessQueue(owner) - await(q.empty) + blockUntil(q.empty) acquire(q.lock) q.data[q.len] = cast[pointer](fv.data) inc q.len @@ -220,7 +220,7 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) = ## to ``action``. Note that due to Nim's parameter passing semantics this ## means that ``T`` doesn't need to be copied and so ``awaitAndThen`` can ## sometimes be more efficient than ``^``. - await(fv) + blockUntil(fv) when T is string or T is seq: action(cast[T](fv.data)) elif T is ref: @@ -231,29 +231,29 @@ proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) = proc unsafeRead*[T](fv: FlowVar[ref T]): ptr T = ## blocks until the value is available and then returns this value. - await(fv) + blockUntil(fv) result = cast[ptr T](fv.data) proc `^`*[T](fv: FlowVar[ref T]): ref T = ## blocks until the value is available and then returns this value. - await(fv) + blockUntil(fv) let src = cast[ref T](fv.data) deepCopy result, src proc `^`*[T](fv: FlowVar[T]): T = ## blocks until the value is available and then returns this value. - await(fv) + blockUntil(fv) when T is string or T is seq: # XXX closures? deepCopy? result = cast[T](fv.data) else: result = fv.blob -proc awaitAny*(flowVars: openArray[FlowVarBase]): int = +proc blockUntilAny*(flowVars: openArray[FlowVarBase]): int = ## awaits any of the given flowVars. Returns the index of one flowVar for - ## which a value arrived. A flowVar only supports one call to 'awaitAny' at - ## the same time. That means if you awaitAny([a,b]) and awaitAny([b,c]) the second - ## call will only await 'c'. If there is no flowVar left to be able to wait + ## which a value arrived. A flowVar only supports one call to 'blockUntilAny' at + ## the same time. That means if you blockUntilAny([a,b]) and blockUntilAny([b,c]) the second + ## call will only blockUntil 'c'. If there is no flowVar left to be able to wait ## on, -1 is returned. ## **Note**: This results in non-deterministic behaviour and should be avoided. var ai: AwaitInfo @@ -269,7 +269,7 @@ proc awaitAny*(flowVars: openArray[FlowVarBase]): int = inc conflicts if conflicts < flowVars.len: if result < 0: - await(ai.cv) + blockUntil(ai.cv) result = ai.idx for i in 0 .. flowVars.high: discard cas(addr flowVars[i].ai, addr ai, nil) @@ -326,7 +326,7 @@ proc slave(w: ptr Worker) {.thread.} = w.ready = true readyWorker = w signal(gSomeReady) - await(w.taskArrived) + blockUntil(w.taskArrived) # XXX Somebody needs to look into this (why does this assertion fail # in Visual Studio?) when not defined(vcc) and not defined(tcc): assert(not w.ready) @@ -351,7 +351,7 @@ proc distinguishedSlave(w: ptr Worker) {.thread.} = else: w.ready = true signal(w.readyForTask) - await(w.taskArrived) + blockUntil(w.taskArrived) assert(not w.ready) w.f(w, w.data) if w.q.len != 0: w.cleanFlowVars @@ -499,7 +499,7 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} = # on the current thread instead. var self = addr(workersData[localThreadId-1]) fn(self, data) - await(self.taskStarted) + blockUntil(self.taskStarted) return if isSlave: @@ -524,7 +524,7 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} = inc numSlavesWaiting - await(gSomeReady) + blockUntil(gSomeReady) if isSlave: withLock numSlavesLock: @@ -542,7 +542,7 @@ proc nimSpawn4(fn: WorkerProc; data: pointer; id: ThreadId) {.compilerProc.} = release(distinguishedLock) while true: if selectWorker(addr(distinguishedData[id]), fn, data): break - await(distinguishedData[id].readyForTask) + blockUntil(distinguishedData[id].readyForTask) proc sync*() = @@ -555,7 +555,7 @@ proc sync*() = if not allReady: break allReady = allReady and workersData[i].ready if allReady: break - await(gSomeReady) + blockUntil(gSomeReady) inc toRelease for i in 0 ..< toRelease: diff --git a/tests/parallel/twaitany.nim b/tests/parallel/twaitany.nim index 69136a3b6..fcabf691e 100644 --- a/tests/parallel/twaitany.nim +++ b/tests/parallel/twaitany.nim @@ -18,12 +18,12 @@ var results: seq[int] = @[] for i in 0 .. durations.high: tasks.add spawn timer(durations[i]) -var index = awaitAny(tasks) +var index = blockUntilAny(tasks) while index != -1: results.add ^cast[FlowVar[int]](tasks[index]) tasks.del(index) #echo repr results - index = awaitAny(tasks) + index = blockUntilAny(tasks) doAssert results.len == 5 doAssert 1000 in results From 18859cbaa1d1261d58ab6ceea2635c8dd02c2175 Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 14 Aug 2018 01:36:02 +0200 Subject: [PATCH 074/103] make nimweb compile again --- lib/impure/re.nim | 2 +- tools/website.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 50a5441e8..a60f70828 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -613,7 +613,7 @@ when isMainModule: doAssert false if "abc" =~ re"(cba)?.*": - doAssert matches[0] == nil + doAssert matches[0] == "" else: doAssert false if "abc" =~ re"().*": diff --git a/tools/website.tmpl b/tools/website.tmpl index f9b1a219a..9e5eb2460 100644 --- a/tools/website.tmpl +++ b/tools/website.tmpl @@ -203,7 +203,7 @@ runForever() # if currentTab == "index": # end if -# if c.gaId != nil: +# if c.gaId.len != 0: