From d2d849db8e3628096b57f3e03668cf9da6b2d560 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:19:30 +0800 Subject: [PATCH 001/489] docuement case statement breaking changes in the changelog (#21686) Reported on Discord follow up https://github.com/nim-lang/Nim/pull/20862 --- changelogs/changelog_2_0_0.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 779eec529e..bb0a9bf4d4 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -221,6 +221,9 @@ - Signed integer literals in `set` literals now default to a range type of `0..255` instead of `0..65535` (the maximum size of sets). + +- Case statements with else branches put before elif/of branches in macros + are rejected with "invalid order of case branches". ## Standard library additions and changes From 0d6b994bee6098dfa212a124d4b20fa700aa28ad Mon Sep 17 00:00:00 2001 From: Bung Date: Wed, 19 Apr 2023 00:50:49 -0700 Subject: [PATCH 002/489] fix #20997 (#21165) * fix #20997 * use ptr UncheckedArray[uint8] instead --- lib/system/sets.nim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/system/sets.nim b/lib/system/sets.nim index e230985e0b..5f7c3e37b8 100644 --- a/lib/system/sets.nim +++ b/lib/system/sets.nim @@ -9,10 +9,8 @@ # set handling -type - NimSet = array[0..8192-1, uint8] -proc cardSetImpl(s: openArray[uint8], len: int): int {.inline.} = +proc cardSetImpl(s: ptr UncheckedArray[uint8], len: int): int {.inline.} = var i = 0 result = 0 when defined(x86) or defined(amd64): @@ -24,5 +22,5 @@ proc cardSetImpl(s: openArray[uint8], len: int): int {.inline.} = inc(result, countBits32(uint32(s[i]))) inc(i, 1) -proc cardSet(s: NimSet, len: int): int {.compilerproc, inline.} = +proc cardSet(s: ptr UncheckedArray[uint8], len: int): int {.compilerproc, inline.} = result = cardSetImpl(s, len) From 9cb06d357e75bdf74f99e1e982841d8bbe90ae0e Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 19 Apr 2023 17:55:54 +0800 Subject: [PATCH 003/489] fixes #21540; deref block at transf phase to make injectdestructors function properly (#21688) * fixes #21540; deref block at transf phase to make injectdestructors function properly * add a test case * add one more test * fixes the type of block * transform block --- compiler/ccgexprs.nim | 15 +--------- compiler/transf.nim | 16 +++++++++- tests/ccgbugs/tderefblock.nim | 55 +++++++++++++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 17 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 44466fb571..5a8e2d296e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -752,21 +752,8 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} = skipTypes(typ, abstractInstOwned).kind in {tyVar} and tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags -proc derefBlock(p: BProc, e: PNode, d: var TLoc) = - # We transform (block: x)[] to (block: x[]) - let e0 = e[0] - var n = shallowCopy(e0) - n.typ = e.typ - for i in 0 ..< e0.len - 1: - n[i] = e0[i] - n[e0.len-1] = newTreeIT(nkHiddenDeref, e.info, e.typ, e0[e0.len-1]) - expr p, n, d - proc genDeref(p: BProc, e: PNode, d: var TLoc) = - if e.kind == nkHiddenDeref and e[0].kind in {nkBlockExpr, nkBlockStmt}: - # bug #20107. Watch out to not deref the pointer too late. - derefBlock(p, e, d) - return + assert e[0].kind notin {nkBlockExpr, nkBlockStmt}, "it should have been transformed in transf" let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0])) if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags: diff --git a/compiler/transf.nim b/compiler/transf.nim index 445bc1df18..752d031e14 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -941,6 +941,15 @@ proc commonOptimizations*(g: ModuleGraph; idgen: IdGenerator; c: PSym, n: PNode) else: result = n +proc transformDerefBlock(c: PTransf, n: PNode): PNode = + # We transform (block: x)[] to (block: x[]) + let e0 = n[0] + result = shallowCopy(e0) + result.typ = n.typ + for i in 0 ..< e0.len - 1: + result[i] = e0[i] + result[e0.len-1] = newTreeIT(nkHiddenDeref, n.info, n.typ, e0[e0.len-1]) + proc transform(c: PTransf, n: PNode): PNode = when false: var oldDeferAnchor: PNode @@ -1012,7 +1021,12 @@ proc transform(c: PTransf, n: PNode): PNode = of nkAddr: result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref}) of nkDerefExpr, nkHiddenDeref: - result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr}) + if n[0].kind in {nkBlockExpr, nkBlockStmt}: + # bug #20107 bug #21540. Watch out to not deref the pointer too late. + let e = transformDerefBlock(c, n) + result = transformBlock(c, e) + else: + result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr}) of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = transformConv(c, n) of nkDiscardStmt: diff --git a/tests/ccgbugs/tderefblock.nim b/tests/ccgbugs/tderefblock.nim index fd21a19b87..d3ba076679 100644 --- a/tests/ccgbugs/tderefblock.nim +++ b/tests/ccgbugs/tderefblock.nim @@ -1,6 +1,5 @@ discard """ - cmd: "nim c -d:release -d:danger $file" - matrix: ";--gc:orc" + matrix: "--mm:refc -d:release -d:danger;--mm:orc -d:useMalloc -d:release -d:danger" output: "42" """ @@ -23,3 +22,55 @@ proc m() = echo $f.a m() + +block: # bug #21540 + type + Option = object + val: string + has: bool + + proc some(val: string): Option = + result.has = true + result.val = val + + # Remove lent and it works + proc get(self: Option): lent string = + result = self.val + + type + StringStream = ref object + data: string + pos: int + + proc readAll(s: StringStream): string = + result = newString(s.data.len) + copyMem(addr(result[0]), addr(s.data[0]), s.data.len) + + proc newStringStream(s: string = ""): StringStream = + new(result) + result.data = s + + proc parseJson(s: string): string = + let stream = newStringStream(s) + result = stream.readAll() + + proc main = + let initialFEN = block: + let initialFEN = some parseJson("startpos") + initialFEN.get + + doAssert initialFEN == "startpos" + + main() + +import std/[ + json, + options +] + +block: # bug #21540 + let cheek = block: + let initialFEN = some("""{"initialFen": "startpos"}""".parseJson{"initialFen"}.getStr) + initialFEN.get + + doAssert cheek == "startpos" From 135b677704110af999797ee375a15a7e33af04c4 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 19 Apr 2023 17:56:12 +0800 Subject: [PATCH 004/489] fixes nightlies regression (#21689) * fixes nightlies regression ref https://github.com/nim-lang/Nim/pull/21659 ref https://github.com/nim-lang/nightlies/actions/runs/4727252660/jobs/8387899690 > /home/runner/work/nightlies/nightlies/nim-1.9.3/lib/std/sysrand.nim(198, 12) Error: cannot evaluate at compile time: EINTR Because EINTR is not a const on i386 * Update lib/std/sysrand.nim --- lib/std/sysrand.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim index b5f61372a3..d57f2845e5 100644 --- a/lib/std/sysrand.nim +++ b/lib/std/sysrand.nim @@ -194,8 +194,7 @@ elif defined(linux) and not defined(nimNoGetRandom) and not defined(emscripten): elif readBytes > 0: inc(result, readBytes) else: - case osLastError().int - of EINTR, EAGAIN: discard + if osLastError().cint in [EINTR, EAGAIN]: discard else: result = -1 break From ed7c6cdc984b12a30a44344167083ec0dc46cf9a Mon Sep 17 00:00:00 2001 From: Thiago <74574275+thisago@users.noreply.github.com> Date: Wed, 19 Apr 2023 19:51:23 +0000 Subject: [PATCH 005/489] Fixed `window.find` return (#21621) https://developer.mozilla.org/en-US/docs/Web/API/Window/find --- lib/js/dom.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 36434846a1..0a825865b3 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1503,7 +1503,7 @@ proc confirm*(w: Window, msg: cstring): bool proc disableExternalCapture*(w: Window) proc enableExternalCapture*(w: Window) proc find*(w: Window, text: cstring, caseSensitive = false, - backwards = false) + backwards = false): bool proc focus*(w: Window) proc forward*(w: Window) proc getComputedStyle*(w: Window, e: Node, pe: Node = nil): Style From f9477396a6f21beaa8ffd3de19129b11fe7169f1 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 20 Apr 2023 23:35:15 +0800 Subject: [PATCH 006/489] static link pthread correctly (#21693) --- config/nim.cfg | 3 +++ lib/std/typedthreads.nim | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config/nim.cfg b/config/nim.cfg index a1559e24ac..13665936b6 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -179,6 +179,9 @@ nimblepath="$home/.nimble/pkgs/" # Configuration for the GNU C/C++ compiler: @if windows: #gcc.path = r"$nim\dist\mingw\bin" + @if gcc: + gcc.options.linker %= "-Wl,-Bstatic -lpthread" + @end @if tcc: tlsEmulation:on @end diff --git a/lib/std/typedthreads.nim b/lib/std/typedthreads.nim index 6cc5dd9e0a..2c1cf6f1d6 100644 --- a/lib/std/typedthreads.nim +++ b/lib/std/typedthreads.nim @@ -35,8 +35,6 @@ ## deinitLock(L) -when defined(windows) and defined(gcc) and (not compileOption("tlsEmulation")): - {.passl: "-Wl,-Bstatic -lpthread -Wl,-Bdynamic".} import std/private/[threadtypes] export Thread From 418e54452b28d2854fb1106be06e231dac842cf1 Mon Sep 17 00:00:00 2001 From: Yardanico Date: Fri, 21 Apr 2023 07:11:30 +0300 Subject: [PATCH 007/489] Fix json.to for float fields that are not present (#21695) --- lib/pure/json.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 45b22cea51..7ccd3c43f5 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1123,6 +1123,7 @@ proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var dst = cast[T](jsonNode.num) proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) = + verifyJsonKind(jsonNode, {JInt, JFloat, JString}, jsonPath) if jsonNode.kind == JString: case jsonNode.str of "nan": @@ -1138,7 +1139,6 @@ proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var st dst = T(b) else: raise newException(JsonKindError, "expected 'nan|inf|-inf', got " & jsonNode.str) else: - verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath) if jsonNode.kind == JFloat: dst = T(jsonNode.fnum) else: From d76458a6cd126a338f7499b1012559883ae7fe5d Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 21 Apr 2023 18:05:50 +0800 Subject: [PATCH 008/489] add test for #13764 (#21699) --- tests/sets/t13764.nim | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/sets/t13764.nim diff --git a/tests/sets/t13764.nim b/tests/sets/t13764.nim new file mode 100644 index 0000000000..1634f113d9 --- /dev/null +++ b/tests/sets/t13764.nim @@ -0,0 +1,6 @@ +discard """ +errormsg: "conversion from int literal(1000000) to range 0..255(int) is invalid" +line: 6 +""" + +let a = {1_000_000} # Compiles From 175a83c2de436b0e84f232fd44d264fb2c79fb14 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Fri, 21 Apr 2023 06:06:20 -0400 Subject: [PATCH 009/489] refact: Remove assertion effect hiding workaround (#21472) refact: Remove asseertion effect hiding workaround There was a code comment to remove after bootstrapping with `nim >= 1.4.0`. Co-authored-by: quantimnot Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- lib/std/assertions.nim | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/std/assertions.nim b/lib/std/assertions.nim index a249d77516..3dca644ad6 100644 --- a/lib/std/assertions.nim +++ b/lib/std/assertions.nim @@ -38,12 +38,7 @@ proc raiseAssert*(msg: string) {.noinline, noreturn, nosinks.} = proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = ## Raises an `AssertionDefect` with `msg`, but this is hidden ## from the effect system. Called when an assertion failed. - # trick the compiler to not list `AssertionDefect` when called - # by `assert`. - # xxx simplify this pending bootstrap >= 1.4.0, after which cast not needed - # anymore since `Defect` can't be raised. - type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, tags: [].} - cast[Hide](raiseAssert)(msg) + raiseAssert(msg) template assertImpl(cond: bool, msg: string, expr: string, enabled: static[bool]) = when enabled: From b54b03d04fc19d18e079ee759730298e2ecd63fd Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 21 Apr 2023 21:36:18 +0800 Subject: [PATCH 010/489] tweak spellsuggest; three counts for equal distances candidates by default (#21700) * tweak spellsuggest; three counts for equal distances candidates * only suggest typos when length > 3 --- compiler/lookups.nim | 9 +++------ tests/misc/tspellsuggest2.nim | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index fc84b90513..8b98ea3f1c 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -490,12 +490,9 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) = let e = list.pop() if c.config.spellSuggestMax == spellSuggestSecretSauce: const - smallThres = 2 - maxCountForSmall = 4 - # avoids ton of operator matches when mis-matching short symbols such as `i` - # other heuristics could be devised, such as only suggesting operators if `name0` - # is an operator (likewise with non-operators). - if e.dist > e0.dist or (name0.len <= smallThres and count >= maxCountForSmall): break + minLengthForSuggestion = 4 + maxCount = 3 # avoids ton of matches; three counts for equal distances + if e.dist > e0.dist or count >= maxCount or name0.len < minLengthForSuggestion: break elif count >= c.config.spellSuggestMax: break if count == 0: result.add "\ncandidates (edit distance, scope distance); see '--spellSuggest': " diff --git a/tests/misc/tspellsuggest2.nim b/tests/misc/tspellsuggest2.nim index bf76cc2087..d20fb00dc5 100644 --- a/tests/misc/tspellsuggest2.nim +++ b/tests/misc/tspellsuggest2.nim @@ -1,6 +1,6 @@ discard """ # pending bug #16521 (bug 12) use `matrix` - cmd: "nim c --spellsuggest --hints:off $file" + cmd: "nim c --spellsuggest:12 --hints:off $file" action: "reject" nimout: ''' tspellsuggest2.nim(45, 13) Error: undeclared identifier: 'fooBar' From 48de0d0cf47131bd7e096418563463b80d43994d Mon Sep 17 00:00:00 2001 From: Raynei Date: Fri, 21 Apr 2023 09:37:21 -0400 Subject: [PATCH 011/489] Documented path substitution by compiler (#21662) Document compiler path substitution (nim-lang#19928) --- doc/manual.md | 2 ++ doc/nimc.md | 11 +++++++++++ lib/system/nimscript.nim | 1 + 3 files changed, 14 insertions(+) diff --git a/doc/manual.md b/doc/manual.md index f5ee10fda3..c381ab4100 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -6676,6 +6676,8 @@ even when one version does not export some of these identifiers. The `import` statement is only allowed at the top level. +String literals can be used for import/include statements. +The compiler performs [path substitution](nimc.html#compiler-usage-commandminusline-switches) when used. Include statement ----------------- diff --git a/doc/nimc.md b/doc/nimc.md index d367c66200..4f715ee83a 100644 --- a/doc/nimc.md +++ b/doc/nimc.md @@ -32,6 +32,17 @@ Compiler Usage Command-line switches --------------------- +All options that take a `PATH` or `DIR` argument are subject to path substitution: + +- `$nim`: The global nim prefix path +- `$lib`: The stdlib path +- `$home` and `~`: The user's home path +- `$config`: The directory of the module currently being compiled +- `$projectname`: The project file's name without file extension +- `$projectpath` and `$projectdir`: The project file's path +- `$nimcache`: The nimcache path + + Basic command-line switches are: .. no syntax highlighting in the below included files at the moment diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 0b49ea2e74..9ce475e5b1 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -86,6 +86,7 @@ proc patchFile*(package, filename, replacement: string) = ## is interpreted to be local to the Nimscript file that contains ## the call to `patchFile`, Nim's `--path` is not used at all ## to resolve the filename! + ## The compiler also performs `path substitution `_ on `replacement`. ## ## Example: ## From 4fa86422c057ae0615a6f06a6fd0a538e1bce029 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 21 Apr 2023 21:37:58 +0800 Subject: [PATCH 012/489] stdlib tests now check refc too (#21664) * stdlib tests now check refc too * typo * fixes line numbers * disable cpp * do not touch --- tests/ccgbugs/t21116.nim | 2 +- tests/coroutines/tgc.nim | 2 +- tests/coroutines/twait.nim | 2 +- tests/js/tsourcemap.nim | 2 +- tests/parallel/t10913.nim | 2 +- tests/parallel/t7535.nim | 2 +- tests/parallel/t9691.nim | 2 +- tests/specialops/terrmsgs.nim | 2 +- tests/statictypes/tstatictypes.nim | 2 +- tests/stdlib/concurrency/tatomics.nim | 4 ++++ tests/stdlib/concurrency/tatomics_size.nim | 1 + tests/stdlib/talgorithm.nim | 1 + tests/stdlib/tarithmetics.nim | 1 + tests/stdlib/tasynchttpserver_transferencoding.nim | 2 +- tests/stdlib/tbase64.nim | 1 + tests/stdlib/tbitops.nim | 1 + tests/stdlib/tbitops_utils.nim | 4 ++++ tests/stdlib/tcgi.nim | 4 ++++ tests/stdlib/tcmdline.nim | 1 + tests/stdlib/tcomplex.nim | 4 ++++ tests/stdlib/tcookies.nim | 1 + tests/stdlib/tcritbits.nim | 1 + tests/stdlib/tcstrutils.nim | 1 + tests/stdlib/tdecls.nim | 1 + tests/stdlib/tdeques.nim | 2 +- tests/stdlib/tdiff.nim | 1 + tests/stdlib/tdochelpers.nim | 1 + tests/stdlib/teditdistance.nim | 4 ++++ tests/stdlib/tencodings.nim | 4 ++++ tests/stdlib/tenumerate.nim | 4 ++++ tests/stdlib/tenumutils.nim | 1 + tests/stdlib/tenvvars.nim | 2 +- tests/stdlib/texitprocs.nim | 1 + tests/stdlib/tfdleak.nim | 2 +- tests/stdlib/tfrexp1.nim | 1 + tests/stdlib/tgetaddrinfo.nim | 1 + tests/stdlib/tgetfileinfo.nim | 1 + tests/stdlib/tgetprotobyname.nim | 4 ++++ tests/stdlib/tglobs.nim | 4 ++++ tests/stdlib/thashes.nim | 2 +- tests/stdlib/theapqueue.nim | 4 ++++ tests/stdlib/thighlite.nim | 3 +++ tests/stdlib/thtmlparser.nim | 1 + tests/stdlib/thttpcore.nim | 4 ++++ tests/stdlib/timportutils.nim | 4 ++++ tests/stdlib/tio.nim | 4 ++++ tests/stdlib/tjsonmacro.nim | 1 + tests/stdlib/tjsonutils.nim | 1 + tests/stdlib/tlists.nim | 1 + tests/stdlib/tlocks.nim | 2 +- tests/stdlib/tmacros.nim | 4 ++++ tests/stdlib/tmath.nim | 2 +- tests/stdlib/tmd5.nim | 1 + tests/stdlib/tmget.nim | 1 + tests/stdlib/tmimetypes.nim | 1 + tests/stdlib/tmisc_issues.nim | 1 + tests/stdlib/tmitems.nim | 1 + tests/stdlib/tmonotimes.nim | 1 + tests/stdlib/tnativesockets.nim | 4 ++++ tests/stdlib/tnet.nim | 1 + tests/stdlib/tnet_ll.nim | 1 + tests/stdlib/tnetbind.nim | 1 + tests/stdlib/tnre.nim | 1 + tests/stdlib/tntpath.nim | 4 ++++ tests/stdlib/topenssl.nim | 4 ++++ tests/stdlib/toptions.nim | 1 + tests/stdlib/tos.nim | 1 + tests/stdlib/tos_unc.nim | 1 + tests/stdlib/tosenv.nim | 2 +- tests/stdlib/tosproc.nim | 1 + tests/stdlib/tosprocterminate.nim | 2 +- tests/stdlib/tpackedsets.nim | 4 ++++ tests/stdlib/tparsecfg.nim | 1 + tests/stdlib/tparsecsv.nim | 4 ++++ tests/stdlib/tparseipv6.nim | 1 + tests/stdlib/tparsesql.nim | 1 + tests/stdlib/tparseuints.nim | 4 ++++ tests/stdlib/tparseutils.nim | 1 + tests/stdlib/tpathnorm.nim | 1 + tests/stdlib/tpaths.nim | 4 ++++ tests/stdlib/tpegs.nim | 1 + tests/stdlib/tposix.nim | 3 ++- tests/stdlib/trandom.nim | 2 +- tests/stdlib/trationals.nim | 4 ++++ tests/stdlib/tre.nim | 4 ++++ tests/stdlib/tregex.nim | 1 + tests/stdlib/tregistry.nim | 2 +- tests/stdlib/trepr.nim | 2 +- tests/stdlib/tropes.nim | 1 + tests/stdlib/trst.nim | 1 + tests/stdlib/trstgen.nim | 1 + tests/stdlib/tsequtils.nim | 1 + tests/stdlib/tsetutils.nim | 1 + tests/stdlib/tsha1.nim | 4 ++++ tests/stdlib/tsharedlist.nim | 2 +- tests/stdlib/tsharedtable.nim | 2 +- tests/stdlib/tsocketstreams.nim | 1 + tests/stdlib/tsortcall.nim | 2 +- tests/stdlib/tsqlparser.nim | 1 + tests/stdlib/tssl.nim | 1 + tests/stdlib/tstats.nim | 4 ++++ tests/stdlib/tstdlib_issues.nim | 1 + tests/stdlib/tstrbasics.nim | 2 +- tests/stdlib/tstreams.nim | 2 +- tests/stdlib/tstrformat.nim | 4 +++- tests/stdlib/tstrimpl.nim | 4 ++++ tests/stdlib/tstring.nim | 1 + tests/stdlib/tstrmiscs.nim | 4 ++++ tests/stdlib/tstrscans.nim | 2 +- tests/stdlib/tstrset.nim | 4 ++++ tests/stdlib/tstrtabs.nim | 1 + tests/stdlib/tstrtabs2.nim | 1 + tests/stdlib/tstrutils.nim | 2 +- tests/stdlib/tsugar.nim | 1 + tests/stdlib/tsums.nim | 4 ++++ tests/stdlib/tsysrand.nim | 2 +- tests/stdlib/tsystem.nim | 1 + tests/stdlib/ttables.nim | 4 ++++ tests/stdlib/ttempfiles.nim | 1 + tests/stdlib/tthreadpool.nim | 2 +- tests/stdlib/ttimes.nim | 2 +- tests/stdlib/ttypeinfo.nim | 4 ++++ tests/stdlib/ttypetraits.nim | 1 + tests/stdlib/tunicode.nim | 4 ++++ tests/stdlib/tunittest.nim | 1 + tests/stdlib/tunittestpass.nim | 1 + tests/stdlib/turi.nim | 1 + tests/stdlib/tuserlocks.nim | 2 +- tests/stdlib/tvarargs.nim | 2 +- tests/stdlib/tvarints.nim | 4 ++++ tests/stdlib/tvmutils.nim | 2 +- tests/stdlib/twchartoutf8.nim | 1 + tests/stdlib/twith.nim | 4 ++++ tests/stdlib/twordwrap.nim | 4 ++++ tests/stdlib/twrapnils.nim | 4 ++++ tests/stdlib/txmltree.nim | 4 ++++ tests/stdlib/tyield.nim | 1 + tests/system/tdollars.nim | 2 +- tests/system/tslimsystem.nim | 2 +- tests/vm/t9622.nim | 2 +- 140 files changed, 256 insertions(+), 39 deletions(-) diff --git a/tests/ccgbugs/t21116.nim b/tests/ccgbugs/t21116.nim index 6418df5397..cc77de1982 100644 --- a/tests/ccgbugs/t21116.nim +++ b/tests/ccgbugs/t21116.nim @@ -1,5 +1,5 @@ discard """ - target: "c cpp" + targets: "c cpp" disabled: windows """ # bug #21116 diff --git a/tests/coroutines/tgc.nim b/tests/coroutines/tgc.nim index e2f8b64697..770d413f5c 100644 --- a/tests/coroutines/tgc.nim +++ b/tests/coroutines/tgc.nim @@ -1,6 +1,6 @@ discard """ matrix: "--gc:refc; --gc:arc; --gc:orc" - target: "c" + targets: "c" """ when compileOption("gc", "refc") or not defined(openbsd): diff --git a/tests/coroutines/twait.nim b/tests/coroutines/twait.nim index 71782ece16..2edfcf675b 100644 --- a/tests/coroutines/twait.nim +++ b/tests/coroutines/twait.nim @@ -1,7 +1,7 @@ discard """ output: "Exit 1\nExit 2" matrix: "--gc:refc; --gc:arc; --gc:orc" - target: "c" + targets: "c" """ when compileOption("gc", "refc") or not defined(openbsd): diff --git a/tests/js/tsourcemap.nim b/tests/js/tsourcemap.nim index ff6f6122f5..d358e4a57f 100644 --- a/tests/js/tsourcemap.nim +++ b/tests/js/tsourcemap.nim @@ -1,6 +1,6 @@ discard """ action: "run" - target: "js" + targets: "js" cmd: "nim js -r -d:nodejs $options --sourceMap:on $file" """ import std/[os, json, strutils, sequtils, algorithm, assertions, paths, compilesettings] diff --git a/tests/parallel/t10913.nim b/tests/parallel/t10913.nim index d8459ecd0c..191939100f 100644 --- a/tests/parallel/t10913.nim +++ b/tests/parallel/t10913.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--threads:on" + matrix: "--mm:refc; --mm:orc" errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter" """ diff --git a/tests/parallel/t7535.nim b/tests/parallel/t7535.nim index 052dcdc3a5..7817a1c9e9 100644 --- a/tests/parallel/t7535.nim +++ b/tests/parallel/t7535.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--threads:on" + matrix: "--mm:refc; --mm:orc" errormsg: "'spawn' takes a call expression; got: proc (x: uint32) = echo [x]" """ diff --git a/tests/parallel/t9691.nim b/tests/parallel/t9691.nim index bbf2b1bc78..254f03416d 100644 --- a/tests/parallel/t9691.nim +++ b/tests/parallel/t9691.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--threads:on" + matrix: "--mm:refc; --mm:orc" errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter" """ diff --git a/tests/specialops/terrmsgs.nim b/tests/specialops/terrmsgs.nim index d1a790e540..081bca4510 100644 --- a/tests/specialops/terrmsgs.nim +++ b/tests/specialops/terrmsgs.nim @@ -1,7 +1,7 @@ discard """ action: reject cmd: '''nim check $options $file''' -matrix: "; -d:testWithout" +matrix: "; -d:testWithout; --mm:refc" """ when not defined(testWithout): # test for same errors before and after diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim index 9b2d81b258..ac84c4a31c 100644 --- a/tests/statictypes/tstatictypes.nim +++ b/tests/statictypes/tstatictypes.nim @@ -22,7 +22,7 @@ heyho Val1 Val1 ''' -matrix: "--hints:off" +matrix: "--hints:off --mm:orc; --hints:off --mm:refc" """ import macros diff --git a/tests/stdlib/concurrency/tatomics.nim b/tests/stdlib/concurrency/tatomics.nim index 9cfdce83d0..3fb5197dae 100644 --- a/tests/stdlib/concurrency/tatomics.nim +++ b/tests/stdlib/concurrency/tatomics.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + # test atomic operations import std/[atomics, bitops] diff --git a/tests/stdlib/concurrency/tatomics_size.nim b/tests/stdlib/concurrency/tatomics_size.nim index 7b43787fbe..cfe568623d 100644 --- a/tests/stdlib/concurrency/tatomics_size.nim +++ b/tests/stdlib/concurrency/tatomics_size.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp" """ import std/atomics diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 83a84f956a..e2024df0c3 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -1,5 +1,6 @@ discard """ targets: "c js" + matrix: "--mm:refc; --mm:orc" output:'''@["3", "2", "1"] ''' """ diff --git a/tests/stdlib/tarithmetics.nim b/tests/stdlib/tarithmetics.nim index a69334e71c..0a6dd1fcfd 100644 --- a/tests/stdlib/tarithmetics.nim +++ b/tests/stdlib/tarithmetics.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ import std/assertions diff --git a/tests/stdlib/tasynchttpserver_transferencoding.nim b/tests/stdlib/tasynchttpserver_transferencoding.nim index dae87be825..886ba0f33f 100644 --- a/tests/stdlib/tasynchttpserver_transferencoding.nim +++ b/tests/stdlib/tasynchttpserver_transferencoding.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--gc:arc --threads:on; --gc:arc --threads:on -d:danger; --threads:on" + matrix: "--mm:arc; --mm:arc -d:danger; --mm:refc" disabled: "freebsd" """ diff --git a/tests/stdlib/tbase64.nim b/tests/stdlib/tbase64.nim index 60fa3865d6..5739b1621c 100644 --- a/tests/stdlib/tbase64.nim +++ b/tests/stdlib/tbase64.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ import std/assertions diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim index c90943a93c..3ecab2c647 100644 --- a/tests/stdlib/tbitops.nim +++ b/tests/stdlib/tbitops.nim @@ -1,5 +1,6 @@ discard """ nimout: "OK" + matrix: "--mm:refc; --mm:orc" output: ''' OK ''' diff --git a/tests/stdlib/tbitops_utils.nim b/tests/stdlib/tbitops_utils.nim index 7a64ea68db..e3f96fecce 100644 --- a/tests/stdlib/tbitops_utils.nim +++ b/tests/stdlib/tbitops_utils.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/private/bitops_utils import std/assertions diff --git a/tests/stdlib/tcgi.nim b/tests/stdlib/tcgi.nim index 7a52dc89b6..ef39450dab 100644 --- a/tests/stdlib/tcgi.nim +++ b/tests/stdlib/tcgi.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/unittest import std/[cgi, strtabs, sugar] import std/assertions diff --git a/tests/stdlib/tcmdline.nim b/tests/stdlib/tcmdline.nim index 5c0f717724..8b428900b5 100644 --- a/tests/stdlib/tcmdline.nim +++ b/tests/stdlib/tcmdline.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" joinable: false """ diff --git a/tests/stdlib/tcomplex.nim b/tests/stdlib/tcomplex.nim index c7666be84e..812bcdc773 100644 --- a/tests/stdlib/tcomplex.nim +++ b/tests/stdlib/tcomplex.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/[complex, math] import std/assertions diff --git a/tests/stdlib/tcookies.nim b/tests/stdlib/tcookies.nim index 4fe104dfc2..3ff0f3baee 100644 --- a/tests/stdlib/tcookies.nim +++ b/tests/stdlib/tcookies.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tcritbits.nim b/tests/stdlib/tcritbits.nim index 0c2e1d6fad..e6282f0456 100644 --- a/tests/stdlib/tcritbits.nim +++ b/tests/stdlib/tcritbits.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tcstrutils.nim b/tests/stdlib/tcstrutils.nim index ec2b8596ca..e73b2b6810 100644 --- a/tests/stdlib/tcstrutils.nim +++ b/tests/stdlib/tcstrutils.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ diff --git a/tests/stdlib/tdecls.nim b/tests/stdlib/tdecls.nim index 5cf352cfbf..c17fd33431 100644 --- a/tests/stdlib/tdecls.nim +++ b/tests/stdlib/tdecls.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ import std/assertions diff --git a/tests/stdlib/tdeques.nim b/tests/stdlib/tdeques.nim index fcfc278a95..49072b1504 100644 --- a/tests/stdlib/tdeques.nim +++ b/tests/stdlib/tdeques.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--gc:refc; --gc:orc" + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ diff --git a/tests/stdlib/tdiff.nim b/tests/stdlib/tdiff.nim index cb9cebb3a8..132f7120bd 100644 --- a/tests/stdlib/tdiff.nim +++ b/tests/stdlib/tdiff.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tdochelpers.nim b/tests/stdlib/tdochelpers.nim index 300ce76dc6..4d532b5d0e 100644 --- a/tests/stdlib/tdochelpers.nim +++ b/tests/stdlib/tdochelpers.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" output: ''' [Suite] Integration with Nim diff --git a/tests/stdlib/teditdistance.nim b/tests/stdlib/teditdistance.nim index b3b323647b..14ba6df976 100644 --- a/tests/stdlib/teditdistance.nim +++ b/tests/stdlib/teditdistance.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/editdistance import std/assertions diff --git a/tests/stdlib/tencodings.nim b/tests/stdlib/tencodings.nim index 10d79f5d08..e5e89ef379 100644 --- a/tests/stdlib/tencodings.nim +++ b/tests/stdlib/tencodings.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/encodings import std/assertions diff --git a/tests/stdlib/tenumerate.nim b/tests/stdlib/tenumerate.nim index b15b9e2db2..2789ebe3ae 100644 --- a/tests/stdlib/tenumerate.nim +++ b/tests/stdlib/tenumerate.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/enumerate import std/assertions diff --git a/tests/stdlib/tenumutils.nim b/tests/stdlib/tenumutils.nim index 63c5637398..67b98efe1e 100644 --- a/tests/stdlib/tenumutils.nim +++ b/tests/stdlib/tenumutils.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tenvvars.nim b/tests/stdlib/tenvvars.nim index 03a46a0139..1a07f02b85 100644 --- a/tests/stdlib/tenvvars.nim +++ b/tests/stdlib/tenvvars.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--threads:on" + matrix: "--mm:refc; --mm:orc" joinable: false targets: "c js cpp" """ diff --git a/tests/stdlib/texitprocs.nim b/tests/stdlib/texitprocs.nim index 9d5378fe82..ea29d8f586 100644 --- a/tests/stdlib/texitprocs.nim +++ b/tests/stdlib/texitprocs.nim @@ -1,4 +1,5 @@ discard """ +matrix: "--mm:refc; --mm:orc" targets: "c cpp js" output: ''' ok4 diff --git a/tests/stdlib/tfdleak.nim b/tests/stdlib/tfdleak.nim index 1ac746e488..272a7507c0 100644 --- a/tests/stdlib/tfdleak.nim +++ b/tests/stdlib/tfdleak.nim @@ -1,7 +1,7 @@ discard """ exitcode: 0 output: "" - matrix: "; -d:nimInheritHandles" + matrix: "; -d:nimInheritHandles; --mm:refc" joinable: false """ diff --git a/tests/stdlib/tfrexp1.nim b/tests/stdlib/tfrexp1.nim index 6b4c3b6d3e..aa734ddac8 100644 --- a/tests/stdlib/tfrexp1.nim +++ b/tests/stdlib/tfrexp1.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "js c cpp" """ diff --git a/tests/stdlib/tgetaddrinfo.nim b/tests/stdlib/tgetaddrinfo.nim index a8bcecb0c5..3a90034c81 100644 --- a/tests/stdlib/tgetaddrinfo.nim +++ b/tests/stdlib/tgetaddrinfo.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" exitcode: 0 output: "" """ diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim index d0413f7576..ae1480a4c0 100644 --- a/tests/stdlib/tgetfileinfo.nim +++ b/tests/stdlib/tgetfileinfo.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" output: "pcDir\npcFile\npcLinkToDir\npcLinkToFile\n" joinable: false """ diff --git a/tests/stdlib/tgetprotobyname.nim b/tests/stdlib/tgetprotobyname.nim index e524510b28..1fc060ffe4 100644 --- a/tests/stdlib/tgetprotobyname.nim +++ b/tests/stdlib/tgetprotobyname.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import nativesockets import std/assertions diff --git a/tests/stdlib/tglobs.nim b/tests/stdlib/tglobs.nim index 69ff31938b..4aa21992c3 100644 --- a/tests/stdlib/tglobs.nim +++ b/tests/stdlib/tglobs.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/private/globs import std/assertions diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index 526a2839f4..6b5e055b4b 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -1,5 +1,5 @@ discard """ - matrix: "; --backend:cpp; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off" + matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off" """ import std/hashes diff --git a/tests/stdlib/theapqueue.nim b/tests/stdlib/theapqueue.nim index bb40b6f932..afb09c7e3f 100644 --- a/tests/stdlib/theapqueue.nim +++ b/tests/stdlib/theapqueue.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/heapqueue import std/assertions diff --git a/tests/stdlib/thighlite.nim b/tests/stdlib/thighlite.nim index d88bc7fecb..0cd3342543 100644 --- a/tests/stdlib/thighlite.nim +++ b/tests/stdlib/thighlite.nim @@ -1,3 +1,6 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" import unittest, strutils import ../../lib/packages/docutils/highlite diff --git a/tests/stdlib/thtmlparser.nim b/tests/stdlib/thtmlparser.nim index a27d41fe61..853a1c0ccd 100644 --- a/tests/stdlib/thtmlparser.nim +++ b/tests/stdlib/thtmlparser.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" output: ''' true diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim index 3b6b1efa0e..93e7d85c6d 100644 --- a/tests/stdlib/thttpcore.nim +++ b/tests/stdlib/thttpcore.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import httpcore, strutils import std/assertions diff --git a/tests/stdlib/timportutils.nim b/tests/stdlib/timportutils.nim index 33afd7def7..6720922829 100644 --- a/tests/stdlib/timportutils.nim +++ b/tests/stdlib/timportutils.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/[importutils, assertions] import stdtest/testutils import mimportutils diff --git a/tests/stdlib/tio.nim b/tests/stdlib/tio.nim index ca411379cd..80a1197631 100644 --- a/tests/stdlib/tio.nim +++ b/tests/stdlib/tio.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + # xxx move to here other tests that belong here; io is a proper module import std/os diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index f08c3946ba..5a1b4b2944 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -1,5 +1,6 @@ discard """ output: "" + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index e81470091b..d6f9023018 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim index 701fb79748..5993278c79 100644 --- a/tests/stdlib/tlists.nim +++ b/tests/stdlib/tlists.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tlocks.nim b/tests/stdlib/tlocks.nim index 9ce9afd130..1c5f671193 100644 --- a/tests/stdlib/tlocks.nim +++ b/tests/stdlib/tlocks.nim @@ -1,6 +1,6 @@ discard """ targets: "c cpp js" - matrix: "--threads:on" + matrix: "--mm:refc; --mm:orc" """ #bug #6049 diff --git a/tests/stdlib/tmacros.nim b/tests/stdlib/tmacros.nim index 9e3ebee83e..7ccb7e7c7d 100644 --- a/tests/stdlib/tmacros.nim +++ b/tests/stdlib/tmacros.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + #[ xxx macros tests need to be reorganized to makes sure each API is tested once See also: diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 66c1f8ca09..8ddb09bf58 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -1,6 +1,6 @@ discard """ targets: "c cpp js" - matrix:"; -d:danger" + matrix:"; -d:danger; --mm:refc" """ # xxx: there should be a test with `-d:nimTmathCase2 -d:danger --passc:-ffast-math`, diff --git a/tests/stdlib/tmd5.nim b/tests/stdlib/tmd5.nim index 254eefea92..37c2f17d7e 100644 --- a/tests/stdlib/tmd5.nim +++ b/tests/stdlib/tmd5.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ diff --git a/tests/stdlib/tmget.nim b/tests/stdlib/tmget.nim index 52e61fd240..bf5e535608 100644 --- a/tests/stdlib/tmget.nim +++ b/tests/stdlib/tmget.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" output: '''Can't access 6 10 11 diff --git a/tests/stdlib/tmimetypes.nim b/tests/stdlib/tmimetypes.nim index 8263e37fdc..e332cea403 100644 --- a/tests/stdlib/tmimetypes.nim +++ b/tests/stdlib/tmimetypes.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tmisc_issues.nim b/tests/stdlib/tmisc_issues.nim index b5a02e614b..33eb9655df 100644 --- a/tests/stdlib/tmisc_issues.nim +++ b/tests/stdlib/tmisc_issues.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim index 171604e33a..cc515a175d 100644 --- a/tests/stdlib/tmitems.nim +++ b/tests/stdlib/tmitems.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" output: '''@[11, 12, 13] @[11, 12, 13] @[1, 3, 5] diff --git a/tests/stdlib/tmonotimes.nim b/tests/stdlib/tmonotimes.nim index f10fef591c..1366dbfe9d 100644 --- a/tests/stdlib/tmonotimes.nim +++ b/tests/stdlib/tmonotimes.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tnativesockets.nim b/tests/stdlib/tnativesockets.nim index b1bbf32c2c..8242beb836 100644 --- a/tests/stdlib/tnativesockets.nim +++ b/tests/stdlib/tnativesockets.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/nativesockets import stdtest/testutils import std/assertions diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim index 06ff44c3db..27a6ac49c9 100644 --- a/tests/stdlib/tnet.nim +++ b/tests/stdlib/tnet.nim @@ -1,4 +1,5 @@ discard """ +matrix: "--mm:refc; --mm:orc" outputsub: "" """ diff --git a/tests/stdlib/tnet_ll.nim b/tests/stdlib/tnet_ll.nim index 13b56dbb93..199946482c 100644 --- a/tests/stdlib/tnet_ll.nim +++ b/tests/stdlib/tnet_ll.nim @@ -1,5 +1,6 @@ discard """ action: run + matrix: "--mm:refc; --mm:orc" output: ''' [Suite] inet_ntop tests diff --git a/tests/stdlib/tnetbind.nim b/tests/stdlib/tnetbind.nim index 734b6c5e7a..84f9ac4642 100644 --- a/tests/stdlib/tnetbind.nim +++ b/tests/stdlib/tnetbind.nim @@ -1,4 +1,5 @@ discard """ +matrix: "--mm:refc; --mm:orc" joinable: false """ diff --git a/tests/stdlib/tnre.nim b/tests/stdlib/tnre.nim index f13c16052f..3b40e9e83b 100644 --- a/tests/stdlib/tnre.nim +++ b/tests/stdlib/tnre.nim @@ -1,4 +1,5 @@ discard """ +matrix: "--mm:refc; --mm:orc" # Since the tests for nre are all bundled together we treat failure in one test as an nre failure # When running 'testament/tester' a failed check() in the test suite will cause the exit # codes to differ and be reported as a failure diff --git a/tests/stdlib/tntpath.nim b/tests/stdlib/tntpath.nim index dce0cf6f81..8efdd6bd00 100644 --- a/tests/stdlib/tntpath.nim +++ b/tests/stdlib/tntpath.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/private/ntpath import std/assertions diff --git a/tests/stdlib/topenssl.nim b/tests/stdlib/topenssl.nim index 3209437de2..af259627f1 100644 --- a/tests/stdlib/topenssl.nim +++ b/tests/stdlib/topenssl.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/wordwrap import openssl import std/assertions diff --git a/tests/stdlib/toptions.nim b/tests/stdlib/toptions.nim index 6065425b98..4f1251abb5 100644 --- a/tests/stdlib/toptions.nim +++ b/tests/stdlib/toptions.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index b2891ef1b5..c2822d2707 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -22,6 +22,7 @@ __really_obscure_dir_name/test Raises Raises ''' + matrix: "--mm:refc; --mm:orc" joinable: false """ # test os path creation, iteration, and deletion diff --git a/tests/stdlib/tos_unc.nim b/tests/stdlib/tos_unc.nim index fc74a4b9d3..194deeb420 100644 --- a/tests/stdlib/tos_unc.nim +++ b/tests/stdlib/tos_unc.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" disabled: "posix" """ diff --git a/tests/stdlib/tosenv.nim b/tests/stdlib/tosenv.nim index 20264102fc..17e3979874 100644 --- a/tests/stdlib/tosenv.nim +++ b/tests/stdlib/tosenv.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--threads" + matrix: "--mm:refc; --mm:arc" joinable: false targets: "c js cpp" """ diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index e86f3853b3..1184503f59 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -1,4 +1,5 @@ discard """ +matrix: "--mm:refc; --mm:orc" joinable: false """ diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim index 08b379569f..93b0317f7d 100644 --- a/tests/stdlib/tosprocterminate.nim +++ b/tests/stdlib/tosprocterminate.nim @@ -1,7 +1,7 @@ discard """ cmd: "nim $target $options -r $file" targets: "c cpp" - matrix: "--threads:on; " + matrix: "--mm:refc; --mm:orc" """ import os, osproc, times, std / monotimes diff --git a/tests/stdlib/tpackedsets.nim b/tests/stdlib/tpackedsets.nim index 2c69f6b1be..f519c08a71 100644 --- a/tests/stdlib/tpackedsets.nim +++ b/tests/stdlib/tpackedsets.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/packedsets import std/sets diff --git a/tests/stdlib/tparsecfg.nim b/tests/stdlib/tparsecfg.nim index 16f12bc9e5..2600d6f663 100644 --- a/tests/stdlib/tparsecfg.nim +++ b/tests/stdlib/tparsecfg.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tparsecsv.nim b/tests/stdlib/tparsecsv.nim index a879019f68..5a1e41bce9 100644 --- a/tests/stdlib/tparsecsv.nim +++ b/tests/stdlib/tparsecsv.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + include parsecsv import strutils, os import std/assertions diff --git a/tests/stdlib/tparseipv6.nim b/tests/stdlib/tparseipv6.nim index 9b9c464c7e..31ec4ecfbf 100644 --- a/tests/stdlib/tparseipv6.nim +++ b/tests/stdlib/tparseipv6.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" output: "all ok" """ diff --git a/tests/stdlib/tparsesql.nim b/tests/stdlib/tparsesql.nim index cfd8ad1482..cd582551df 100644 --- a/tests/stdlib/tparsesql.nim +++ b/tests/stdlib/tparsesql.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ import parsesql diff --git a/tests/stdlib/tparseuints.nim b/tests/stdlib/tparseuints.nim index ef8c782b39..9c71a27d65 100644 --- a/tests/stdlib/tparseuints.nim +++ b/tests/stdlib/tparseuints.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import unittest, strutils block: # parseutils diff --git a/tests/stdlib/tparseutils.nim b/tests/stdlib/tparseutils.nim index 218dd08f6d..0209644469 100644 --- a/tests/stdlib/tparseutils.nim +++ b/tests/stdlib/tparseutils.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp" """ diff --git a/tests/stdlib/tpathnorm.nim b/tests/stdlib/tpathnorm.nim index 1cd9130848..3dd287a776 100644 --- a/tests/stdlib/tpathnorm.nim +++ b/tests/stdlib/tpathnorm.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" """ import std/os diff --git a/tests/stdlib/tpaths.nim b/tests/stdlib/tpaths.nim index 2d1a3e2ca4..082c4937a9 100644 --- a/tests/stdlib/tpaths.nim +++ b/tests/stdlib/tpaths.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/paths import std/assertions import pathnorm diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim index a6079d47c9..da3fc14b7b 100644 --- a/tests/stdlib/tpegs.nim +++ b/tests/stdlib/tpegs.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" output: ''' PEG AST traversal output diff --git a/tests/stdlib/tposix.nim b/tests/stdlib/tposix.nim index d06c5cd56a..c5e820836a 100644 --- a/tests/stdlib/tposix.nim +++ b/tests/stdlib/tposix.nim @@ -1,5 +1,6 @@ discard """ -outputsub: "" + matrix: "--mm:refc; --mm:orc" + disabled: windows """ # Test Posix interface diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim index c35fc47da8..4104ad1a44 100644 --- a/tests/stdlib/trandom.nim +++ b/tests/stdlib/trandom.nim @@ -1,6 +1,6 @@ discard """ joinable: false # to avoid messing with global rand state - matrix: "; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" + matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" """ import std/[assertions, formatfloat] import std/[random, math, stats, sets, tables] diff --git a/tests/stdlib/trationals.nim b/tests/stdlib/trationals.nim index cf2e92003f..cd9954f61d 100644 --- a/tests/stdlib/trationals.nim +++ b/tests/stdlib/trationals.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/[rationals, math] import std/assertions diff --git a/tests/stdlib/tre.nim b/tests/stdlib/tre.nim index 3986934c49..39637434dd 100644 --- a/tests/stdlib/tre.nim +++ b/tests/stdlib/tre.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/re import std/assertions diff --git a/tests/stdlib/tregex.nim b/tests/stdlib/tregex.nim index cf80f81224..9dd66cd603 100644 --- a/tests/stdlib/tregex.nim +++ b/tests/stdlib/tregex.nim @@ -1,5 +1,6 @@ discard """ output: "key: keyAYes!" + matrix: "--mm:refc; --mm:orc" """ # Test the new regular expression module # which is based on the PCRE library diff --git a/tests/stdlib/tregistry.nim b/tests/stdlib/tregistry.nim index 4956f81962..25aed8df8c 100644 --- a/tests/stdlib/tregistry.nim +++ b/tests/stdlib/tregistry.nim @@ -1,6 +1,6 @@ discard """ disabled: "unix" - matrix: "--gc:refc; --gc:arc" + matrix: "--mm:refc; --mm:orc" """ when defined(windows): diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index 0511d1004c..a8c62ea55b 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -1,6 +1,6 @@ discard """ targets: "c cpp js" - matrix: ";--gc:arc" + matrix: "--mm:refc;--mm:arc" """ # if excessive, could remove 'cpp' from targets diff --git a/tests/stdlib/tropes.nim b/tests/stdlib/tropes.nim index 6d41e9e44a..eb0edc3641 100644 --- a/tests/stdlib/tropes.nim +++ b/tests/stdlib/tropes.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index c9024ded8d..5da5fc360a 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -17,6 +17,7 @@ discard """ [Suite] RST inline markup ''' +matrix: "--mm:refc; --mm:orc" """ # tests for rst module diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index dae4ea1cf8..8c68f68c98 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1,4 +1,5 @@ discard """ +matrix: "--mm:refc; --mm:orc" outputsub: "" """ diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim index 2b9ef5d6ea..1094ae2335 100644 --- a/tests/stdlib/tsequtils.nim +++ b/tests/stdlib/tsequtils.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tsetutils.nim b/tests/stdlib/tsetutils.nim index 037c696c1c..c8498f23e0 100644 --- a/tests/stdlib/tsetutils.nim +++ b/tests/stdlib/tsetutils.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tsha1.nim b/tests/stdlib/tsha1.nim index c984d97bda..50bf392c59 100644 --- a/tests/stdlib/tsha1.nim +++ b/tests/stdlib/tsha1.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/sha1 import std/assertions diff --git a/tests/stdlib/tsharedlist.nim b/tests/stdlib/tsharedlist.nim index 0bb3ad827f..b91302d19f 100644 --- a/tests/stdlib/tsharedlist.nim +++ b/tests/stdlib/tsharedlist.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--threads:on" + matrix: "--mm:orc; --mm:refc" """ import std/sharedlist diff --git a/tests/stdlib/tsharedtable.nim b/tests/stdlib/tsharedtable.nim index 0022f7bb25..10ad5f658c 100644 --- a/tests/stdlib/tsharedtable.nim +++ b/tests/stdlib/tsharedtable.nim @@ -1,5 +1,5 @@ discard """ -cmd: "nim $target --threads:on $options $file" +matrix: "--mm:refc; --mm:orc" output: ''' ''' """ diff --git a/tests/stdlib/tsocketstreams.nim b/tests/stdlib/tsocketstreams.nim index 0cf952810c..a37e7c34cc 100644 --- a/tests/stdlib/tsocketstreams.nim +++ b/tests/stdlib/tsocketstreams.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" output: ''' OM NIM diff --git a/tests/stdlib/tsortcall.nim b/tests/stdlib/tsortcall.nim index 242e3fe4c5..32e0049214 100644 --- a/tests/stdlib/tsortcall.nim +++ b/tests/stdlib/tsortcall.nim @@ -1,5 +1,5 @@ discard """ -outputsub: "" + matrix: "--mm:refc; --mm:orc" """ import algorithm diff --git a/tests/stdlib/tsqlparser.nim b/tests/stdlib/tsqlparser.nim index 11ee22e2bd..6f123f21df 100644 --- a/tests/stdlib/tsqlparser.nim +++ b/tests/stdlib/tsqlparser.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" output: '''true''' """ diff --git a/tests/stdlib/tssl.nim b/tests/stdlib/tssl.nim index 6f6858be44..0e3f9cd82c 100644 --- a/tests/stdlib/tssl.nim +++ b/tests/stdlib/tssl.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" joinable: false disabled: "freebsd" disabled: "openbsd" diff --git a/tests/stdlib/tstats.nim b/tests/stdlib/tstats.nim index 3ed0130052..728d93d09b 100644 --- a/tests/stdlib/tstats.nim +++ b/tests/stdlib/tstats.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/[stats, assertions] import std/math diff --git a/tests/stdlib/tstdlib_issues.nim b/tests/stdlib/tstdlib_issues.nim index 9db3196038..b7b806db89 100644 --- a/tests/stdlib/tstdlib_issues.nim +++ b/tests/stdlib/tstdlib_issues.nim @@ -1,4 +1,5 @@ discard """ +matrix: "--mm:refc; --mm:orc" output: ''' 02 1 diff --git a/tests/stdlib/tstrbasics.nim b/tests/stdlib/tstrbasics.nim index 9a624fec3c..a965ff15fb 100644 --- a/tests/stdlib/tstrbasics.nim +++ b/tests/stdlib/tstrbasics.nim @@ -1,6 +1,6 @@ discard """ targets: "c cpp js" - matrix: "--gc:refc; --gc:arc" + matrix: "--mm:refc; --mm:orc" """ import std/[strbasics, sugar, assertions] diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index 891b38e202..0668d12bd6 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--gc:refc; --gc:arc" + matrix: "--mm:refc; --mm:orc" input: "Arne" output: ''' Hello! What is your name? diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index d332e83750..0b163125bd 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -1,4 +1,6 @@ -# xxx: test js target +discard """ + matrix: "--mm:refc; --mm:orc" +""" import genericstrformat import std/[strformat, strutils, times, tables, json] diff --git a/tests/stdlib/tstrimpl.nim b/tests/stdlib/tstrimpl.nim index d12150f8e7..a8933e53f7 100644 --- a/tests/stdlib/tstrimpl.nim +++ b/tests/stdlib/tstrimpl.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/private/strimpl import std/assertions diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim index 2e8fe09e1a..b9b3c78a38 100644 --- a/tests/stdlib/tstring.nim +++ b/tests/stdlib/tstring.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ diff --git a/tests/stdlib/tstrmiscs.nim b/tests/stdlib/tstrmiscs.nim index 76b14d27aa..b42f2e1fe7 100644 --- a/tests/stdlib/tstrmiscs.nim +++ b/tests/stdlib/tstrmiscs.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/strmisc import std/assertions diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim index e30c86279b..ae7fd98cac 100644 --- a/tests/stdlib/tstrscans.nim +++ b/tests/stdlib/tstrscans.nim @@ -1,5 +1,5 @@ discard """ - output: "" + matrix: "--mm:refc; --mm:orc" """ import std/[strscans, strutils, assertions] diff --git a/tests/stdlib/tstrset.nim b/tests/stdlib/tstrset.nim index f0cf5cbe4f..bbb6c2677f 100644 --- a/tests/stdlib/tstrset.nim +++ b/tests/stdlib/tstrset.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + # test a simple yet highly efficient set of strings type diff --git a/tests/stdlib/tstrtabs.nim b/tests/stdlib/tstrtabs.nim index 036287bfda..d261abe763 100644 --- a/tests/stdlib/tstrtabs.nim +++ b/tests/stdlib/tstrtabs.nim @@ -1,4 +1,5 @@ discard """ +matrix: "--mm:refc; --mm:orc" sortoutput: true output: ''' key1: value1 diff --git a/tests/stdlib/tstrtabs2.nim b/tests/stdlib/tstrtabs2.nim index f055b5d33a..aeef28d655 100644 --- a/tests/stdlib/tstrtabs2.nim +++ b/tests/stdlib/tstrtabs2.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 12b0c13b11..67eb5cf3a5 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -1,5 +1,5 @@ discard """ - matrix: "; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" + matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" """ import std/strutils diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim index 1b629165a4..5e0c51b2dc 100644 --- a/tests/stdlib/tsugar.nim +++ b/tests/stdlib/tsugar.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" output: ''' x + y = 30 ''' diff --git a/tests/stdlib/tsums.nim b/tests/stdlib/tsums.nim index 071e0b303c..cf410cddf2 100644 --- a/tests/stdlib/tsums.nim +++ b/tests/stdlib/tsums.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/sums from math import pow import std/assertions diff --git a/tests/stdlib/tsysrand.nim b/tests/stdlib/tsysrand.nim index e6b65e70f1..7b7a0fc347 100644 --- a/tests/stdlib/tsysrand.nim +++ b/tests/stdlib/tsysrand.nim @@ -1,6 +1,6 @@ discard """ targets: "c cpp js" - matrix: "--experimental:vmopsDanger" + matrix: "--experimental:vmopsDanger; --experimental:vmopsDanger --mm:refc" """ import std/sysrand diff --git a/tests/stdlib/tsystem.nim b/tests/stdlib/tsystem.nim index 810c3af046..c1cadb49de 100644 --- a/tests/stdlib/tsystem.nim +++ b/tests/stdlib/tsystem.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ diff --git a/tests/stdlib/ttables.nim b/tests/stdlib/ttables.nim index ab65024111..c529aff9fb 100644 --- a/tests/stdlib/ttables.nim +++ b/tests/stdlib/ttables.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import tables, hashes import std/assertions diff --git a/tests/stdlib/ttempfiles.nim b/tests/stdlib/ttempfiles.nim index 1159e08efc..352788c421 100644 --- a/tests/stdlib/ttempfiles.nim +++ b/tests/stdlib/ttempfiles.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" joinable: false # not strictly necessary """ diff --git a/tests/stdlib/tthreadpool.nim b/tests/stdlib/tthreadpool.nim index bc574faebd..1947074be1 100644 --- a/tests/stdlib/tthreadpool.nim +++ b/tests/stdlib/tthreadpool.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--threads:on --gc:arc" + matrix: "--mm:arc; --mm:refc" disabled: "freebsd" output: "42" """ diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index 47d2efcf15..91db310339 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -1,5 +1,5 @@ discard """ - matrix: "; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off" + matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off" """ import times, strutils, unittest diff --git a/tests/stdlib/ttypeinfo.nim b/tests/stdlib/ttypeinfo.nim index 5e17c151a2..8d5061124c 100644 --- a/tests/stdlib/ttypeinfo.nim +++ b/tests/stdlib/ttypeinfo.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/typeinfo import std/assertions diff --git a/tests/stdlib/ttypetraits.nim b/tests/stdlib/ttypetraits.nim index 574204da65..6851b9220b 100644 --- a/tests/stdlib/ttypetraits.nim +++ b/tests/stdlib/ttypetraits.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ diff --git a/tests/stdlib/tunicode.nim b/tests/stdlib/tunicode.nim index 2b1cb2385e..adc8d2078d 100644 --- a/tests/stdlib/tunicode.nim +++ b/tests/stdlib/tunicode.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/unicode import std/assertions diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim index 606c9bc702..0442c7863b 100644 --- a/tests/stdlib/tunittest.nim +++ b/tests/stdlib/tunittest.nim @@ -19,6 +19,7 @@ discard """ [Suite] test name filtering ''' +matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tunittestpass.nim b/tests/stdlib/tunittestpass.nim index cff37a3b77..d8de277b71 100644 --- a/tests/stdlib/tunittestpass.nim +++ b/tests/stdlib/tunittestpass.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/turi.nim b/tests/stdlib/turi.nim index 77ba02dd18..9c717c5b15 100644 --- a/tests/stdlib/turi.nim +++ b/tests/stdlib/turi.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c js" """ diff --git a/tests/stdlib/tuserlocks.nim b/tests/stdlib/tuserlocks.nim index ba8ea050ea..9270771204 100644 --- a/tests/stdlib/tuserlocks.nim +++ b/tests/stdlib/tuserlocks.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--threads:on" + matrix: "--mm:refc; --mm:orc" """ import std/rlocks diff --git a/tests/stdlib/tvarargs.nim b/tests/stdlib/tvarargs.nim index 3207572b5a..2edc26264a 100644 --- a/tests/stdlib/tvarargs.nim +++ b/tests/stdlib/tvarargs.nim @@ -1,6 +1,6 @@ discard """ targets: "c js" - matrix: "--gc:refc; --gc:arc" + matrix: "--mm:refc; --mm:orc" """ import std/assertions diff --git a/tests/stdlib/tvarints.nim b/tests/stdlib/tvarints.nim index bb0d3d37fa..35f1cd8498 100644 --- a/tests/stdlib/tvarints.nim +++ b/tests/stdlib/tvarints.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/varints import std/assertions diff --git a/tests/stdlib/tvmutils.nim b/tests/stdlib/tvmutils.nim index f43557ad80..63804c1366 100644 --- a/tests/stdlib/tvmutils.nim +++ b/tests/stdlib/tvmutils.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" joinable: false nimout: ''' 0 @@ -19,7 +20,6 @@ tvmutils.nim(29, 14) [opcIndCall] vmTrace(false) """ # line 20 (only showing a subset of nimout to avoid making the test rigid) import std/vmutils - proc main() = for i in 0..<7: echo i diff --git a/tests/stdlib/twchartoutf8.nim b/tests/stdlib/twchartoutf8.nim index 0b6cf696ea..e437177ac3 100644 --- a/tests/stdlib/twchartoutf8.nim +++ b/tests/stdlib/twchartoutf8.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" output: '''OK''' """ diff --git a/tests/stdlib/twith.nim b/tests/stdlib/twith.nim index b2d72bd0ca..ea3f3d99fd 100644 --- a/tests/stdlib/twith.nim +++ b/tests/stdlib/twith.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/with import std/[assertions, formatfloat] diff --git a/tests/stdlib/twordwrap.nim b/tests/stdlib/twordwrap.nim index a08e64cf96..5d49477d3a 100644 --- a/tests/stdlib/twordwrap.nim +++ b/tests/stdlib/twordwrap.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/wordwrap import std/assertions diff --git a/tests/stdlib/twrapnils.nim b/tests/stdlib/twrapnils.nim index 5d5c1ab2d0..3da230b5e4 100644 --- a/tests/stdlib/twrapnils.nim +++ b/tests/stdlib/twrapnils.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/wrapnils from std/options import get, isSome import std/assertions diff --git a/tests/stdlib/txmltree.nim b/tests/stdlib/txmltree.nim index c878715445..add12a3fc0 100644 --- a/tests/stdlib/txmltree.nim +++ b/tests/stdlib/txmltree.nim @@ -1,3 +1,7 @@ +discard """ + matrix: "--mm:refc; --mm:orc" +""" + import std/[xmltree, assertions, xmlparser] diff --git a/tests/stdlib/tyield.nim b/tests/stdlib/tyield.nim index 0cf52999c0..f385ddd050 100644 --- a/tests/stdlib/tyield.nim +++ b/tests/stdlib/tyield.nim @@ -1,4 +1,5 @@ discard """ + matrix: "--mm:refc; --mm:orc" targets: "c cpp js" """ diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim index 7eb26cd6bc..913db7c863 100644 --- a/tests/system/tdollars.nim +++ b/tests/system/tdollars.nim @@ -1,5 +1,5 @@ discard """ - matrix: "; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" + matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" """ #[ diff --git a/tests/system/tslimsystem.nim b/tests/system/tslimsystem.nim index 690f4ee9ba..4815306b54 100644 --- a/tests/system/tslimsystem.nim +++ b/tests/system/tslimsystem.nim @@ -1,6 +1,6 @@ discard """ output: "123" - matrix: "-d:nimPreviewSlimSystem" + matrix: "-d:nimPreviewSlimSystem --mm:refc; -d:nimPreviewSlimSystem --mm:arc" """ echo 123 \ No newline at end of file diff --git a/tests/vm/t9622.nim b/tests/vm/t9622.nim index 214ab0f193..fada8fe59d 100644 --- a/tests/vm/t9622.nim +++ b/tests/vm/t9622.nim @@ -1,6 +1,6 @@ discard """ targets: "c cpp" - matrix: "--gc:refc; --gc:arc" + matrix: "--mm:refc; --mm:arc" """ type From c136ebf1ed0812f019895acc5aeeda8fde75ed00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Fri, 21 Apr 2023 14:40:13 +0100 Subject: [PATCH 013/489] implements #21620: allowing to import multiple modules with shared names (#21628) --- compiler/importer.nim | 6 ++++++ compiler/lookups.nim | 21 +++++++++++++-------- compiler/semdata.nim | 1 + tests/import/t21496.nim | 2 +- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/compiler/importer.nim b/compiler/importer.nim index 84f4bb5457..0324b2fbce 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -228,6 +228,11 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im for i in 0..n.safeLen-1: importForwarded(c, n[i], exceptSet, fromMod, importSet) +proc addUnique[T](x: var seq[T], y: sink T) {.noSideEffect.} = + for i in 0..high(x): + if x[i] == y: return + x.add y + proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym = result = realModule template createModuleAliasImpl(ident): untyped = @@ -245,6 +250,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool) result.options.incl optImportHidden c.unusedImports.add((result, n.info)) c.importModuleMap[result.id] = realModule.id + c.importModuleLookup.mgetOrPut(realModule.name.id, @[]).addUnique realModule.id proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] = var ret: typeof(result) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 8b98ea3f1c..3b4599f2c2 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -8,7 +8,7 @@ # # This module implements lookup helpers. -import std/[algorithm, strutils] +import std/[algorithm, strutils, tables] when defined(nimPreviewSlimSystem): import std/assertions @@ -343,14 +343,15 @@ proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) = if sym.name.s == "_": return let conflict = scope.addUniqueSym(sym) if conflict != nil: - if sym.kind == skModule and conflict.kind == skModule and - sym.position == conflict.position: + if sym.kind == skModule and conflict.kind == skModule: # e.g.: import foo; import foo # xxx we could refine this by issuing a different hint for the case - # where a duplicate import happens inside an include. - localError(c.config, info, hintDuplicateModuleImport, - "duplicate import of '$1'; previous import here: $2" % - [sym.name.s, c.config $ conflict.info]) + # where a duplicate import happens inside an include. + if c.importModuleMap[sym.id] == c.importModuleMap[conflict.id]: + #only hints if the conflict is the actual module not just a shared name + localError(c.config, info, hintDuplicateModuleImport, + "duplicate import of '$1'; previous import here: $2" % + [sym.name.s, c.config $ conflict.info]) else: wrongRedefinition(c, info, sym.name.s, conflict.info, errGenerated) @@ -631,7 +632,11 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = if m == c.module: result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config) else: - result = someSym(c.graph, m, ident).skipAlias(n, c.config) + if c.importModuleLookup.getOrDefault(m.name.id).len > 1: + var amb: bool + result = errorUseQualifier(c, n.info, m, amb) + else: + result = someSym(c.graph, m, ident).skipAlias(n, c.config) if result == nil and checkUndeclared in flags: result = errorUndeclaredIdentifierHint(c, n[1], ident) elif n[1].kind == nkSym: diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 5b94cc770d..90d496c8ce 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -166,6 +166,7 @@ type lastTLineInfo*: TLineInfo sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index inUncheckedAssignSection*: int + importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id]) template config*(c: PContext): ConfigRef = c.graph.config diff --git a/tests/import/t21496.nim b/tests/import/t21496.nim index 568f2ac515..b49d830b0e 100644 --- a/tests/import/t21496.nim +++ b/tests/import/t21496.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "redefinition of 'm21496'; previous declaration here: t21496.nim(5, 12)" + errormsg: "ambiguous identifier: 'm21496'" """ import fizz/m21496, buzz/m21496 From 63d29ddd6980ee9f89673c454c15da52e2984283 Mon Sep 17 00:00:00 2001 From: metagn Date: Sat, 22 Apr 2023 10:11:56 +0300 Subject: [PATCH 014/489] alias syntax fixes, improvements and tests (#21671) * alias syntax fixes, improvements and tests * even better, cannot use alias syntax with generics * more type tests, improve comment * fix again * consistent error message + make t5167_5 work * more comments, remove {.noalias.} --- compiler/ast.nim | 11 +-- compiler/semexprs.nim | 20 ++-- compiler/semgnrc.nim | 47 +++------- compiler/semstmts.nim | 15 ++- compiler/semtempl.nim | 8 ++ compiler/semtypes.nim | 129 +++++++++++++------------- doc/manual_experimental.md | 17 ++-- tests/errmsgs/t5167_5.nim | 20 ++-- tests/template/t13515.nim | 16 ---- tests/template/taliassyntax.nim | 63 +++++++++++++ tests/template/taliassyntaxerrors.nim | 28 ++++++ 11 files changed, 226 insertions(+), 148 deletions(-) delete mode 100644 tests/template/t13515.nim create mode 100644 tests/template/taliassyntax.nim create mode 100644 tests/template/taliassyntaxerrors.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index b5306c423c..8aa4ca6b1e 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -303,6 +303,8 @@ type sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally' sfSingleUsedTemp # For temporaries that we know will only be used once sfNoalias # 'noalias' annotation, means C's 'restrict' + # for templates and macros, means cannot be called + # as a lone symbol (cannot use alias syntax) sfEffectsDelayed # an 'effectsDelayed' parameter sfGeneratedType # A anonymous generic type that is generated by the compiler for # objects that do not have generic parameters in case one of the @@ -1920,15 +1922,6 @@ proc isRunnableExamples*(n: PNode): bool = result = n.kind == nkSym and n.sym.magic == mRunnableExamples or n.kind == nkIdent and n.ident.s == "runnableExamples" -proc requiredParams*(s: PSym): int = - # Returns the number of required params (without default values) - # XXX: Perhaps we can store this in the `offset` field of the - # symbol instead? - for i in 1.. 0 or - (n.kind notin nkCallKinds and s.requiredParams > 0) or - sfCustomPragma in sym.flags: + # check if we cannot use alias syntax (no required args or generic params) + if sfNoalias in s.flags: let info = getCallLineInfo(n) markUsed(c, info, s) onUse(info, s) @@ -1588,9 +1595,8 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result.add(x[0]) return checkMinSonsLen(n, 2, c.config) - # make sure we don't evaluate generic macros/templates - n[0] = semExprWithType(c, n[0], - {efNoEvaluateGeneric}) + # signal that generic parameters may be applied after + n[0] = semExprWithType(c, n[0], {efNoEvaluateGeneric}) var arr = skipTypes(n[0].typ, {tyGenericInst, tyUserTypeClassInst, tyOwned, tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink}) if arr.kind == tyStatic: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index fa37af850a..695f8a01d9 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -50,13 +50,6 @@ proc semGenericStmtScope(c: PContext, n: PNode, result = semGenericStmt(c, n, flags, ctx) closeScope(c) -template macroToExpand(s): untyped = - s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfAllUntyped in s.flags) - -template macroToExpandSym(s): untyped = - sfCustomPragma notin s.flags and s.kind in {skMacro, skTemplate} and - (s.typ.len == 1) and not fromDotExpr - template isMixedIn(sym): bool = let s = sym s.name.id in ctx.toMixin or (withinConcept in flags and @@ -74,19 +67,14 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result = n of skProc, skFunc, skMethod, skIterator, skConverter, skModule: result = symChoice(c, n, s, scOpen) - of skTemplate: - if macroToExpandSym(s): + of skTemplate, skMacro: + # alias syntax, see semSym for skTemplate, skMacro + if sfNoalias notin s.flags and not fromDotExpr: onUse(n.info, s) - result = semTemplateExpr(c, n, s, {efNoSemCheck}) - c.friendModules.add(s.owner.getModule) - result = semGenericStmt(c, result, {}, ctx) - discard c.friendModules.pop() - else: - result = symChoice(c, n, s, scOpen) - of skMacro: - if macroToExpandSym(s): - onUse(n.info, s) - result = semMacroExpr(c, n, n, s, {efNoSemCheck}) + case s.kind + of skTemplate: result = semTemplateExpr(c, n, s, {efNoSemCheck}) + of skMacro: result = semMacroExpr(c, n, n, s, {efNoSemCheck}) + else: discard # unreachable c.friendModules.add(s.owner.getModule) result = semGenericStmt(c, result, {}, ctx) discard c.friendModules.pop() @@ -245,21 +233,14 @@ proc semGenericStmt(c: PContext, n: PNode, else: scOpen let sc = symChoice(c, fn, s, whichChoice) case s.kind - of skMacro: - if macroToExpand(s) and sc.safeLen <= 1: + of skMacro, skTemplate: + # unambiguous macros/templates are expanded if all params are untyped + if sfAllUntyped in s.flags and sc.safeLen <= 1: onUse(fn.info, s) - result = semMacroExpr(c, n, n, s, {efNoSemCheck}) - c.friendModules.add(s.owner.getModule) - result = semGenericStmt(c, result, flags, ctx) - discard c.friendModules.pop() - else: - n[0] = sc - result = n - mixinContext = true - of skTemplate: - if macroToExpand(s) and sc.safeLen <= 1: - onUse(fn.info, s) - result = semTemplateExpr(c, n, s, {efNoSemCheck}) + case s.kind + of skMacro: result = semMacroExpr(c, n, n, s, {efNoSemCheck}) + of skTemplate: result = semTemplateExpr(c, n, s, {efNoSemCheck}) + else: discard # unreachable c.friendModules.add(s.owner.getModule) result = semGenericStmt(c, result, flags, ctx) discard c.friendModules.pop() diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 3701e09f54..20fb12d715 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -682,7 +682,14 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = localError(c.config, def.info, errCannotInferTypeOfTheLiteral % typ.kind.toHumanStr) elif typ.kind == tyProc and def.kind == nkSym and isGenericRoutine(def.sym.ast): # tfUnresolved in typ.flags: - localError(c.config, def.info, errProcHasNoConcreteType % def.renderTree) + let owner = typ.owner + let err = + # consistent error message with evaltempl/semMacroExpr + if owner != nil and owner.kind in {skTemplate, skMacro}: + errMissingGenericParamsForTemplate % def.renderTree + else: + errProcHasNoConcreteType % def.renderTree + localError(c.config, def.info, err) when false: # XXX This typing rule is neither documented nor complete enough to # justify it. Instead use the newer 'unowned x' until we figured out @@ -2328,10 +2335,16 @@ proc semMacroDef(c: PContext, n: PNode): PNode = var s = result[namePos].sym var t = s.typ var allUntyped = true + var requiresParams = false for i in 1.. 0: - let bound = result.typ[0].sym - if bound != nil: return bound - return result - if result.typ.sym == nil: - localError(c.config, n.info, errTypeExpected) - return errorSym(c, n) - result = result.typ.sym.copySym(nextSymId c.idgen) - result.typ = exactReplica(result.typ) - result.typ.flags.incl tfUnresolved - - if result.kind == skGenericParam: - if result.typ.kind == tyGenericParam and result.typ.len == 0 and - tfWildcard in result.typ.flags: - # collapse the wild-card param to a type - result.transitionGenericParamToType() - result.typ.flags.excl tfWildcard - return - else: - localError(c.config, n.info, errTypeExpected) - return errorSym(c, n) - if result.kind != skType and result.magic notin {mStatic, mType, mTypeOf}: - # this implements the wanted ``var v: V, x: V`` feature ... - var ov: TOverloadIter - var amb = initOverloadIter(ov, c, n) - while amb != nil and amb.kind != skType: - amb = nextOverloadIter(ov, c, n) - if amb != nil: result = amb - else: - if result.kind != skError: localError(c.config, n.info, errTypeExpected) - return errorSym(c, n) - if result.typ.kind != tyGenericParam: - # XXX get rid of this hack! - var oldInfo = n.info - when defined(useNodeIds): - let oldId = n.id - reset(n[]) - when defined(useNodeIds): - n.id = oldId - n.transitionNoneToSym() - n.sym = result - n.info = oldInfo - n.typ = result.typ - else: - localError(c.config, n.info, "identifier expected") - result = errorSym(c, n) - proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType = if n.len == 0: localError(c.config, n.info, errTypeExpected) @@ -1801,6 +1739,73 @@ proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType = fixupTypeOf(c, prev, t) result = t.typ +proc semTypeIdent(c: PContext, n: PNode): PSym = + if n.kind == nkSym: + result = getGenSym(c, n.sym) + else: + result = pickSym(c, n, {skType, skGenericParam, skParam}) + if result.isNil: + result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) + if result != nil: + markUsed(c, n.info, result) + onUse(n.info, result) + + # alias syntax, see semSym for skTemplate, skMacro + if result.kind in {skTemplate, skMacro} and sfNoalias notin result.flags: + let t = semTypeExpr(c, n, nil) + result = symFromType(c, t, n.info) + + if result.kind == skParam and result.typ.kind == tyTypeDesc: + # This is a typedesc param. is it already bound? + # it's not bound when it's used multiple times in the + # proc signature for example + if c.inGenericInst > 0: + let bound = result.typ[0].sym + if bound != nil: return bound + return result + if result.typ.sym == nil: + localError(c.config, n.info, errTypeExpected) + return errorSym(c, n) + result = result.typ.sym.copySym(nextSymId c.idgen) + result.typ = exactReplica(result.typ) + result.typ.flags.incl tfUnresolved + + if result.kind == skGenericParam: + if result.typ.kind == tyGenericParam and result.typ.len == 0 and + tfWildcard in result.typ.flags: + # collapse the wild-card param to a type + result.transitionGenericParamToType() + result.typ.flags.excl tfWildcard + return + else: + localError(c.config, n.info, errTypeExpected) + return errorSym(c, n) + if result.kind != skType and result.magic notin {mStatic, mType, mTypeOf}: + # this implements the wanted ``var v: V, x: V`` feature ... + var ov: TOverloadIter + var amb = initOverloadIter(ov, c, n) + while amb != nil and amb.kind != skType: + amb = nextOverloadIter(ov, c, n) + if amb != nil: result = amb + else: + if result.kind != skError: localError(c.config, n.info, errTypeExpected) + return errorSym(c, n) + if result.typ.kind != tyGenericParam: + # XXX get rid of this hack! + var oldInfo = n.info + when defined(useNodeIds): + let oldId = n.id + reset(n[]) + when defined(useNodeIds): + n.id = oldId + n.transitionNoneToSym() + n.sym = result + n.info = oldInfo + n.typ = result.typ + else: + localError(c.config, n.info, "identifier expected") + result = errorSym(c, n) + proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = nil inc c.inTypeContext diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 2a56c13542..37453bc896 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -453,28 +453,25 @@ Assuming `foo` is a macro or a template, this is roughly equivalent to: ``` -Symbols as template/macro calls -=============================== +Symbols as template/macro calls (alias syntax) +============================================== -Templates and macros that take no arguments can be called as lone symbols, -i.e. without parentheses. This is useful for repeated uses of complex -expressions that cannot conveniently be represented as runtime values. +Templates and macros that have no generic parameters and no required arguments +can be called as lone symbols, i.e. without parentheses. This is useful for +repeated uses of complex expressions that cannot conveniently be represented +as runtime values. ```nim type Foo = object bar: int var foo = Foo(bar: 10) - template bar: untyped = foo.bar + template bar: int = foo.bar assert bar == 10 bar = 15 assert bar == 15 ``` -In the future, this may require more specific information on template or macro -signatures to be used. Specializations for some applications of this may also -be introduced to guarantee consistency and circumvent bugs. - Not nil annotation ================== diff --git a/tests/errmsgs/t5167_5.nim b/tests/errmsgs/t5167_5.nim index ab6f094f35..6c1269bce5 100644 --- a/tests/errmsgs/t5167_5.nim +++ b/tests/errmsgs/t5167_5.nim @@ -1,13 +1,9 @@ discard """ cmd: "nim check --mm:refc $file" -errormsg: "'t' has unspecified generic parameters" -nimout: ''' -t5167_5.nim(10, 16) Error: expression 'system' has no type (or is ambiguous) -t5167_5.nim(21, 9) Error: 't' has unspecified generic parameters -''' """ # issue #11942 -discard newSeq[system]() +discard newSeq[system]() #[tt.Error + ^ expression 'system' has no type (or is ambiguous)]# # issue #5167 template t[B]() = @@ -18,8 +14,12 @@ macro m[T]: untyped = nil proc bar(x: proc (x: int)) = echo "bar" -let x = t -bar t +let x = t #[tt.Error + ^ 't' has unspecified generic parameters]# +bar t #[tt.Error + ^ 't' has unspecified generic parameters]# -let y = m -bar m +let y = m #[tt.Error + ^ 'm' has unspecified generic parameters]# +bar m #[tt.Error + ^ 'm' has unspecified generic parameters]# diff --git a/tests/template/t13515.nim b/tests/template/t13515.nim deleted file mode 100644 index ffebedcbe8..0000000000 --- a/tests/template/t13515.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - action: compile -""" - -template test: bool = true - -# compiles: -if not test: - echo "wtf" - -# does not compile: -template x = - if not test: - echo "wtf" - -x diff --git a/tests/template/taliassyntax.nim b/tests/template/taliassyntax.nim new file mode 100644 index 0000000000..969a9d1443 --- /dev/null +++ b/tests/template/taliassyntax.nim @@ -0,0 +1,63 @@ +type Foo = object + bar: int + +var foo = Foo(bar: 10) +template bar: int = foo.bar +doAssert bar == 10 +bar = 15 +doAssert bar == 15 +var foo2 = Foo(bar: -10) +doAssert bar == 15 +# works in generics +proc genericProc[T](x: T): string = + $(x, bar) +doAssert genericProc(true) == "(true, 15)" +# redefine +template bar: int {.redefine.} = foo2.bar +doAssert bar == -10 + +block: # subscript + var bazVal = @[1, 2, 3] + template baz: seq[int] = bazVal + doAssert baz[1] == 2 + proc genericProc2[T](x: T): string = + result = $(x, baz[1]) + baz[1] = 7 + doAssert genericProc2(true) == "(true, 2)" + doAssert baz[1] == 7 + baz[1] = 14 + doAssert baz[1] == 14 + +block: # type alias + template Int2: untyped = int + let x: Int2 = 123 + proc generic[T](): string = + template U: untyped = T + var x: U + result = $typeof(x) + doAssert result == $U + doAssert result == $T + doAssert generic[int]() == "int" + doAssert generic[Int2]() == "int" + doAssert generic[string]() == "string" + doAssert generic[seq[int]]() == "seq[int]" + doAssert generic[seq[Int2]]() == "seq[int]" + discard generic[123]() + proc genericStatic[X; T: static[X]](): string = + template U: untyped = T + result = $U + doAssert result == $T + doAssert genericStatic[int, 123]() == "123" + doAssert genericStatic[Int2, 123]() == "123" + doAssert genericStatic[(string, bool), ("a", true)]() == "(\"a\", true)" + +block: # issue #13515 + template test: bool = true + # compiles: + if not test: + doAssert false + # does not compile: + template x = + if not test: + doAssert false + x diff --git a/tests/template/taliassyntaxerrors.nim b/tests/template/taliassyntaxerrors.nim new file mode 100644 index 0000000000..f16acaf919 --- /dev/null +++ b/tests/template/taliassyntaxerrors.nim @@ -0,0 +1,28 @@ +discard """ + cmd: "nim check --hints:off $file" +""" + +block: # with params + type Foo = object + bar: int + + var foo = Foo(bar: 10) + template bar(x: int): int = x + foo.bar + let a = bar #[tt.Error + ^ invalid type: 'template (x: int): int' for let. Did you mean to call the template with '()'?]# + bar = 15 #[tt.Error + ^ 'bar' cannot be assigned to]# + +block: # generic template + type Foo = object + bar: int + + var foo = Foo(bar: 10) + template bar[T]: T = T(foo.bar) + let a = bar #[tt.Error + ^ invalid type: 'template (): T' for let. Did you mean to call the template with '()'?; tt.Error + ^ 'bar' has unspecified generic parameters]# + let b = bar[float]() + doAssert b == 10.0 + bar = 15 #[tt.Error + ^ 'bar' cannot be assigned to]# From 6ad246b2155bdac0dae35b3853207d72594bdc0b Mon Sep 17 00:00:00 2001 From: metagn Date: Sun, 23 Apr 2023 08:09:25 +0300 Subject: [PATCH 015/489] temporarily disable badssl tests (#21710) * temporarily disable badssl tests refs #21709 * fix --- .../thttpclient_ssl_remotenetwork.nim | 142 ++++++++++-------- 1 file changed, 77 insertions(+), 65 deletions(-) diff --git a/tests/untestable/thttpclient_ssl_remotenetwork.nim b/tests/untestable/thttpclient_ssl_remotenetwork.nim index d2366d9a97..65f7cc8d61 100644 --- a/tests/untestable/thttpclient_ssl_remotenetwork.nim +++ b/tests/untestable/thttpclient_ssl_remotenetwork.nim @@ -32,65 +32,71 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win good, bad, dubious, good_broken, bad_broken, dubious_broken CertTest = tuple[url:string, category:Category, desc: string] - const certificate_tests: array[0..54, CertTest] = [ - ("https://wrong.host.badssl.com/", bad, "wrong.host"), - ("https://captive-portal.badssl.com/", bad, "captive-portal"), - ("https://expired.badssl.com/", bad, "expired"), - ("https://google.com/", good, "good"), - ("https://self-signed.badssl.com/", bad, "self-signed"), - ("https://untrusted-root.badssl.com/", bad, "untrusted-root"), - ("https://revoked.badssl.com/", bad_broken, "revoked"), - ("https://pinning-test.badssl.com/", bad_broken, "pinning-test"), - ("https://no-common-name.badssl.com/", bad, "no-common-name"), - ("https://no-subject.badssl.com/", bad, "no-subject"), - ("https://sha1-intermediate.badssl.com/", bad, "sha1-intermediate"), - ("https://sha256.badssl.com/", good, "sha256"), - ("https://sha384.badssl.com/", bad, "sha384"), - ("https://sha512.badssl.com/", bad, "sha512"), - ("https://1000-sans.badssl.com/", bad, "1000-sans"), - ("https://10000-sans.badssl.com/", good_broken, "10000-sans"), - ("https://ecc256.badssl.com/", good_broken, "ecc256"), - ("https://ecc384.badssl.com/", good_broken, "ecc384"), - ("https://rsa2048.badssl.com/", good, "rsa2048"), - ("https://rsa8192.badssl.com/", dubious_broken, "rsa8192"), - ("http://http.badssl.com/", good, "regular http"), - ("https://http.badssl.com/", bad_broken, "http on https URL"), # FIXME - ("https://cbc.badssl.com/", dubious, "cbc"), - ("https://rc4-md5.badssl.com/", bad, "rc4-md5"), - ("https://rc4.badssl.com/", bad, "rc4"), - ("https://3des.badssl.com/", bad, "3des"), - ("https://null.badssl.com/", bad, "null"), - ("https://mozilla-old.badssl.com/", bad_broken, "mozilla-old"), - ("https://mozilla-intermediate.badssl.com/", dubious_broken, "mozilla-intermediate"), - ("https://mozilla-modern.badssl.com/", good, "mozilla-modern"), - ("https://dh480.badssl.com/", bad, "dh480"), - ("https://dh512.badssl.com/", bad, "dh512"), - ("https://dh1024.badssl.com/", dubious_broken, "dh1024"), - ("https://dh2048.badssl.com/", good, "dh2048"), - ("https://dh-small-subgroup.badssl.com/", bad_broken, "dh-small-subgroup"), - ("https://dh-composite.badssl.com/", bad_broken, "dh-composite"), - ("https://static-rsa.badssl.com/", dubious, "static-rsa"), - ("https://tls-v1-0.badssl.com:1010/", dubious, "tls-v1-0"), - ("https://tls-v1-1.badssl.com:1011/", dubious, "tls-v1-1"), - ("https://invalid-expected-sct.badssl.com/", bad, "invalid-expected-sct"), - ("https://hsts.badssl.com/", good, "hsts"), - ("https://upgrade.badssl.com/", good, "upgrade"), - ("https://preloaded-hsts.badssl.com/", good, "preloaded-hsts"), - ("https://subdomain.preloaded-hsts.badssl.com/", bad, "subdomain.preloaded-hsts"), - ("https://https-everywhere.badssl.com/", good, "https-everywhere"), - ("https://long-extended-subdomain-name-containing-many-letters-and-dashes.badssl.com/", good, - "long-extended-subdomain-name-containing-many-letters-and-dashes"), - ("https://longextendedsubdomainnamewithoutdashesinordertotestwordwrapping.badssl.com/", good, - "longextendedsubdomainnamewithoutdashesinordertotestwordwrapping"), - ("https://superfish.badssl.com/", bad, "(Lenovo) Superfish"), - ("https://edellroot.badssl.com/", bad, "(Dell) eDellRoot"), - ("https://dsdtestprovider.badssl.com/", bad, "(Dell) DSD Test Provider"), - ("https://preact-cli.badssl.com/", bad, "preact-cli"), - ("https://webpack-dev-server.badssl.com/", bad, "webpack-dev-server"), - ("https://mitm-software.badssl.com/", bad, "mitm-software"), - ("https://sha1-2016.badssl.com/", dubious, "sha1-2016"), - ("https://sha1-2017.badssl.com/", bad, "sha1-2017"), - ] + # XXX re-enable when badssl fixes certs, some expired as of 2023-04-23 (#21709) + when false: + const certificate_tests: array[0..54, CertTest] = [ + ("https://wrong.host.badssl.com/", bad, "wrong.host"), + ("https://captive-portal.badssl.com/", bad, "captive-portal"), + ("https://expired.badssl.com/", bad, "expired"), + ("https://google.com/", good, "good"), + ("https://self-signed.badssl.com/", bad, "self-signed"), + ("https://untrusted-root.badssl.com/", bad, "untrusted-root"), + ("https://revoked.badssl.com/", bad_broken, "revoked"), + ("https://pinning-test.badssl.com/", bad_broken, "pinning-test"), + ("https://no-common-name.badssl.com/", bad, "no-common-name"), + ("https://no-subject.badssl.com/", bad, "no-subject"), + ("https://sha1-intermediate.badssl.com/", bad, "sha1-intermediate"), + ("https://sha256.badssl.com/", good, "sha256"), + ("https://sha384.badssl.com/", bad, "sha384"), + ("https://sha512.badssl.com/", bad, "sha512"), + ("https://1000-sans.badssl.com/", bad, "1000-sans"), + ("https://10000-sans.badssl.com/", good_broken, "10000-sans"), + ("https://ecc256.badssl.com/", good_broken, "ecc256"), + ("https://ecc384.badssl.com/", good_broken, "ecc384"), + ("https://rsa2048.badssl.com/", good, "rsa2048"), + ("https://rsa8192.badssl.com/", dubious_broken, "rsa8192"), + ("http://http.badssl.com/", good, "regular http"), + ("https://http.badssl.com/", bad_broken, "http on https URL"), # FIXME + ("https://cbc.badssl.com/", dubious, "cbc"), + ("https://rc4-md5.badssl.com/", bad, "rc4-md5"), + ("https://rc4.badssl.com/", bad, "rc4"), + ("https://3des.badssl.com/", bad, "3des"), + ("https://null.badssl.com/", bad, "null"), + ("https://mozilla-old.badssl.com/", bad_broken, "mozilla-old"), + ("https://mozilla-intermediate.badssl.com/", dubious_broken, "mozilla-intermediate"), + ("https://mozilla-modern.badssl.com/", good, "mozilla-modern"), + ("https://dh480.badssl.com/", bad, "dh480"), + ("https://dh512.badssl.com/", bad, "dh512"), + ("https://dh1024.badssl.com/", dubious_broken, "dh1024"), + ("https://dh2048.badssl.com/", good, "dh2048"), + ("https://dh-small-subgroup.badssl.com/", bad_broken, "dh-small-subgroup"), + ("https://dh-composite.badssl.com/", bad_broken, "dh-composite"), + ("https://static-rsa.badssl.com/", dubious, "static-rsa"), + ("https://tls-v1-0.badssl.com:1010/", dubious, "tls-v1-0"), + ("https://tls-v1-1.badssl.com:1011/", dubious, "tls-v1-1"), + ("https://invalid-expected-sct.badssl.com/", bad, "invalid-expected-sct"), + ("https://hsts.badssl.com/", good, "hsts"), + ("https://upgrade.badssl.com/", good, "upgrade"), + ("https://preloaded-hsts.badssl.com/", good, "preloaded-hsts"), + ("https://subdomain.preloaded-hsts.badssl.com/", bad, "subdomain.preloaded-hsts"), + ("https://https-everywhere.badssl.com/", good, "https-everywhere"), + ("https://long-extended-subdomain-name-containing-many-letters-and-dashes.badssl.com/", good, + "long-extended-subdomain-name-containing-many-letters-and-dashes"), + ("https://longextendedsubdomainnamewithoutdashesinordertotestwordwrapping.badssl.com/", good, + "longextendedsubdomainnamewithoutdashesinordertotestwordwrapping"), + ("https://superfish.badssl.com/", bad, "(Lenovo) Superfish"), + ("https://edellroot.badssl.com/", bad, "(Dell) eDellRoot"), + ("https://dsdtestprovider.badssl.com/", bad, "(Dell) DSD Test Provider"), + ("https://preact-cli.badssl.com/", bad, "preact-cli"), + ("https://webpack-dev-server.badssl.com/", bad, "webpack-dev-server"), + ("https://mitm-software.badssl.com/", bad, "mitm-software"), + ("https://sha1-2016.badssl.com/", dubious, "sha1-2016"), + ("https://sha1-2017.badssl.com/", bad, "sha1-2017"), + ] + else: + const certificate_tests: array[0..0, CertTest] = [ + ("https://google.com/", good, "good") + ] template evaluate(exception_msg: string, category: Category, desc: string) = @@ -190,12 +196,18 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win type NetSocketTest = tuple[hostname: string, port: Port, category:Category, desc: string] - const net_tests:array[0..3, NetSocketTest] = [ - ("imap.gmail.com", 993.Port, good, "IMAP"), - ("wrong.host.badssl.com", 443.Port, bad, "wrong.host"), - ("captive-portal.badssl.com", 443.Port, bad, "captive-portal"), - ("expired.badssl.com", 443.Port, bad, "expired"), - ] + # XXX re-enable when badssl fixes certs, some expired as of 2023-04-23 (#21709) + when false: + const net_tests:array[0..3, NetSocketTest] = [ + ("imap.gmail.com", 993.Port, good, "IMAP"), + ("wrong.host.badssl.com", 443.Port, bad, "wrong.host"), + ("captive-portal.badssl.com", 443.Port, bad, "captive-portal"), + ("expired.badssl.com", 443.Port, bad, "expired"), + ] + else: + const net_tests: array[0..0, NetSocketTest] = [ + ("imap.gmail.com", 993.Port, good, "IMAP") + ] # TODO: ("null.badssl.com", 443.Port, bad_broken, "null"), From 265a340e807a44c63c31ba7ffda1f68f6f887624 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 23 Apr 2023 15:34:46 +0800 Subject: [PATCH 016/489] fixes booting warnings (#21711) follow up https://github.com/nim-lang/Nim/pull/21604 --- compiler/spawn.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 581f722d53..0931407d46 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -317,7 +317,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; call.add(threadLocal.newSymNode) proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExpr: PNode; retType: PType; - barrier, dest: PNode = nil): PNode = + barrier: PNode = nil, dest: PNode = nil): PNode = # if 'barrier' != nil, then it is in a 'parallel' section and we # generate quite different code let n = spawnExpr[^2] From 380dafcc32abed83148f5da78a2aaef608831f8a Mon Sep 17 00:00:00 2001 From: metagn Date: Sun, 23 Apr 2023 12:43:59 +0300 Subject: [PATCH 017/489] fix iterator equality + add test for proc equality + fix sameType (#21707) * fix iterator equality + add test also for procs fixes #21706 * all targets * and isNil and repr * separate overloads, fix sameType * more restricted sameType? * merge overloads again?? * remove sametype change for now * fix sameType anyway (CI failure was not related) --------- Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- compiler/sigmatch.nim | 2 +- compiler/types.nim | 6 +++- lib/system.nim | 2 +- lib/system/comparisons.nim | 2 +- lib/system/repr_v2.nim | 2 +- tests/system/tcomparisons.nim | 51 ++++++++++++++++++++++++++++++++ tests/typerel/tproctypeclass.nim | 13 ++++++++ 7 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 tests/system/tcomparisons.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index ad88ed7b26..19fa0b5997 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -372,7 +372,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType = of tyOwned: # bug #11257: the comparison system.`==`[T: proc](x, y: T) works # better without the 'owned' type: - if f != nil and f.len > 0 and f[0].skipTypes({tyBuiltInTypeClass}).kind == tyProc: + if f != nil and f.len > 0 and f[0].skipTypes({tyBuiltInTypeClass, tyOr}).kind == tyProc: result = t.lastSon else: result = t diff --git a/compiler/types.nim b/compiler/types.nim index 3874295675..d2517127a9 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1235,7 +1235,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = assert a[0].len == 0 assert b.len == 1 assert b[0].len == 0 - result = a[0].kind == b[0].kind + result = a[0].kind == b[0].kind and sameFlags(a[0], b[0]) + if result and a[0].kind == tyProc and IgnoreCC notin c.flags: + let ecc = a[0].flags * {tfExplicitCallConv} + result = ecc == b[0].flags * {tfExplicitCallConv} and + (ecc == {} or a[0].callConv == b[0].callConv) of tyGenericInvocation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyLent, tySink, tyUncheckedArray, tyArray, tyProc, tyVarargs, tyOrdinal, tyCompositeTypeClass, tyUserTypeClass, tyUserTypeClassInst, diff --git a/lib/system.nim b/lib/system.nim index dcf09d6044..f232423152 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1405,7 +1405,7 @@ proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".} 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".} -proc isNil*[T: proc](x: T): bool {.noSideEffect, magic: "IsNil".} +proc isNil*[T: proc | iterator {.closure.}](x: T): bool {.noSideEffect, magic: "IsNil".} ## Fast check whether `x` is nil. This is sometimes more efficient than ## `== nil`. diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index 36d4d06a8e..9759c3c99a 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -35,7 +35,7 @@ proc `==`*[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.} ## Checks that two `ref` variables refer to the same item. proc `==`*[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.} ## Checks that two `ptr` variables refer to the same item. -proc `==`*[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.} +proc `==`*[T: proc | iterator](x, y: T): bool {.magic: "EqProc", noSideEffect.} ## Checks that two `proc` variables refer to the same procedure. proc `<=`*[Enum: enum](x, y: Enum): bool {.magic: "LeEnum", noSideEffect.} diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index 206b5c5f56..e9a6596fd3 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -94,7 +94,7 @@ proc repr*(p: pointer): string = result[j] = HexChars[n and 0xF] n = n shr 4 -proc repr*(p: proc): string = +proc repr*(p: proc | iterator {.closure.}): string = ## repr of a proc as its address repr(cast[ptr pointer](unsafeAddr p)[]) diff --git a/tests/system/tcomparisons.nim b/tests/system/tcomparisons.nim new file mode 100644 index 0000000000..a661b14a15 --- /dev/null +++ b/tests/system/tcomparisons.nim @@ -0,0 +1,51 @@ +discard """ + targets: "c cpp js" +""" + +template main = + block: # proc equality + var prc: proc(): int {.closure.} + prc = nil + doAssert prc == nil + doAssert prc.isNil + prc = proc(): int = + result = 123 + doAssert prc != nil + doAssert not prc.isNil + doAssert prc == prc + let prc2 = prc + doAssert prc == prc2 + doAssert prc2 != nil + doAssert not prc2.isNil + doAssert not prc.isNil + prc = proc(): int = + result = 456 + doAssert prc != nil + doAssert not prc.isNil + doAssert prc != prc2 + block: # iterator equality + when nimvm: discard # vm does not support closure iterators + else: + when not defined(js): # js also does not support closure iterators + var iter: iterator(): int {.closure.} + iter = nil + doAssert iter == nil + doAssert iter.isNil + iter = iterator(): int = + yield 123 + doAssert iter != nil + doAssert not iter.isNil + doAssert iter == iter + let iter2 = iter + doAssert iter == iter2 + doAssert iter2 != nil + doAssert not iter2.isNil + doAssert not iter.isNil + iter = iterator(): int = + yield 456 + doAssert iter != nil + doAssert not iter.isNil + doAssert iter != iter2 + +static: main() +main() diff --git a/tests/typerel/tproctypeclass.nim b/tests/typerel/tproctypeclass.nim index 4df9c558b9..e8fab97804 100644 --- a/tests/typerel/tproctypeclass.nim +++ b/tests/typerel/tproctypeclass.nim @@ -73,4 +73,17 @@ proc main = doAssert closureProc is proc takesAnyProc(closureProc) + block: # supposed to test that sameType works + template ensureNotRedefine(Ty): untyped = + proc foo[T: Ty](x: T) = discard + doAssert not (compiles do: + proc bar[T: Ty](x: T) = discard + proc bar[T: Ty](x: T) = discard) + ensureNotRedefine proc + ensureNotRedefine iterator + ensureNotRedefine proc {.nimcall.} + ensureNotRedefine iterator {.nimcall.} + ensureNotRedefine proc {.closure.} + ensureNotRedefine iterator {.closure.} + main() From 20b011de19c507380164c46c04cce174842f8e9e Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 24 Apr 2023 06:52:37 +0200 Subject: [PATCH 018/489] =?UTF-8?q?refactoring=20in=20preparation=20for=20?= =?UTF-8?q?better,=20simpler=20name=20mangling=20that=20wor=E2=80=A6=20(#2?= =?UTF-8?q?1667)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactoring in preparation for better, simpler name mangling that works with IC flawlessly * use new disamb field * see if this makes tests green * make tests green again --- compiler/ast.nim | 26 +++++++--- compiler/ccgtypes.nim | 84 ++++++++++++++++---------------- compiler/cgmeth.nim | 4 +- compiler/closureiters.nim | 8 +-- compiler/concepts.nim | 2 +- compiler/enumtostr.nim | 12 ++--- compiler/evaltempl.nim | 2 +- compiler/ic/ic.nim | 3 +- compiler/ic/packed_ast.nim | 3 +- compiler/importer.nim | 2 +- compiler/injectdestructors.nim | 6 +-- compiler/lambdalifting.nim | 18 +++---- compiler/liftdestructors.nim | 18 +++---- compiler/lookups.nim | 2 +- compiler/lowerings.nim | 15 +++--- compiler/magicsys.nim | 4 +- compiler/modulegraphs.nim | 2 +- compiler/nilcheck.nim | 4 +- compiler/packages.nim | 8 +-- compiler/plugins/itersgen.nim | 2 +- compiler/plugins/locals.nim | 2 +- compiler/pragmas.nim | 10 ++-- compiler/sem.nim | 8 +-- compiler/semdata.nim | 2 +- compiler/semexprs.nim | 10 ++-- compiler/semfields.nim | 2 +- compiler/semgnrc.nim | 2 +- compiler/seminst.nim | 12 ++--- compiler/semmagic.nim | 8 +-- compiler/semparallel.nim | 2 +- compiler/sempass2.nim | 4 +- compiler/semstmts.nim | 16 +++--- compiler/semtempl.nim | 2 +- compiler/semtypes.nim | 10 ++-- compiler/semtypinst.nim | 2 +- compiler/sighashes.nim | 2 +- compiler/sigmatch.nim | 4 +- compiler/sizealignoffsetimpl.nim | 50 +++++++++---------- compiler/spawn.nim | 26 +++++----- compiler/transf.nim | 7 ++- compiler/vm.nim | 2 +- compiler/vmdeps.nim | 2 +- compiler/vmgen.nim | 4 +- compiler/vmmarshal.nim | 2 +- tests/ccgbugs/tnoalias.nim | 2 +- 45 files changed, 216 insertions(+), 202 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 8aa4ca6b1e..bf942f7849 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -919,7 +919,9 @@ type # for modules, an unique index corresponding # to the module's fileIdx # for variables a slot index for the evaluator - offset*: int # offset of record field + offset*: int32 # offset of record field + disamb*: int32 # disambiguation number; the basic idea is that + # `___` loc*: TLoc annex*: PLib # additional fields (seldom used, so we use a # reference to another object to save space) @@ -1143,13 +1145,17 @@ type symId*: int32 typeId*: int32 sealed*: bool + disambTable*: CountTable[PIdent] const PackageModuleId* = -3'i32 proc idGeneratorFromModule*(m: PSym): IdGenerator = assert m.kind == skModule - result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0) + result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0, disambTable: initCountTable[PIdent]()) + +proc idGeneratorForPackage*(nextIdWillBe: int32): IdGenerator = + result = IdGenerator(module: PackageModuleId, symId: nextIdWillBe - 1'i32, typeId: 0, disambTable: initCountTable[PIdent]()) proc nextSymId*(x: IdGenerator): ItemId {.inline.} = assert(not x.sealed) @@ -1341,11 +1347,15 @@ when false: echo k echo v -proc newSym*(symKind: TSymKind, name: PIdent, id: ItemId, owner: PSym, +proc newSym*(symKind: TSymKind, name: PIdent, idgen: IdGenerator; owner: PSym, info: TLineInfo; options: TOptions = {}): PSym = # generates a symbol and initializes the hash field too + assert not name.isNil + let id = nextSymId idgen result = PSym(name: name, kind: symKind, flags: {}, info: info, itemId: id, - options: options, owner: owner, offset: defaultOffset) + options: options, owner: owner, offset: defaultOffset, + disamb: getOrDefault(idgen.disambTable, name).int32) + idgen.disambTable.inc name when false: if id.module == 48 and id.item == 39: writeStackTrace() @@ -1559,8 +1569,8 @@ proc copyType*(t: PType, id: ItemId, owner: PSym): PType = proc exactReplica*(t: PType): PType = result = copyType(t, t.itemId, t.owner) -proc copySym*(s: PSym; id: ItemId): PSym = - result = newSym(s.kind, s.name, id, s.owner, s.info, s.options) +proc copySym*(s: PSym; idgen: IdGenerator): PSym = + result = newSym(s.kind, s.name, idgen, s.owner, s.info, s.options) #result.ast = nil # BUGFIX; was: s.ast which made problems result.typ = s.typ result.flags = s.flags @@ -1575,9 +1585,9 @@ proc copySym*(s: PSym; id: ItemId): PSym = result.bitsize = s.bitsize result.alignment = s.alignment -proc createModuleAlias*(s: PSym, id: ItemId, newIdent: PIdent, info: TLineInfo; +proc createModuleAlias*(s: PSym, idgen: IdGenerator, newIdent: PIdent, info: TLineInfo; options: TOptions): PSym = - result = newSym(s.kind, newIdent, id, s.owner, info, options) + result = newSym(s.kind, newIdent, idgen, s.owner, info, options) # keep ID! result.ast = s.ast #result.id = s.id # XXX figure out what to do with the ID. diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 6cc009bb96..65f938ca03 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -39,10 +39,10 @@ proc fillBackendName(m: BModule; s: PSym) = var result = s.name.s.mangle.rope result.add "__" result.add m.g.graph.ifaces[s.itemId.module].uniqueName - result.add "_" - result.add rope s.itemId.item + result.add "_u" + result.addInt s.itemId.item # s.disamb # if m.hcrOn: - result.add "_" + result.add '_' result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config)) s.loc.r = result writeMangledName(m.ndi, s, m.config) @@ -50,7 +50,9 @@ proc fillBackendName(m: BModule; s: PSym) = proc fillParamName(m: BModule; s: PSym) = if s.loc.r == "": var res = s.name.s.mangle - res.add idOrSig(s, res, m.sigConflicts, m.config) + res.add "_p" + res.addInt s.position + #res.add idOrSig(s, res, m.sigConflicts, m.config) # Take into account if HCR is on because of the following scenario: # if a module gets imported and it has some more importc symbols in it, # some param names might receive the "_0" suffix to distinguish from what @@ -203,7 +205,7 @@ proc isImportedCppType(t: PType): bool = proc isOrHasImportedCppType(typ: PType): bool = searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType) -proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope +proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TSymKind): Rope proc isObjLackingTypeField(typ: PType): bool {.inline.} = result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and @@ -247,7 +249,7 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope = # linear search is not necessary anymore: result = tab.getOrDefault(sig) -proc addAbiCheck(m: BModule, t: PType, name: Rope) = +proc addAbiCheck(m: BModule; t: PType, name: Rope) = if isDefined(m.config, "checkAbi") and (let size = getSize(m.config, t); size != szUnknownSize): var msg = "backend & Nim disagree on size for: " msg.addTypeHeader(m.config, t) @@ -272,7 +274,7 @@ proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope = else: result = rope(literal) -proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = +proc getSimpleTypeDesc(m: BModule; typ: PType): Rope = const NumericalTypeToStr: array[tyInt..tyUInt64, string] = [ "NI", "NI8", "NI16", "NI32", "NI64", @@ -309,13 +311,13 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = if cacheGetType(m.typeCache, sig) == "": m.typeCache[sig] = result -proc pushType(m: BModule, typ: PType) = +proc pushType(m: BModule; typ: PType) = for i in 0..high(m.typeStack): # pointer equality is good enough here: if m.typeStack[i] == typ: return m.typeStack.add(typ) -proc getTypePre(m: BModule, typ: PType; sig: SigHash): Rope = +proc getTypePre(m: BModule; typ: PType; sig: SigHash): Rope = if typ == nil: result = rope("void") else: result = getSimpleTypeDesc(m, typ) @@ -328,7 +330,7 @@ proc structOrUnion(t: PType): Rope = if tfUnion in t.flags: cachedUnion else: cachedStruct -proc addForwardStructFormat(m: BModule, structOrUnion: Rope, typename: Rope) = +proc addForwardStructFormat(m: BModule; structOrUnion: Rope, typename: Rope) = if m.compileToCpp: m.s[cfsForwardTypes].addf "$1 $2;$n", [structOrUnion, typename] else: @@ -338,7 +340,7 @@ proc seqStar(m: BModule): string = if optSeqDestructors in m.config.globalOptions: result = "" else: result = "*" -proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = +proc getTypeForward(m: BModule; typ: PType; sig: SigHash): Rope = result = cacheGetType(m.forwTypeCache, sig) if result != "": return result = getTypePre(m, typ, sig) @@ -422,7 +424,7 @@ proc paramStorageLoc(param: PSym): TStorageLoc = else: result = OnUnknown -proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, +proc genProcParams(m: BModule; t: PType, rettype, params: var Rope, check: var IntSet, declareEnvironment=true; weakDep=false) = params = "(" @@ -492,7 +494,7 @@ proc mangleRecFieldName(m: BModule; field: PSym): Rope = result = rope(mangleField(m, field.name)) if result == "": internalError(m.config, field.info, "mangleRecFieldName") -proc genRecordFieldsAux(m: BModule, n: PNode, +proc genRecordFieldsAux(m: BModule; n: PNode, rectype: PType, check: var IntSet; result: var Rope; unionPrefix = "") = case n.kind @@ -562,7 +564,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode, result.addf("$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) else: internalError(m.config, n.info, "genRecordFieldsAux()") -proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope = +proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope = result = newRopeAppender() genRecordFieldsAux(m, typ.n, typ, check, result) @@ -574,7 +576,7 @@ proc fillObjectFields*(m: BModule; typ: PType) = proc mangleDynLibProc(sym: PSym): Rope -proc getRecordDesc(m: BModule, typ: PType, name: Rope, +proc getRecordDesc(m: BModule; typ: PType, name: Rope, check: var IntSet): Rope = # declare the record: var hasField = false @@ -629,7 +631,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope, if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props: result.add "#pragma pack(pop)\L" -proc getTupleDesc(m: BModule, typ: PType, name: Rope, +proc getTupleDesc(m: BModule; typ: PType, name: Rope, check: var IntSet): Rope = result = "$1 $2 {$n" % [structOrUnion(typ), name] var desc: Rope = "" @@ -669,7 +671,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType = result = if result.kind == tyGenericInst: result[1] else: result.elemType -proc getOpenArrayDesc(m: BModule, t: PType, check: var IntSet; kind: TSymKind): Rope = +proc getOpenArrayDesc(m: BModule; t: PType, check: var IntSet; kind: TSymKind): Rope = let sig = hashType(t, m.config) if kind == skParam: result = getTypeDescWeak(m, t[0], check, kind) & "*" @@ -682,7 +684,7 @@ proc getOpenArrayDesc(m: BModule, t: PType, check: var IntSet; kind: TSymKind): m.s[cfsTypes].addf("typedef struct {$n$2* Field0;$nNI Field1;$n} $1;$n", [result, elemType]) -proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope = +proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TSymKind): Rope = # returns only the type's name var t = origTyp.skipTypes(irrelevantForBackend-{tyOwned}) @@ -916,7 +918,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKin # fixes bug #145: excl(check, t.id) -proc getTypeDesc(m: BModule, typ: PType; kind = skParam): Rope = +proc getTypeDesc(m: BModule; typ: PType; kind = skParam): Rope = var check = initIntSet() result = getTypeDescAux(m, typ, check, kind) @@ -926,7 +928,7 @@ type clHalfWithEnv, ## fn(args, void* env) type with trailing 'void* env' parameter clFull ## struct {fn(args, void* env), env} -proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope = +proc getClosureType(m: BModule; t: PType, kind: TClosureTypeKind): Rope = assert t.kind == tyProc var check = initIntSet() result = getTempName(m) @@ -957,13 +959,13 @@ proc finishTypeDescriptions(m: BModule) = template cgDeclFrmt*(s: PSym): string = s.constraint.strVal -proc isReloadable(m: BModule, prc: PSym): bool = +proc isReloadable(m: BModule; prc: PSym): bool = return m.hcrOn and sfNonReloadable notin prc.flags -proc isNonReloadable(m: BModule, prc: PSym): bool = +proc isNonReloadable(m: BModule; prc: PSym): bool = return m.hcrOn and sfNonReloadable in prc.flags -proc genProcHeader(m: BModule, prc: PSym; result: var Rope; asPtr: bool = false) = +proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false) = # using static is needed for inline procs var check = initIntSet() fillBackendName(m, prc) @@ -997,12 +999,12 @@ proc genProcHeader(m: BModule, prc: PSym; result: var Rope; asPtr: bool = false) # ------------------ type info generation ------------------------------------- -proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope +proc genTypeInfoV1(m: BModule; t: PType; info: TLineInfo): Rope proc getNimNode(m: BModule): Rope = result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)] inc(m.typeNodes) -proc tiNameForHcr(m: BModule, name: Rope): Rope = +proc tiNameForHcr(m: BModule; name: Rope): Rope = return if m.hcrOn: "(*".rope & name & ")" else: name proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; @@ -1051,7 +1053,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; else: m.s[cfsStrData].addf("N_LIB_PRIVATE TNimType $1;$n", [name]) -proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope; +proc genTypeInfoAux(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo) = var base: Rope if typ.len > 0 and typ.lastSon != nil: @@ -1065,7 +1067,7 @@ proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope; base = rope("0") genTypeInfoAuxBase(m, typ, origType, name, base, info) -proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope = +proc discriminatorTableName(m: BModule; objtype: PType, d: PSym): Rope = # bugfix: we need to search the type that contains the discriminator: var objtype = objtype.skipTypes(abstractPtrs) while lookupInRecord(objtype.n, d.name) == nil: @@ -1076,12 +1078,12 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope = proc rope(arg: Int128): Rope = rope($arg) -proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope = +proc discriminatorTableDecl(m: BModule; objtype: PType, d: PSym): Rope = cgsym(m, "TNimNode") var tmp = discriminatorTableName(m, objtype, d) result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(m.config, d.typ)+1)] -proc genTNimNodeArray(m: BModule, name: Rope, size: Rope) = +proc genTNimNodeArray(m: BModule; name: Rope, size: Rope) = if m.hcrOn: m.s[cfsData].addf("static TNimNode** $1;$n", [name]) m.hcrCreateTypeInfosProc.addf("\thcrRegisterGlobal($3, \"$1\", sizeof(TNimNode*) * $2, NULL, (void**)&$1);$n", @@ -1089,7 +1091,7 @@ proc genTNimNodeArray(m: BModule, name: Rope, size: Rope) = else: m.s[cfsTypeInit1].addf("static TNimNode* $1[$2];$n", [name, size]) -proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; +proc genObjectFields(m: BModule; typ, origType: PType, n: PNode, expr: Rope; info: TLineInfo) = case n.kind of nkRecList: @@ -1159,7 +1161,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope; field.loc.r, genTypeInfoV1(m, field.typ, info), makeCString(field.name.s)]) else: internalError(m.config, n.info, "genObjectFields") -proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) = +proc genObjectInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo) = if typ.kind == tyObject: if incompleteType(typ): localError(m.config, info, "request for RTTI generation for incomplete object: " & @@ -1177,7 +1179,7 @@ proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo t.flags.incl tfObjHasKids t = t[0] -proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) = +proc genTupleInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo) = genTypeInfoAuxBase(m, typ, typ, name, rope("0"), info) var expr = getNimNode(m) if typ.len > 0: @@ -1199,7 +1201,7 @@ proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) [expr, rope(typ.len)]) m.s[cfsTypeInit3].addf("$1.node = &$2;$n", [tiNameForHcr(m, name), expr]) -proc genEnumInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = +proc genEnumInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) = # Type information for enumerations is quite heavy, so we do some # optimizations here: The ``typ`` field is never set, as it is redundant # anyway. We generate a cstring array and a loop over it. Exceptional @@ -1240,14 +1242,14 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = # 1 << 2 is {ntfEnumHole} m.s[cfsTypeInit3].addf("$1.flags = 1<<2;$n", [tiNameForHcr(m, name)]) -proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = +proc genSetInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) = assert(typ[0] != nil) genTypeInfoAux(m, typ, typ, name, info) var tmp = getNimNode(m) m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 0;$n$3.node = &$1;$n", [tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)]) -proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = +proc genArrayInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) = genTypeInfoAuxBase(m, typ, typ, name, genTypeInfoV1(m, typ[1], info), info) proc fakeClosureType(m: BModule; owner: PSym): PType = @@ -1266,7 +1268,7 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) = m.s[cfsTypeInit3].addf("$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n", [result, s.loc.r]) -proc declareNimType(m: BModule, name: string; str: Rope, module: int) = +proc declareNimType(m: BModule; name: string; str: Rope, module: int) = let nr = rope(name) if m.hcrOn: m.s[cfsStrData].addf("static $2* $1;$n", [str, nr]) @@ -1335,7 +1337,7 @@ proc genDisplayElem(d: MD5Digest): uint32 = result += uint32(d[i]) result = result shl 8 -proc genDisplay(m: BModule, t: PType, depth: int): Rope = +proc genDisplay(m: BModule; t: PType, depth: int): Rope = result = Rope"{" var x = t var seqs = newSeq[string](depth+1) @@ -1434,7 +1436,7 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) -proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope = +proc genTypeInfoV2(m: BModule; t: PType; info: TLineInfo): Rope = let origType = t # distinct types can have their own destructors var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses - {tyDistinct}) @@ -1509,7 +1511,7 @@ proc typeToC(t: PType): string = # be clashes with our special meanings result.addInt ord(c) -proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = +proc genTypeInfoV1(m: BModule; t: PType; info: TLineInfo): Rope = let origType = t var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses) @@ -1610,10 +1612,10 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope = result = prefixTI.rope & result & ")".rope -proc genTypeSection(m: BModule, n: PNode) = +proc genTypeSection(m: BModule; n: PNode) = discard -proc genTypeInfo*(config: ConfigRef, m: BModule, t: PType; info: TLineInfo): Rope = +proc genTypeInfo*(config: ConfigRef, m: BModule; t: PType; info: TLineInfo): Rope = if optTinyRtti in config.globalOptions: result = genTypeInfoV2(m, t, info) else: diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 1711c5f9a4..cc37691fdf 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -113,7 +113,7 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) = s.ast[dispatcherPos] = dispatcher proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym = - var disp = copySym(s, nextSymId(idgen)) + var disp = copySym(s, idgen) incl(disp.flags, sfDispatcher) excl(disp.flags, sfExported) let old = disp.typ @@ -127,7 +127,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym = disp.loc.r = "" if s.typ[0] != nil: if disp.ast.len > resultPos: - disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextSymId(idgen)) + disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen) else: # We've encountered a method prototype without a filled-in # resultPos slot. We put a placeholder in there that will diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 5c048db2be..3c5d3991be 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -183,7 +183,7 @@ proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode = ctx.newStateAssgn(newIntTypeNode(stateNo, ctx.g.getSysType(TLineInfo(), tyInt))) proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym = - result = newSym(skVar, getIdent(ctx.g.cache, name), nextSymId(ctx.idgen), ctx.fn, ctx.fn.info) + result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.idgen, ctx.fn, ctx.fn.info) result.typ = typ assert(not typ.isNil) @@ -1348,7 +1348,7 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode = let idefs = copyNode(it) for v in 0..it.len-3: if it[v].kind == nkSym: - let x = copySym(it[v].sym, nextSymId(c.idgen)) + let x = copySym(it[v].sym, c.idgen) c.tab[it[v].sym.id] = x idefs.add newSymNode(x) else: @@ -1431,9 +1431,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n: # Lambda lifting was not done yet. Use temporary :state sym, which will # be handled specially by lambda lifting. Local temp vars (if needed) # should follow the same logic. - ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), nextSymId(idgen), fn, fn.info) + ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), idgen, fn, fn.info) ctx.stateVarSym.typ = g.createClosureIterStateType(fn, idgen) - ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), nextSymId(idgen), fn, fn.info) + ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), idgen, fn, fn.info) var pc = PreprocessContext(finallys: @[], config: g.config, idgen: idgen) var n = preprocess(pc, n.toStmtList) #echo "transformed into ", n diff --git a/compiler/concepts.nim b/compiler/concepts.nim index bcf2d4d0e1..6a383a937c 100644 --- a/compiler/concepts.nim +++ b/compiler/concepts.nim @@ -27,7 +27,7 @@ const proc declareSelf(c: PContext; info: TLineInfo) = ## Adds the magical 'Self' symbols to the current scope. let ow = getCurrOwner(c) - let s = newSym(skType, getIdent(c.cache, "Self"), nextSymId(c.idgen), ow, info) + let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info) s.typ = newType(tyTypeDesc, nextTypeId(c.idgen), ow) s.typ.flags.incl {tfUnresolved, tfPacked} s.typ.add newType(tyEmpty, nextTypeId(c.idgen), ow) diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim index f8b3744d5c..4ae17235b3 100644 --- a/compiler/enumtostr.nim +++ b/compiler/enumtostr.nim @@ -6,12 +6,12 @@ when defined(nimPreviewSlimSystem): proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = - result = newSym(skProc, getIdent(g.cache, "$"), nextSymId idgen, t.owner, info) + result = newSym(skProc, getIdent(g.cache, "$"), idgen, t.owner, info) - let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info) + let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info) dest.typ = t - let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info) + let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info) res.typ = getSysType(g, info, tyString) result.typ = newType(tyProc, nextTypeId idgen, t.owner) @@ -67,12 +67,12 @@ proc searchObjCase(t: PType; field: PSym): PNode = doAssert result != nil proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym = - result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), nextSymId idgen, t.owner, info) + result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), idgen, t.owner, info) - let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info) + let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info) dest.typ = field.typ - let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info) + let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info) res.typ = getSysType(g, info, tyUInt8) result.typ = newType(tyProc, nextTypeId idgen, t.owner) diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index d4aa466c2b..1b090a6d71 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -49,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) = internalAssert c.config, sfGenSym in s.flags or s.kind == skType var x = PSym(idTableGet(c.mapping, s)) if x == nil: - x = copySym(s, nextSymId(c.idgen)) + x = copySym(s, c.idgen) # sem'check needs to set the owner properly later, see bug #9476 x.owner = nil # c.genSymOwner #if x.kind == skParam and x.owner.kind == skModule: diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 36a57f11e2..793ece80a8 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -390,7 +390,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId assert sfForward notin s.flags var p = PackedSym(kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic, - position: s.position, offset: s.offset, options: s.options, + position: s.position, offset: s.offset, disamb: s.disamb, options: s.options, name: s.name.s.toLitId(m)) storeNode(p, s, ast) @@ -830,6 +830,7 @@ proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; options: s.options, position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position, offset: if s.kind in routineKinds: defaultOffset else: s.offset, + disamb: s.disamb, name: getIdent(c.cache, g[si].fromDisk.strings[s.name]) ) diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 87b1516fa6..dda07dcf20 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -63,7 +63,8 @@ type alignment*: int # for alignment options*: TOptions position*: int - offset*: int + offset*: int32 + disamb*: int32 externalName*: LitId # instead of TLoc locFlags*: TLocFlags annex*: PackedLib diff --git a/compiler/importer.nim b/compiler/importer.nim index 0324b2fbce..39a447b709 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -236,7 +236,7 @@ proc addUnique[T](x: var seq[T], y: sink T) {.noSideEffect.} = proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym = result = realModule template createModuleAliasImpl(ident): untyped = - createModuleAlias(realModule, nextSymId c.idgen, ident, n.info, c.config.options) + createModuleAlias(realModule, c.idgen, ident, n.info, c.config.options) if n.kind != nkImportAs: discard elif n.len != 2 or n[1].kind != nkIdent: localError(c.config, n.info, "module alias must be an identifier") diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 96102d54d2..6d5e070f27 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -70,7 +70,7 @@ proc hasDestructor(c: Con; t: PType): bool {.inline.} = assert(not containsGarbageCollectedRef(t)) proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = - let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), nextSymId c.idgen, c.owner, info) + let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.idgen, c.owner, info) sym.typ = typ s.vars.add(sym) result = newSymNode(sym) @@ -399,7 +399,7 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = else: result = newNodeIT(nkStmtListExpr, n.info, n.typ) - var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextSymId c.idgen, c.owner, n.info) + var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.idgen, c.owner, n.info) temp.typ = n.typ var v = newNodeI(nkLetSection, n.info) let tempAsNode = newSymNode(temp) @@ -1023,7 +1023,7 @@ proc sameLocation*(a, b: PNode): bool = proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode = # with side effects - var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), nextSymId c.idgen, c.owner, ri[1].info) + var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), c.idgen, c.owner, ri[1].info) temp.typ = ri[1].typ var v = newNodeI(nkLetSection, ri[1].info) let tempAsNode = newSymNode(temp) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index f6bc21c010..ce36123b3a 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -140,7 +140,7 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator) rawAddSon(result, intType) proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym = - result = newSym(skField, getIdent(g.cache, ":state"), nextSymId(idgen), iter, iter.info) + result = newSym(skField, getIdent(g.cache, ":state"), idgen, iter, iter.info) result.typ = createClosureIterStateType(g, iter, idgen) proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType = @@ -154,7 +154,7 @@ proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym result = iter.ast[resultPos].sym else: # XXX a bit hacky: - result = newSym(skResult, getIdent(g.cache, ":result"), nextSymId(idgen), iter, iter.info, {}) + result = newSym(skResult, getIdent(g.cache, ":result"), idgen, iter, iter.info, {}) result.typ = iter.typ[0] incl(result.flags, sfUsed) iter.ast.add newSymNode(result) @@ -267,7 +267,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache, idgen) env = indirectAccess(newSymNode(it), hp, hp.info) else: - let e = newSym(skLet, iter.name, nextSymId(idgen), owner, n.info) + let e = newSym(skLet, iter.name, idgen, owner, n.info) e.typ = hp.typ e.flags = hp.flags env = newSymNode(e) @@ -380,7 +380,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags: localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor") else: - let result = newSym(skField, upIdent, nextSymId(c.idgen), obj.owner, obj.owner.info) + let result = newSym(skField, upIdent, c.idgen, obj.owner, obj.owner.info) result.typ = fieldType when false: if c.graph.config.selectedGC == gcDestructors: @@ -418,7 +418,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) = let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner let t = c.getEnvTypeForOwner(owner, info) if cp == nil: - cp = newSym(skParam, getIdent(c.graph.cache, paramName), nextSymId(c.idgen), fn, fn.info) + cp = newSym(skParam, getIdent(c.graph.cache, paramName), c.idgen, fn, fn.info) incl(cp.flags, sfFromGeneric) cp.typ = t addHiddenParam(fn, cp) @@ -545,7 +545,7 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode = result = n proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idgen: IdGenerator): PNode = - var v = newSym(skVar, getIdent(cache, envName), nextSymId(idgen), owner, info) + var v = newSym(skVar, getIdent(cache, envName), idgen, owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = typ result = newSymNode(v) @@ -569,7 +569,7 @@ proc setupEnvVar(owner: PSym; d: var DetectionPass; result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info, d.idgen) c.envVars[owner.id] = result if optOwnedRefs in d.graph.config.globalOptions: - var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextSymId d.idgen, owner, info) + var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), d.idgen, owner, info) v.flags = {sfShadowed, sfGeneratedOp} v.typ = envVarType c.unownedEnvVars[owner.id] = newSymNode(v) @@ -653,7 +653,7 @@ proc closureCreationForIter(iter: PNode; d: var DetectionPass; c: var LiftingPass): PNode = result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ) let owner = iter.sym.skipGenericOwner - var v = newSym(skVar, getIdent(d.graph.cache, envName), nextSymId(d.idgen), owner, iter.info) + var v = newSym(skVar, getIdent(d.graph.cache, envName), d.idgen, owner, iter.info) incl(v.flags, sfShadowed) v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ) var vnode: PNode @@ -943,7 +943,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym): let iter = op.sym let hp = getHiddenParam(g, iter) - env = newSym(skLet, iter.name, nextSymId(idgen), owner, body.info) + env = newSym(skLet, iter.name, idgen, owner, body.info) env.typ = hp.typ env.flags = hp.flags diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 467f015d83..3fd3c5f378 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -243,7 +243,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = # for every field (dependent on dest.kind): # `=` dest.field, src.field # =destroy(blob) - var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info) + var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info) dummy.typ = y.typ if ccgIntroducedPtr(c.g.config, dummy, y.typ): # Because of potential aliasing when the src param is passed by ref, we need to check for equality here, @@ -252,7 +252,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x), newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y)) cond.typ = getSysType(c.g, x.info, tyBool) body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info))) - var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info) + var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info) temp.typ = x.typ incl(temp.flags, sfFromGeneric) var v = newNodeI(nkVarSection, c.info) @@ -464,7 +464,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = result = true proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = - var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info) + var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info) temp.typ = getSysType(c.g, body.info, tyInt) incl(temp.flags, sfFromGeneric) @@ -474,7 +474,7 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = body.add v proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode = - var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info) + var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info) temp.typ = value.typ incl(temp.flags, sfFromGeneric) @@ -954,10 +954,10 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp info: TLineInfo; idgen: IdGenerator): PSym = let procname = getIdent(g.cache, AttachedOpToStr[kind]) - result = newSym(skProc, procname, nextSymId(idgen), owner, info) - let dest = newSym(skParam, getIdent(g.cache, "dest"), nextSymId(idgen), result, info) + result = newSym(skProc, procname, idgen, owner, info) + let dest = newSym(skParam, getIdent(g.cache, "dest"), idgen, result, info) let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"), - nextSymId(idgen), result, info) + idgen, result, info) dest.typ = makeVarType(typ.owner, typ, idgen) if kind == attachedTrace: src.typ = getSysType(g, info, tyPointer) @@ -972,7 +972,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp if kind == attachedAsgn and g.config.selectedGC == gcOrc and cyclicType(typ.skipTypes(abstractInst)): let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"), - nextSymId(idgen), result, info) + idgen, result, info) cycleParam.typ = getSysType(g, info, tyBool) result.typ.addParam cycleParam @@ -1049,7 +1049,7 @@ proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym, a.addMemReset = true let discrimantDest = result.typ.n[1].sym - let dst = newSym(skVar, getIdent(g.cache, "dest"), nextSymId(idgen), result, info) + let dst = newSym(skVar, getIdent(g.cache, "dest"), idgen, result, info) dst.typ = makePtrType(typ.owner, typ, idgen) let dstSym = newSymNode(dst) let d = newDeref(dstSym) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 3b4599f2c2..81ea63c328 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -274,7 +274,7 @@ proc errorSym*(c: PContext, n: PNode): PSym = considerQuotedIdent(c, m) else: getIdent(c.cache, "err:" & renderTree(m)) - result = newSym(skError, ident, nextSymId(c.idgen), getCurrOwner(c), n.info, {}) + result = newSym(skError, ident, c.idgen, getCurrOwner(c), n.info, {}) result.typ = errorType(c) incl(result.flags, sfDiscardable) # pretend it's from the top level scope to prevent cascading errors: diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 54a59c80aa..bd81773a82 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -79,7 +79,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: P if avoidTemp: tempAsNode = value else: - var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen), + var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen, owner, value.info, g.config.options) temp.typ = skipTypes(value.typ, abstractInst) incl(temp.flags, sfFromGeneric) @@ -100,7 +100,7 @@ proc evalOnce*(g: ModuleGraph; value: PNode; idgen: IdGenerator; owner: PSym): P ## freely, multiple times. This is frequently required and such a builtin would also be ## handy to have in macros.nim. The value that can be reused is 'result.lastSon'! result = newNodeIT(nkStmtListExpr, value.info, value.typ) - var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen), + var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen, owner, value.info, g.config.options) temp.typ = skipTypes(value.typ, abstractInst) incl(temp.flags, sfFromGeneric) @@ -126,7 +126,7 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; o let value = n.lastSon result = newNodeI(nkStmtList, n.info) - var temp = newSym(skTemp, getIdent(g.cache, "_"), nextSymId(idgen), owner, value.info, owner.options) + var temp = newSym(skTemp, getIdent(g.cache, "_"), idgen, owner, value.info, owner.options) var v = newNodeI(nkLetSection, value.info) let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info) @@ -144,7 +144,7 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; o proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode = result = newNodeI(nkStmtList, n.info) # note: cannot use 'skTemp' here cause we really need the copy for the VM :-( - var temp = newSym(skVar, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, n.info, owner.options) + var temp = newSym(skVar, getIdent(g.cache, genPrefix), idgen, owner, n.info, owner.options) temp.typ = n[1].typ incl(temp.flags, sfFromGeneric) incl(temp.flags, sfGenSym) @@ -171,8 +171,7 @@ proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo rawAddSon(result, getCompilerProc(g, "RootObj").typ) result.n = newNodeI(nkRecList, info) let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s), - nextSymId(idgen), - owner, info, owner.options) + idgen, owner, info, owner.options) incl s.flags, sfAnon s.typ = result result.sym = s @@ -234,7 +233,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym # because of 'gensym' support, we have to mangle the name with its ID. # This is hacky but the clean solution is much more complex than it looks. var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), - nextSymId(idgen), s.owner, s.info, s.options) + idgen, s.owner, s.info, s.options) field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item) let t = skipIntLit(s.typ, idgen) field.typ = t @@ -250,7 +249,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym {.discardable.} = result = lookupInRecord(obj.n, s.itemId) if result == nil: - var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), nextSymId(idgen), + var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), idgen, s.owner, s.info, s.options) field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item) let t = skipIntLit(s.typ, idgen) diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index ab234a2a8c..8261b14c7e 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -26,7 +26,7 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym = result = systemModuleSym(g, getIdent(g.cache, name)) if result == nil: localError(g.config, info, "system module needs: " & name) - result = newSym(skError, getIdent(g.cache, name), nextSymId(g.idgen), g.systemModule, g.systemModule.info, {}) + result = newSym(skError, getIdent(g.cache, name), g.idgen, g.systemModule, g.systemModule.info, {}) result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule) if result.kind == skAlias: result = result.owner @@ -39,7 +39,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy result = r if result != nil: return result localError(g.config, info, "system module needs: " & name) - result = newSym(skError, id, nextSymId(g.idgen), g.systemModule, g.systemModule.info, {}) + result = newSym(skError, id, g.idgen, g.systemModule, g.systemModule.info, {}) result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule) proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType = diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 8ffbe20a58..4fdeb354e4 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -411,7 +411,7 @@ proc stopCompile*(g: ModuleGraph): bool {.inline.} = result = g.doStopCompile != nil and g.doStopCompile() proc createMagic*(g: ModuleGraph; idgen: IdGenerator; name: string, m: TMagic): PSym = - result = newSym(skProc, getIdent(g.cache, name), nextSymId(idgen), nil, unknownLineInfo, {}) + result = newSym(skProc, getIdent(g.cache, name), idgen, nil, unknownLineInfo, {}) result.magic = m result.flags = {sfNeverRaises} diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index 91d76b2b8d..5cc66f3ea4 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -909,7 +909,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode = else: "" var cache = newIdentCache() - var op = newSym(skVar, cache.getIdent(name), nextSymId ctx.idgen, nil, r.info) + var op = newSym(skVar, cache.getIdent(name), ctx.idgen, nil, r.info) op.magic = magic result = nkInfix.newTree( @@ -920,7 +920,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode = proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode = var cache = newIdentCache() - var op = newSym(skVar, cache.getIdent("not"), nextSymId ctx.idgen, nil, node.info) + var op = newSym(skVar, cache.getIdent("not"), ctx.idgen, nil, node.info) op.magic = mNot result = nkPrefix.newTree( diff --git a/compiler/packages.nim b/compiler/packages.nim index d8b97e374c..bb54d61546 100644 --- a/compiler/packages.nim +++ b/compiler/packages.nim @@ -8,7 +8,7 @@ # ## Package related procs. -## +## ## See Also: ## * `packagehandling` for package path handling ## * `modulegraphs.getPackage` @@ -22,7 +22,7 @@ when defined(nimPreviewSlimSystem): proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym = ## Return a new package symbol. - ## + ## ## See Also: ## * `modulegraphs.getPackage` let @@ -31,7 +31,7 @@ proc getPackage*(conf: ConfigRef; cache: IdentCache; fileIdx: FileIndex): PSym = info = newLineInfo(fileIdx, 1, 1) pkgName = getPackageName(conf, filename.string) pkgIdent = getIdent(cache, pkgName) - newSym(skPackage, pkgIdent, ItemId(module: PackageModuleId, item: int32(fileIdx)), nil, info) + newSym(skPackage, pkgIdent, idGeneratorForPackage(int32(fileIdx)), nil, info) func getPackageSymbol*(sym: PSym): PSym = ## Return the owning package symbol. @@ -47,7 +47,7 @@ func getPackageId*(sym: PSym): int = func belongsToProjectPackage*(conf: ConfigRef, sym: PSym): bool = ## Return whether the symbol belongs to the project's package. - ## + ## ## See Also: ## * `modulegraphs.belongsToStdlib` conf.mainPackageId == sym.getPackageId diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim index 24e26b2b7b..1a291c04d2 100644 --- a/compiler/plugins/itersgen.nim +++ b/compiler/plugins/itersgen.nim @@ -31,7 +31,7 @@ proc iterToProcImpl*(c: PContext, n: PNode): PNode = return let body = liftIterToProc(c.graph, iter.sym, getBody(c.graph, iter.sym), t, c.idgen) - let prc = newSym(skProc, n[3].ident, nextSymId c.idgen, iter.sym.owner, iter.sym.info) + let prc = newSym(skProc, n[3].ident, c.idgen, iter.sym.owner, iter.sym.info) prc.typ = copyType(iter.sym.typ, nextTypeId c.idgen, prc) excl prc.typ.flags, tfCapturesEnv prc.typ.n.add newSymNode(getEnvParam(iter.sym)) diff --git a/compiler/plugins/locals.nim b/compiler/plugins/locals.nim index 384780f7ba..d3046cd659 100644 --- a/compiler/plugins/locals.nim +++ b/compiler/plugins/locals.nim @@ -26,7 +26,7 @@ proc semLocals*(c: PContext, n: PNode): PNode = {tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyUntyped, tyTyped, tyEmpty}: if it.owner == owner: - var field = newSym(skField, it.name, nextSymId c.idgen, owner, n.info) + var field = newSym(skField, it.name, c.idgen, owner, n.info) field.typ = it.typ.skipTypes({tyVar}) field.position = counter inc(counter) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index c752c5263e..22677ba015 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -139,7 +139,7 @@ proc pragmaEnsures(c: PContext, n: PNode) = openScope(c) let o = getCurrOwner(c) if o.kind in routineKinds and o.typ != nil and o.typ.sons[0] != nil: - var s = newSym(skResult, getIdent(c.cache, "result"), nextSymId(c.idgen), o, n.info) + var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen, o, n.info) s.typ = o.typ.sons[0] incl(s.flags, sfUsed) addDecl(c, s) @@ -675,7 +675,7 @@ proc processPragma(c: PContext, n: PNode, i: int) = elif it.safeLen != 2 or it[0].kind != nkIdent or it[1].kind != nkIdent: invalidPragma(c, n) - var userPragma = newSym(skTemplate, it[1].ident, nextSymId(c.idgen), c.module, it.info, c.config.options) + var userPragma = newSym(skTemplate, it[1].ident, c.idgen, c.module, it.info, c.config.options) userPragma.ast = newTreeI(nkPragma, n.info, n.sons[i+1..^1]) strTableAdd(c.userPragmas, userPragma) @@ -741,7 +741,7 @@ proc deprecatedStmt(c: PContext; outerPragma: PNode) = if dest == nil or dest.kind in routineKinds: localError(c.config, n.info, warnUser, "the .deprecated pragma is unreliable for routines") let src = considerQuotedIdent(c, n[0]) - let alias = newSym(skAlias, src, nextSymId(c.idgen), dest, n[0].info, c.config.options) + let alias = newSym(skAlias, src, c.idgen, dest, n[0].info, c.config.options) incl(alias.flags, sfExported) if sfCompilerProc in dest.flags: markCompilerProc(c, alias) addInterfaceDecl(c, alias) @@ -763,7 +763,7 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym = # We return a dummy symbol; later passes over the type will repair it. # Generic instantiation needs to know about this too. But we're lazy # and perform the lookup on demand instead. - result = newSym(skUnknown, considerQuotedIdent(c, n), nextSymId(c.idgen), nil, n.info, + result = newSym(skUnknown, considerQuotedIdent(c, n), c.idgen, nil, n.info, c.config.options) else: result = qualifiedLookUp(c, n, {checkUndeclared}) @@ -787,7 +787,7 @@ proc semCustomPragma(c: PContext, n: PNode, sym: PSym): PNode = if r.isNil or sfCustomPragma notin r[0].sym.flags: invalidPragma(c, n) return n - + # we have a valid custom pragma if sym != nil and sym.kind in {skEnumField, skForVar, skModule}: illegalCustomPragma(c, n, sym) diff --git a/compiler/sem.nim b/compiler/sem.nim index 1c15f905e3..bac029fb98 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -9,6 +9,8 @@ # This module implements the semantic checking pass. +import tables + import ast, strutils, options, astalgo, trees, wordrecg, ropes, msgs, idents, renderer, types, platform, math, @@ -219,7 +221,7 @@ proc commonType*(c: PContext; x: PType, y: PNode): PType = commonType(c, x, y.typ) proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = - result = newSym(kind, considerQuotedIdent(c, n), nextSymId c.idgen, getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info) when defined(nimsuggest): suggestDecl(c, n, result) @@ -242,7 +244,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = # template; we must fix it here: see #909 result.owner = getCurrOwner(c) else: - result = newSym(kind, considerQuotedIdent(c, n), nextSymId c.idgen, getCurrOwner(c), n.info) + result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info) #if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule: # incl(result.flags, sfGlobal) when defined(nimsuggest): @@ -281,7 +283,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, proc symFromType(c: PContext; t: PType, info: TLineInfo): PSym = if t.sym != nil: return t.sym - result = newSym(skType, getIdent(c.cache, "AnonType"), nextSymId c.idgen, t.owner, info) + result = newSym(skType, getIdent(c.cache, "AnonType"), c.idgen, t.owner, info) result.flags.incl sfAnon result.typ = t diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 90d496c8ce..8235eba9c4 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -431,7 +431,7 @@ proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = incl typedesc.flags, tfCheckedForDestructor internalAssert(c.config, typ != nil) typedesc.addSonSkipIntLit(typ, c.idgen) - let sym = newSym(skType, c.cache.idAnon, nextSymId(c.idgen), getCurrOwner(c), info, + let sym = newSym(skType, c.cache.idAnon, c.idgen, getCurrOwner(c), info, c.config.options).linkTo(typedesc) result = newSymNode(sym, info) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 46d83c0e74..a55d74a240 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -846,7 +846,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) = # So we need to make sure we are checking them still when in a converter call if n[i].kind != nkHiddenAddr or isConverter: n[i] = analyseIfAddressTaken(c, n[i].skipAddr(), isOutParam(skipTypes(t[i], abstractInst-{tyTypeDesc}))) - + include semmagic proc evalAtCompileTime(c: PContext, n: PNode): PNode = @@ -1236,7 +1236,7 @@ proc readTypeParameter(c: PContext, typ: PType, # This seems semantically correct and then we'll be able # to return the section symbol directly here let foundType = makeTypeDesc(c, def[2].typ) - return newSymNode(copySym(def[0].sym, nextSymId c.idgen).linkTo(foundType), info) + return newSymNode(copySym(def[0].sym, c.idgen).linkTo(foundType), info) of nkConstSection: for def in statement: @@ -1261,7 +1261,7 @@ proc readTypeParameter(c: PContext, typ: PType, return c.graph.emptyNode else: let foundTyp = makeTypeDesc(c, rawTyp) - return newSymNode(copySym(tParam.sym, nextSymId c.idgen).linkTo(foundTyp), info) + return newSymNode(copySym(tParam.sym, c.idgen).linkTo(foundTyp), info) return nil @@ -2093,7 +2093,7 @@ proc expectString(c: PContext, n: PNode): string = localError(c.config, n.info, errStringLiteralExpected) proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym = - result = newSym(kind, c.cache.idAnon, nextSymId c.idgen, getCurrOwner(c), info) + result = newSym(kind, c.cache.idAnon, c.idgen, getCurrOwner(c), info) proc semExpandToAst(c: PContext, n: PNode): PNode = let macroCall = n[1] @@ -2865,7 +2865,7 @@ proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode) let paramPos = defExpr.sym.position + 1 if call[paramPos].kind != nkSym: - let hoistedVarSym = newSym(skLet, getIdent(c.graph.cache, genPrefix), nextSymId c.idgen, + let hoistedVarSym = newSym(skLet, getIdent(c.graph.cache, genPrefix), c.idgen, c.p.owner, letSection.info, c.p.owner.options) hoistedVarSym.typ = call[paramPos].typ diff --git a/compiler/semfields.nim b/compiler/semfields.nim index 36e3b57e74..5f3172f816 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -109,7 +109,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = var trueSymbol = systemModuleSym(c.graph, getIdent(c.cache, "true")) if trueSymbol == nil: localError(c.config, n.info, "system needs: 'true'") - trueSymbol = newSym(skUnknown, getIdent(c.cache, "true"), nextSymId c.idgen, getCurrOwner(c), n.info) + trueSymbol = newSym(skUnknown, getIdent(c.cache, "true"), c.idgen, getCurrOwner(c), n.info) trueSymbol.typ = getSysType(c.graph, n.info, tyBool) result[0] = newSymNode(trueSymbol, n.info) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 695f8a01d9..7241a47020 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -465,7 +465,7 @@ proc semGenericStmt(c: PContext, n: PNode, flags, ctx) if n[paramsPos].kind != nkEmpty: if n[paramsPos][0].kind != nkEmpty: - addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), nextSymId c.idgen, nil, n.info)) + addPrelimDecl(c, newSym(skUnknown, getIdent(c.cache, "result"), c.idgen, nil, n.info)) n[paramsPos] = semGenericStmt(c, n[paramsPos], flags, ctx) n[pragmasPos] = semGenericStmt(c, n[pragmasPos], flags, ctx) var body: PNode diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 25e5b267ef..3afbedec7f 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -45,7 +45,7 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym var q = a.sym if q.typ.kind in {tyTypeDesc, tyGenericParam, tyStatic, tyConcept}+tyTypeClasses: let symKind = if q.typ.kind == tyStatic: skConst else: skType - var s = newSym(symKind, q.name, nextSymId(c.idgen), getCurrOwner(c), q.info) + var s = newSym(symKind, q.name, c.idgen, getCurrOwner(c), q.info) s.flags.incl {sfUsed, sfFromGeneric} var t = PType(idTableGet(pt, q.typ)) if t == nil: @@ -100,7 +100,7 @@ proc freshGenSyms(c: PContext; n: PNode, owner, orig: PSym, symMap: var TIdTable n.sym = x elif s.owner == nil or s.owner.kind == skPackage: #echo "copied this ", s.name.s - x = copySym(s, nextSymId c.idgen) + x = copySym(s, c.idgen) x.owner = owner idTablePut(symMap, s, x) n.sym = x @@ -128,7 +128,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) = idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym) freshGenSyms(c, b, result, orig, symMap) - if sfBorrow notin orig.flags: + if sfBorrow notin orig.flags: # We do not want to generate a body for generic borrowed procs. # As body is a sym to the borrowed proc. let resultType = # todo probably refactor it into a function @@ -193,7 +193,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType, var param: PSym template paramSym(kind): untyped = - newSym(kind, genParam.sym.name, nextSymId c.idgen, genericTyp.sym, genParam.sym.info) + newSym(kind, genParam.sym.name, c.idgen, genericTyp.sym, genParam.sym.info) if genParam.kind == tyStatic: param = paramSym skConst @@ -263,7 +263,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable, internalAssert c.config, originalParams[i].kind == nkSym let oldParam = originalParams[i].sym - let param = copySym(oldParam, nextSymId c.idgen) + let param = copySym(oldParam, c.idgen) param.owner = prc param.typ = result[i] @@ -340,7 +340,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, c.matchedConcept = nil let oldScope = c.currentScope while not isTopLevel(c): c.currentScope = c.currentScope.parent - result = copySym(fn, nextSymId c.idgen) + result = copySym(fn, c.idgen) incl(result.flags, sfFromGeneric) result.owner = fn result.ast = n diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index e72b27d52c..6af7527701 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -420,14 +420,14 @@ proc turnFinalizerIntoDestructor(c: PContext; orig: PSym; info: TLineInfo): PSym #if n.kind == nkDerefExpr and sameType(n[0].typ, old): # result = - result = copySym(orig, nextSymId c.idgen) + result = copySym(orig, c.idgen) result.info = info result.flags.incl sfFromGeneric result.owner = orig let origParamType = orig.typ[1] let newParamType = makeVarType(result, origParamType.skipTypes(abstractPtrs), c.idgen) let oldParam = orig.typ.n[1].sym - let newParam = newSym(skParam, oldParam.name, nextSymId c.idgen, result, result.info) + let newParam = newSym(skParam, oldParam.name, c.idgen, result, result.info) newParam.typ = newParamType # proc body: result.ast = transform(c, orig.ast, origParamType, newParamType, oldParam, newParam) @@ -493,8 +493,8 @@ proc semNewFinalize(c: PContext; n: PNode): PNode = getAttachedOp(c.graph, t, attachedDestructor).owner == fin: discard "already turned this one into a finalizer" else: - let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), nextSymId c.idgen, fin.owner, fin.info) - let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, nextSymId c.idgen)) + let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), c.idgen, fin.owner, fin.info) + let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, c.idgen)) selfSymNode.typ = fin.typ[1] wrapperSym.flags.incl sfUsed diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index ced479dbe0..420a1f2d6a 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -486,7 +486,7 @@ proc liftParallel*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; n: PNode): P checkArgs(a, body) var varSection = newNodeI(nkVarSection, n.info) - var temp = newSym(skTemp, getIdent(g.cache, "barrier"), nextSymId idgen, owner, n.info) + var temp = newSym(skTemp, getIdent(g.cache, "barrier"), idgen, owner, n.info) temp.typ = magicsys.getCompilerProc(g, "Barrier").typ incl(temp.flags, sfFromGeneric) let tempNode = newSymNode(temp) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index f9d06f7a89..ce4febd3fb 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -233,7 +233,7 @@ proc markGcUnsafe(a: PEffects; reason: PNode) = if reason.kind == nkSym: a.owner.gcUnsafetyReason = reason.sym else: - a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name, nextSymId a.c.idgen, + a.owner.gcUnsafetyReason = newSym(skUnknown, a.owner.name, a.c.idgen, a.owner, reason.info, {}) proc markSideEffect(a: PEffects; reason: PNode | PSym; useLoc: TLineInfo) = @@ -246,7 +246,7 @@ proc markSideEffect(a: PEffects; reason: PNode | PSym; useLoc: TLineInfo) = sym = reason.sym else: let kind = if reason.kind == nkHiddenDeref: skParam else: skUnknown - sym = newSym(kind, a.owner.name, nextSymId a.c.idgen, a.owner, reason.info, {}) + sym = newSym(kind, a.owner.name, a.c.idgen, a.owner, reason.info, {}) else: sym = reason a.c.sideEffects.mgetOrPut(a.owner.id, @[]).add (useLoc, sym) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 20fb12d715..63b3382a8e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -460,7 +460,7 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) = let y = considerQuotedIdent(c, n[1]) let obj = x.typ.skipTypes(abstractPtrs) if obj.kind == tyObject and tfPartial in obj.flags: - let field = newSym(skField, getIdent(c.cache, y.s), nextSymId c.idgen, obj.sym, n[1].info) + let field = newSym(skField, getIdent(c.cache, y.s), c.idgen, obj.sym, n[1].info) field.typ = skipIntLit(typ, c.idgen) field.position = obj.n.len obj.n.add newSymNode(field) @@ -599,7 +599,7 @@ proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSy let useTemp = def.kind notin {nkPar, nkTupleConstr} or symkind == skConst if useTemp: # use same symkind for compatibility with original section - tmpTuple = newSym(symkind, getIdent(c.cache, "tmpTuple"), nextSymId c.idgen, getCurrOwner(c), n.info) + tmpTuple = newSym(symkind, getIdent(c.cache, "tmpTuple"), c.idgen, getCurrOwner(c), n.info) tmpTuple.typ = typ tmpTuple.flags.incl(sfGenSym) lastDef = newNodeI(defkind, a.info) @@ -1127,10 +1127,10 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil popCaseContext(c) closeScope(c) return handleCaseStmtMacro(c, n, flags) - template invalidOrderOfBranches(n: PNode) = + template invalidOrderOfBranches(n: PNode) = localError(c.config, n.info, "invalid order of case branches") break - + for i in 1.. 0: - accum.align(n.sym.alignment) + accum.align(n.sym.alignment.int32) n.sym.offset = accum.offset accum.inc(size) else: @@ -180,15 +180,15 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; packed: bo discard finish(branchAccum) accum.mergeBranch(branchAccum) of nkSym: - var size = szUnknownSize - var align = szUnknownSize + var size = szUnknownSize.int32 + var align = szUnknownSize.int32 if n.sym.bitsize == 0: # 0 represents bitsize not set computeSizeAlign(conf, n.sym.typ) - size = n.sym.typ.size.int - align = if packed: 1 else: n.sym.typ.align.int + size = n.sym.typ.size.int32 + align = if packed: 1 else: n.sym.typ.align.int32 accum.align(align) if n.sym.alignment > 0: - accum.align(n.sym.alignment) + accum.align(n.sym.alignment.int32) n.sym.offset = accum.offset accum.inc(size) else: @@ -339,7 +339,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = if typ.n != nil: # is named tuple (has field symbols)? let sym = typ.n[i].sym sym.offset = accum.offset - accum.inc(int(child.size)) + accum.inc(int32(child.size)) typ.paddingAtEnd = int16(accum.finish()) typ.size = if accum.offset == 0: 1 else: accum.offset typ.align = int16(accum.maxAlign) @@ -359,19 +359,19 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = computeSizeAlign(conf, st) if conf.backend == backendCpp: OffsetAccum( - offset: int(st.size) - int(st.paddingAtEnd), + offset: int32(st.size) - int32(st.paddingAtEnd), maxAlign: st.align ) else: OffsetAccum( - offset: int(st.size), + offset: int32(st.size), maxAlign: st.align ) elif isObjectWithTypeFieldPredicate(typ): # this branch is taken for RootObj OffsetAccum( - offset: conf.target.intSize, - maxAlign: conf.target.intSize + offset: conf.target.intSize.int32, + maxAlign: conf.target.intSize.int32 ) else: OffsetAccum(maxAlign: 1) diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 0931407d46..add36759da 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -55,7 +55,7 @@ proc typeNeedsNoDeepCopy(t: PType): bool = proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; idgen: IdGenerator; owner: PSym; typ: PType; v: PNode; useShallowCopy=false): PSym = - result = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId idgen, owner, varSection.info, + result = newSym(skTemp, getIdent(g.cache, genPrefix), idgen, owner, varSection.info, owner.options) result.typ = typ incl(result.flags, sfFromGeneric) @@ -219,7 +219,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; # localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure") let fieldname = if i < formals.len: formals[i].sym.name else: tmpName - var field = newSym(skField, fieldname, nextSymId idgen, objType.owner, n.info, g.config.options) + var field = newSym(skField, fieldname, idgen, objType.owner, n.info, g.config.options) field.typ = argType discard objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i]) @@ -250,7 +250,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; # localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure") let fieldname = if i < formals.len: formals[i].sym.name else: tmpName - var field = newSym(skField, fieldname, nextSymId idgen, objType.owner, n.info, g.config.options) + var field = newSym(skField, fieldname, idgen, objType.owner, n.info, g.config.options) if argType.kind in {tyVarargs, tyOpenArray}: # important special case: we always create a zero-copy slice: @@ -258,7 +258,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; slice.typ = n.typ slice[0] = newSymNode(createMagic(g, idgen, "slice", mSlice)) slice[0].typ = getSysType(g, n.info, tyInt) # fake type - var fieldB = newSym(skField, tmpName, nextSymId idgen, objType.owner, n.info, g.config.options) + var fieldB = newSym(skField, tmpName, idgen, objType.owner, n.info, g.config.options) fieldB.typ = getSysType(g, n.info, tyInt) discard objType.addField(fieldB, g.cache, idgen) @@ -268,7 +268,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; discard objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) - var fieldA = newSym(skField, tmpName, nextSymId idgen, objType.owner, n.info, g.config.options) + var fieldA = newSym(skField, tmpName, idgen, objType.owner, n.info, g.config.options) fieldA.typ = getSysType(g, n.info, tyInt) discard objType.addField(fieldA, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2]) @@ -343,9 +343,9 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp var fn = n[0] let name = (if fn.kind == nkSym: fn.sym.name.s else: genPrefix) & "Wrapper" - wrapperProc = newSym(skProc, getIdent(g.cache, name), nextSymId idgen, owner, fn.info, g.config.options) - threadParam = newSym(skParam, getIdent(g.cache, "thread"), nextSymId idgen, wrapperProc, n.info, g.config.options) - argsParam = newSym(skParam, getIdent(g.cache, "args"), nextSymId idgen, wrapperProc, n.info, g.config.options) + wrapperProc = newSym(skProc, getIdent(g.cache, name), idgen, owner, fn.info, g.config.options) + threadParam = newSym(skParam, getIdent(g.cache, "thread"), idgen, wrapperProc, n.info, g.config.options) + argsParam = newSym(skParam, getIdent(g.cache, "args"), idgen, wrapperProc, n.info, g.config.options) wrapperProc.flags.incl sfInjectDestructors block: @@ -358,7 +358,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp incl(objType.flags, tfFinal) let castExpr = createCastExpr(argsParam, objType, idgen) - var scratchObj = newSym(skVar, getIdent(g.cache, "scratch"), nextSymId idgen, owner, n.info, g.config.options) + var scratchObj = newSym(skVar, getIdent(g.cache, "scratch"), idgen, owner, n.info, g.config.options) block: scratchObj.typ = objType incl(scratchObj.flags, sfFromGeneric) @@ -375,7 +375,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp skFunc, skMethod, skConverter}): # for indirect calls we pass the function pointer in the scratchObj var argType = n[0].typ.skipTypes(abstractInst) - var field = newSym(skField, getIdent(g.cache, "fn"), nextSymId idgen, owner, n.info, g.config.options) + var field = newSym(skField, getIdent(g.cache, "fn"), idgen, owner, n.info, g.config.options) field.typ = argType discard objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0]) @@ -397,7 +397,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp if barrier != nil: let typ = newType(tyPtr, nextTypeId idgen, owner) typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ) - var field = newSym(skField, getIdent(g.cache, "barrier"), nextSymId idgen, owner, n.info, g.config.options) + var field = newSym(skField, getIdent(g.cache, "barrier"), idgen, owner, n.info, g.config.options) field.typ = typ discard objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier) @@ -405,7 +405,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp var fvField, fvAsExpr: PNode = nil if spawnKind == srFlowVar: - var field = newSym(skField, getIdent(g.cache, "fv"), nextSymId idgen, owner, n.info, g.config.options) + var field = newSym(skField, getIdent(g.cache, "fv"), idgen, owner, n.info, g.config.options) field.typ = retType discard objType.addField(field, g.cache, idgen) fvField = newDotExpr(scratchObj, field) @@ -416,7 +416,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField.info, fvField) elif spawnKind == srByVar: - var field = newSym(skField, getIdent(g.cache, "fv"), nextSymId idgen, owner, n.info, g.config.options) + var field = newSym(skField, getIdent(g.cache, "fv"), idgen, owner, n.info, g.config.options) field.typ = newType(tyPtr, nextTypeId idgen, objType.owner) field.typ.rawAddSon(retType) discard objType.addField(field, g.cache, idgen) diff --git a/compiler/transf.nim b/compiler/transf.nim index 752d031e14..0176a10871 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -91,7 +91,7 @@ proc getCurrOwner(c: PTransf): PSym = else: result = c.module proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode = - let r = newSym(skTemp, getIdent(c.graph.cache, genPrefix), nextSymId(c.idgen), getCurrOwner(c), info) + let r = newSym(skTemp, getIdent(c.graph.cache, genPrefix), c.idgen, getCurrOwner(c), info) r.typ = typ #skipTypes(typ, {tyGenericInst, tyAlias, tySink}) incl(r.flags, sfFromGeneric) let owner = getCurrOwner(c) @@ -177,7 +177,7 @@ proc freshVar(c: PTransf; v: PSym): PNode = if owner.isIterator and not c.tooEarly: result = freshVarForClosureIter(c.graph, v, c.idgen, owner) else: - var newVar = copySym(v, nextSymId(c.idgen)) + var newVar = copySym(v, c.idgen) incl(newVar.flags, sfFromGeneric) newVar.owner = owner result = newSymNode(newVar) @@ -249,8 +249,7 @@ proc hasContinue(n: PNode): bool = if hasContinue(n[i]): return true proc newLabel(c: PTransf, n: PNode): PSym = - result = newSym(skLabel, nil, nextSymId(c.idgen), getCurrOwner(c), n.info) - result.name = getIdent(c.graph.cache, genPrefix) + result = newSym(skLabel, getIdent(c.graph.cache, genPrefix), c.idgen, getCurrOwner(c), n.info) proc transformBlock(c: PTransf, n: PNode): PNode = var labl: PSym diff --git a/compiler/vm.nim b/compiler/vm.nim index e00f0f02e1..dbb02cffa8 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -2123,7 +2123,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = else: regs[rc].node.strVal if k < 0 or k > ord(high(TSymKind)): internalError(c.config, c.debug[pc], "request to create symbol of invalid kind") - var sym = newSym(k.TSymKind, getIdent(c.cache, name), nextSymId c.idgen, c.module.owner, c.debug[pc]) + var sym = newSym(k.TSymKind, getIdent(c.cache, name), c.idgen, c.module.owner, c.debug[pc]) incl(sym.flags, sfGenSym) regs[ra].node = newSymNode(sym) regs[ra].node.flags.incl nfIsRef diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 118a3031ed..75692fcc0e 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -29,7 +29,7 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): str proc atomicTypeX(cache: IdentCache; name: string; m: TMagic; t: PType; info: TLineInfo; idgen: IdGenerator): PNode = - let sym = newSym(skType, getIdent(cache, name), nextSymId(idgen), t.owner, info) + let sym = newSym(skType, getIdent(cache, name), idgen, t.owner, info) sym.magic = m sym.typ = t result = newSymNode(sym) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 5183f2def9..48792790d8 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -2044,7 +2044,7 @@ proc procIsCallback(c: PCtx; s: PSym): bool = if c.callbackIndex.contains(key): let index = c.callbackIndex[key] doAssert s.offset == -1 - s.offset = -2 - index + s.offset = -2'i32 - index.int32 result = true else: result = false @@ -2344,7 +2344,7 @@ proc genProc(c: PCtx; s: PSym): int = c.patch(procStart) c.gABC(body, opcEof, eofInstr.regA) c.optimizeJumps(result) - s.offset = c.prc.regInfo.len + s.offset = c.prc.regInfo.len.int32 #if s.name.s == "main" or s.name.s == "[]": # echo renderTree(body) # c.echoCode(result) diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index e44bc0bea3..b48197aefa 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -224,7 +224,7 @@ proc loadAny(p: var JsonParser, t: PType, if pos >= result.len: setLen(result.sons, pos + 1) let fieldNode = newNode(nkExprColonExpr) - fieldNode.add newSymNode(newSym(skField, ident, nextSymId(idgen), nil, unknownLineInfo)) + fieldNode.add newSymNode(newSym(skField, ident, idgen, nil, unknownLineInfo)) fieldNode.add loadAny(p, field.typ, tab, cache, conf, idgen) result[pos] = fieldNode if p.kind == jsonObjectEnd: next(p) diff --git a/tests/ccgbugs/tnoalias.nim b/tests/ccgbugs/tnoalias.nim index 96c3d390b5..2c3c2f0f40 100644 --- a/tests/ccgbugs/tnoalias.nim +++ b/tests/ccgbugs/tnoalias.nim @@ -1,5 +1,5 @@ discard """ - ccodecheck: "\\i@'NI* NIM_NOALIAS field;' @'NIM_CHAR* NIM_NOALIAS x__0qEngDE9aYoYsF8tWnyPacw,' @'void* NIM_NOALIAS q'" + ccodecheck: "\\i@'NI* NIM_NOALIAS field;' @'NIM_CHAR* NIM_NOALIAS x_p0,' @'void* NIM_NOALIAS q'" """ type From 0f226c0e4865eb27a534fcd8defc34576e222177 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 24 Apr 2023 20:57:48 +0800 Subject: [PATCH 019/489] fixes #21703; moveOrCopy should consider when vm (#21721) --- compiler/injectdestructors.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 6d5e070f27..ccb19720df 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -1054,7 +1054,8 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy else: result = newTree(nkFastAsgn, dest, p(ri, c, s, normal)) else: - case ri.kind + let ri2 = if ri.kind == nkWhen: ri[1][0] else: ri + case ri2.kind of nkCallKinds: result = c.genSink(s, dest, p(ri, c, s, consumed), flags) of nkBracketExpr: From 4754c51f1b7225d061b03688c93ff15d4b625ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Mon, 24 Apr 2023 16:44:29 +0100 Subject: [PATCH 020/489] Pragma to force the exportc of a type. #21645 (#21648) exportc export all types not just those used by exported proc/globals Co-authored-by: Andreas Rumpf --- compiler/ccgtypes.nim | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 65f938ca03..1a9a5a766a 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1612,11 +1612,20 @@ proc genTypeInfoV1(m: BModule; t: PType; info: TLineInfo): Rope = result = prefixTI.rope & result & ")".rope -proc genTypeSection(m: BModule; n: PNode) = - discard - proc genTypeInfo*(config: ConfigRef, m: BModule; t: PType; info: TLineInfo): Rope = if optTinyRtti in config.globalOptions: result = genTypeInfoV2(m, t, info) else: result = genTypeInfoV1(m, t, info) + +proc genTypeSection(m: BModule, n: PNode) = + var intSet = initIntSet() + for i in 0.. Date: Mon, 24 Apr 2023 17:09:07 +0100 Subject: [PATCH 021/489] documents #21628 (#21723) * documents #21628 * Update doc/manual.md --------- Co-authored-by: Andreas Rumpf --- doc/manual.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/doc/manual.md b/doc/manual.md index c381ab4100..31e69d0acc 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -6889,6 +6889,35 @@ iterator in which case the overloading resolution takes place: var x = 4 write(stdout, x) # not ambiguous: uses the module C's x ``` +Modules can share their name, however, when trying to qualify a identifier with the module name the compiler will fail with ambiguous identifier error. One can qualify the identifier by aliasing the module. + + +```nim +# Module A/C +proc fb* = echo "fizz" +``` + + +```nim +# Module B/C +proc fb* = echo "buzz" +``` + + +```nim +import A/C +import B/C + +C.fb() # Error: ambiguous identifier: 'fb' +``` + + +```nim +import A/C as fizz +import B/C + +fizz.fb() # Works +``` Packages From f0ae1ed54490bdce4f32cc7adf7ac3d85c706f3a Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Tue, 25 Apr 2023 12:29:17 +0100 Subject: [PATCH 022/489] Add benchmarking based on Minimize (#21566) * Add benchmarking based on Minimize * Update .github/workflows/ci_bench.yml Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --------- Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- .github/workflows/ci_bench.yml | 117 +++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 .github/workflows/ci_bench.yml diff --git a/.github/workflows/ci_bench.yml b/.github/workflows/ci_bench.yml new file mode 100644 index 0000000000..b044ab51f2 --- /dev/null +++ b/.github/workflows/ci_bench.yml @@ -0,0 +1,117 @@ +name: Benchmarks CI +on: + pull_request: + push: + branches: + - 'devel' + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: [ubuntu-20.04] + cpu: [amd64] + name: '${{ matrix.os }}' + runs-on: ${{ matrix.os }} + timeout-minutes: 60 # refs bug #18178 + steps: + - name: 'Checkout' + uses: actions/checkout@v3 + with: + fetch-depth: 2 + + - name: 'Install node.js 16.x' + uses: actions/setup-node@v3 + with: + node-version: '16.x' + + - name: 'Install dependencies (Linux amd64)' + if: runner.os == 'Linux' && matrix.cpu == 'amd64' + run: | + sudo apt-fast update -qq + DEBIAN_FRONTEND='noninteractive' \ + sudo apt-fast install --no-install-recommends -yq \ + libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \ + valgrind libc6-dbg libblas-dev xorg-dev + + - name: 'Add build binaries to PATH' + shell: bash + run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}" + + - name: 'Build csourcesAny' + shell: bash + run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}' + + - name: 'Build koch' + shell: bash + run: nim c koch + + - name: 'Build Nim' + shell: bash + run: ./koch boot -d:release -d:nimStrictMode --lib:lib + + - name: 'Build Nimble' + shell: bash + run: ./koch nimble + + - name: 'Action' + shell: bash + run: nim c -r -d:release ci/action.nim + + - name: 'Checkout minimize' + uses: actions/checkout@v3 + with: + repository: 'nim-lang/ci_bench' + path: minimize + + - name: 'Run minimize benchmarks' + shell: bash + run: ./minimize/minimize ci-bench + + - name: 'Restore minimize cached database' + id: minimize-cache + uses: actions/cache/restore@v3 + with: + path: minimize.sqlite + key: minimize-db-key + + - name: 'Update minimize db' + shell: bash + run: ./minimize/minimize update-db + + # - name: 'Save minimize cached database' + #if: | + # github.event_name == 'push' && github.ref == 'refs/heads/devel' && + # matrix.target == 'linux' + # id: minimize-cache + # uses: actions/cache/save@v3 + # with: + # path: minimize.sqlite + # key: minimize-db-key + + - name: 'Generate minimize report' + shell: bash + run: ./minimize/minimize generate-report + + - name: 'Archive minimize report' + uses: actions/upload-artifact@v3 + with: + name: minimize-report + path: | + minimize/minimize.html + minimize/minimize.csv + + # Requires additional permissions, see: + # https://github.com/nim-lang/Nim/actions/runs/4778177321/jobs/8494423792?pr=21566 + # - name: 'Publish HTML report' + # uses: rossjrw/pr-preview-action@v1 + # with: + # source-dir: minimize + # umbrella-dir: minimize + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract md summary + run: | + cat minimize/summary.md >> $GITHUB_STEP_SUMMARY From 0032322ea8e4f93f9fc6b7879b5e4bbb5f56c078 Mon Sep 17 00:00:00 2001 From: metagn Date: Wed, 26 Apr 2023 09:02:44 +0300 Subject: [PATCH 023/489] fix #21727 (#21729) --- compiler/semstmts.nim | 13 ++++++++----- compiler/semtempl.nim | 16 +++++++++------- tests/template/taliassyntax.nim | 11 +++++++++++ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 63b3382a8e..d493364eac 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2019,6 +2019,9 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, s.ast = n s.options = c.config.options #s.scope = c.currentScope + if s.kind in {skMacro, skTemplate}: + # push noalias flag at first to prevent unwanted recursive calls: + incl(s.flags, sfNoalias) # before compiling the proc params & body, set as current the scope # where the proc was declared @@ -2335,16 +2338,16 @@ proc semMacroDef(c: PContext, n: PNode): PNode = var s = result[namePos].sym var t = s.typ var allUntyped = true - var requiresParams = false + var nullary = true for i in 1.. Date: Wed, 26 Apr 2023 14:04:13 +0800 Subject: [PATCH 024/489] fixes #21731; fixes #21537; disable `warnBareExcept` by default [backport] (#21728) * disable warnBareExcept for default * fixes a typo --- changelogs/changelog_2_0_0.md | 2 +- compiler/lineinfos.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index bb0a9bf4d4..17f0fcfc4b 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -131,7 +131,7 @@ `foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`. This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead. -- If no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered. +- When `--warning[BareExcept]:on` is enabled, if no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered. - The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection. diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 44e9cb716c..7a51a4db7e 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -248,7 +248,7 @@ type TNoteKinds* = set[TNoteKind] proc computeNotesVerbosity(): array[0..3, TNoteKinds] = - result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv} + result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept} result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, From 8f79a124c96947283deecb137b7849557ae47f2f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 26 Apr 2023 16:00:43 +0800 Subject: [PATCH 025/489] fixes broken CI (#21732) * fixes broken CI * Update testament/important_packages.nim --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 08cafa0086..2fe012b26d 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -136,7 +136,7 @@ pkg "pylib" pkg "rbtree" pkg "react", "nimble example" pkg "regex", "nim c src/regex" -pkg "result", "nim c -r result.nim" +pkg "results", "nim c -r results.nim" pkg "RollingHash", "nim c -r tests/test_cyclichash.nim" pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim" pkg "sdl1", "nim c -r src/sdl.nim" From 220b45048983998675df761d4f33cd31128f10d5 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 26 Apr 2023 22:32:10 +0200 Subject: [PATCH 026/489] fixes #21245; warn about destructors that can raise (#21726) * fixes #21245; warn about destructors that can raise * doc update * progress * typo --- changelogs/changelog_2_0_0.md | 11 ++++++++--- compiler/sempass2.nim | 3 ++- compiler/semstmts.nim | 5 +++++ doc/destructors.md | 14 +++++++++++--- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 17f0fcfc4b..8a50197316 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -179,7 +179,7 @@ for 64-bit integer types (`int64` and `uint64`) by default. As this affects JS code generation, code using these types to interface with the JS backend may need to be updated. Note that `int` and `uint` are not affected. - + For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint) and in the case of potential bugs with the new implementation, the old behavior is currently still supported with the command line option @@ -195,7 +195,7 @@ iterator iter(): int = yield 123 - + proc takesProc[T: proc](x: T) = discard proc takesIter[T: iterator](x: T) = discard @@ -221,10 +221,15 @@ - Signed integer literals in `set` literals now default to a range type of `0..255` instead of `0..65535` (the maximum size of sets). - + - Case statements with else branches put before elif/of branches in macros are rejected with "invalid order of case branches". +- Destructors now default to `.raises: []` (i.e. destructors must not raise + unlisted exceptions) and explicitly raising destructors are implementation + defined behavior. + + ## Standard library additions and changes [//]: # "Changes:" diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index ce4febd3fb..f0e55887cf 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1499,7 +1499,8 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = let p = s.ast[pragmasPos] let raisesSpec = effectSpec(p, wRaises) if not isNil(raisesSpec): - checkRaisesSpec(g, false, raisesSpec, t.exc, "can raise an unlisted exception: ", + let useWarning = s.name.s == "=destroy" + checkRaisesSpec(g, useWarning, raisesSpec, t.exc, "can raise an unlisted exception: ", hints=on, subtypeRelation, hintsArg=s.ast[0]) # after the check, use the formal spec: effects[exceptionEffects] = raisesSpec diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d493364eac..43d22bc551 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1857,6 +1857,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = case name of "=destroy": bindTypeHook(c, s, n, attachedDestructor) + if s.ast != nil: + if s.ast[pragmasPos].kind == nkEmpty: + s.ast[pragmasPos] = newNodeI(nkPragma, s.info) + s.ast[pragmasPos].add newTree(nkExprColonExpr, + newIdentNode(c.cache.getIdent("raises"), s.info), newNodeI(nkBracket, s.info)) of "deepcopy", "=deepcopy": if s.typ.len == 2 and s.typ[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and diff --git a/doc/destructors.md b/doc/destructors.md index a96ac35ef3..a37eade330 100644 --- a/doc/destructors.md +++ b/doc/destructors.md @@ -13,12 +13,12 @@ Nim Destructors and Move Semantics About this document =================== -This document describes the upcoming Nim runtime which does +This document describes the ARC/ORC Nim runtime which does not use classical GC algorithms anymore but is based on destructors and -move semantics. The new runtime's advantages are that Nim programs become +move semantics. The advantages are that Nim programs become oblivious to the involved heap sizes and programs are easier to write to make effective use of multi-core machines. As a nice bonus, files and sockets and -the like will not require manual `close` calls anymore. +the like can be written not to require manual `close` calls anymore. This document aims to be a precise specification about how move semantics and destructors work in Nim. @@ -132,6 +132,14 @@ The general pattern in `=destroy` looks like: freeResource(x.field) ``` +A `=destroy` is implicitly annotated with `.raises: []`; a destructor +should not raise exceptions. For backwards compatibility the compiler +produces a warning for a `=destroy` that does raise. + +A `=destroy` can explicitly list the exceptions it can raise, if any, +but this of little utility as a raising destructor is implementation defined +behavior. Later versions of the language specification might cover this case precisely. + `=sink` hook ------------ From 560fa9a1fe3c098e00ca6486b425951a3a8cd568 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 28 Apr 2023 16:25:31 +0800 Subject: [PATCH 027/489] handle quoted routine symbols and non symbols expressions as before (#21740) --- compiler/semexprs.nim | 5 +++-- tests/stdlib/tmacros.nim | 11 +++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a55d74a240..930fd35163 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2224,8 +2224,9 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "untyped").newSymNode # return type dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[0], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode) for i in 1.. Date: Fri, 28 Apr 2023 10:30:16 +0200 Subject: [PATCH 028/489] improve C/C++ debug output readability (1/N) (#21690) * hacky attempt to reconcile default explicit constructors with enforcement of brace initialization, instead of memsetting imported objects to 0 * improve C/C++ debug output readability (1/N) --- compiler/ccgexprs.nim | 80 +++++++++++++++++------------------ compiler/ccgstmts.nim | 75 +++++++++++++++++---------------- compiler/ccgtypes.nim | 36 ++++++++-------- compiler/cgen.nim | 97 +++++++++++++++++++++++++++---------------- 4 files changed, 159 insertions(+), 129 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 5a8e2d296e..1767edb8c9 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -199,12 +199,12 @@ proc canMove(p: BProc, n: PNode; dest: TLoc): bool = proc genRefAssign(p: BProc, dest, src: TLoc) = if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config): - linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) elif dest.storage == OnHeap: - linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n", + linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);\n", [addrLoc(p.config, dest), rdLoc(src)]) else: - linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", + linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);\n", [addrLoc(p.config, dest), rdLoc(src)]) proc asgnComplexity(n: PNode): int = @@ -270,19 +270,19 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # (for objects, etc.): if optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, - "$1 = $2;$n", + "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) elif needToCopy notin flags or tfShallow in skipTypes(dest.t, abstractVarRange).flags: if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config): linefmt(p, cpsStmts, - "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", + "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));\n", [addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)]) else: - linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n", + linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);\n", [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) else: - linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", + linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);\n", [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) = @@ -318,7 +318,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # the assignment operation in C. if src.t != nil and src.t.kind == tyPtr: # little HACK to support the new 'var T' as return type: - linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) return let ty = skipTypes(dest.t, abstractRange + tyUserTypeClasses + {tyStatic}) case ty.kind @@ -330,7 +330,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = elif (needToCopy notin flags and src.storage != OnStatic) or canMove(p, src.lode, dest): genRefAssign(p, dest, src) else: - linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", + linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);\n", [addrLoc(p.config, dest), rdLoc(src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tyString: @@ -340,16 +340,16 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = genRefAssign(p, dest, src) else: if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config): - linefmt(p, cpsStmts, "$1 = #copyString($2);$n", [dest.rdLoc, src.rdLoc]) + linefmt(p, cpsStmts, "$1 = #copyString($2);\n", [dest.rdLoc, src.rdLoc]) elif dest.storage == OnHeap: # we use a temporary to care for the dreaded self assignment: var tmp: TLoc getTemp(p, ty, tmp) - linefmt(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);$n", + linefmt(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);\n", [dest.rdLoc, src.rdLoc, tmp.rdLoc]) - linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", [tmp.rdLoc]) + linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);\n", [tmp.rdLoc]) else: - linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n", + linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));\n", [addrLoc(p.config, dest), rdLoc(src)]) of tyProc: if containsGarbageCollectedRef(dest.t): @@ -357,19 +357,19 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = let a = optAsgnLoc(dest, dest.t, "ClE_0".rope) let b = optAsgnLoc(src, dest.t, "ClE_0".rope) genRefAssign(p, a, b) - linefmt(p, cpsStmts, "$1.ClP_0 = $2.ClP_0;$n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1.ClP_0 = $2.ClP_0;\n", [rdLoc(dest), rdLoc(src)]) else: - linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) of tyTuple: if containsGarbageCollectedRef(dest.t): if dest.t.len <= 4: genOptAsgnTuple(p, dest, src, flags) else: genGenericAsgn(p, dest, src, flags) else: - linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) of tyObject: # XXX: check for subtyping? if ty.isImportedCppType: - linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) elif not isObjLackingTypeField(ty): genGenericAsgn(p, dest, src, flags) elif containsGarbageCollectedRef(ty): @@ -380,13 +380,13 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: genGenericAsgn(p, dest, src, flags) else: - linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) of tyArray: if containsGarbageCollectedRef(dest.t) and p.config.selectedGC notin {gcArc, gcOrc, gcHooks}: genGenericAsgn(p, dest, src, flags) else: linefmt(p, cpsStmts, - "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", + "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));\n", [rdLoc(dest), rdLoc(src), getTypeDesc(p.module, dest.t)]) of tyOpenArray, tyVarargs: # open arrays are always on the stack - really? What if a sequence is @@ -395,30 +395,30 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = genOpenArrayConv(p, dest, src) elif containsGarbageCollectedRef(dest.t): linefmt(p, cpsStmts, # XXX: is this correct for arrays? - "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", + "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);\n", [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) else: linefmt(p, cpsStmts, # bug #4799, keep the nimCopyMem for a while - #"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);$n", - "$1 = $2;$n", + #"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);\n", + "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) of tySet: if mapSetType(p.config, ty) == ctArray: - linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", + linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);\n", [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: - linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCstring, tyInt..tyUInt64, tyRange, tyVar, tyLent, tyNil: - linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genAssignment: " & $ty.kind) if optMemTracker in p.options and dest.storage in {OnHeap, OnUnknown}: #writeStackTrace() #echo p.currLineInfo, " requesting" - linefmt(p, cpsStmts, "#memTrackerWrite((void*)$1, $2, $3, $4);$n", + linefmt(p, cpsStmts, "#memTrackerWrite((void*)$1, $2, $3, $4);\n", [addrLoc(p.config, dest), getSize(p.config, dest.t), makeCString(toFullPath(p.config, p.currLineInfo)), p.currLineInfo.safeLineNm]) @@ -437,32 +437,32 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = case ty.kind of tyPtr, tyRef, tyProc, tyTuple, tyObject, tyArray: # XXX optimize this - linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", + linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);\n", [addrLoc(p.config, dest), addrLocOrTemp(src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tySequence, tyString: if optTinyRtti in p.config.globalOptions: - linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", + linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);\n", [addrLoc(p.config, dest), addrLocOrTemp(src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) else: - linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n", + linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);\n", [addrLoc(p.config, dest), rdLoc(src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tyOpenArray, tyVarargs: linefmt(p, cpsStmts, - "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", + "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);\n", [addrLoc(p.config, dest), addrLocOrTemp(src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tySet: if mapSetType(p.config, ty) == ctArray: - linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", + linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);\n", [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: - linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) of tyPointer, tyChar, tyBool, tyEnum, tyCstring, tyInt..tyUInt64, tyRange, tyVar, tyLent: - linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genDeepCopy: " & $ty.kind) proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) = @@ -507,14 +507,14 @@ proc binaryStmt(p: BProc, e: PNode, d: var TLoc, op: string) = if d.k != locNone: internalError(p.config, e.info, "binaryStmt") initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) - lineCg(p, cpsStmts, "$1 $2 $3;$n", [rdLoc(a), op, rdLoc(b)]) + lineCg(p, cpsStmts, "$1 $2 $3;\n", [rdLoc(a), op, rdLoc(b)]) proc binaryStmtAddr(p: BProc, e: PNode, d: var TLoc, cpname: string) = var a, b: TLoc if d.k != locNone: internalError(p.config, e.info, "binaryStmtAddr") initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) - lineCg(p, cpsStmts, "#$1($2, $3);$n", [cpname, byRefLoc(p, a), rdLoc(b)]) + lineCg(p, cpsStmts, "#$1($2, $3);\n", [cpname, byRefLoc(p, a), rdLoc(b)]) template unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = var a: TLoc @@ -1193,9 +1193,9 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = expr(p, e[1], tmp) L = getLabel(p) if m == mOr: - lineF(p, cpsStmts, "if ($1) goto $2;$n", [rdLoc(tmp), L]) + lineF(p, cpsStmts, "if ($1) goto $2;\n", [rdLoc(tmp), L]) else: - lineF(p, cpsStmts, "if (!($1)) goto $2;$n", [rdLoc(tmp), L]) + lineF(p, cpsStmts, "if (!($1)) goto $2;\n", [rdLoc(tmp), L]) expr(p, e[2], tmp) fixLabel(p, L) if d.k == locNone: @@ -1276,15 +1276,15 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e[i + 1], a) if skipTypes(e[i + 1].typ, abstractVarRange).kind == tyChar: inc(L) - appends.add(ropecg(p.module, "#appendChar($1, $2);$n", [strLoc(p, tmp), rdLoc(a)])) + appends.add(ropecg(p.module, "#appendChar($1, $2);\n", [strLoc(p, tmp), rdLoc(a)])) else: if e[i + 1].kind in {nkStrLit..nkTripleStrLit}: inc(L, e[i + 1].strVal.len) else: lens.add(lenExpr(p, a)) lens.add(" + ") - appends.add(ropecg(p.module, "#appendString($1, $2);$n", [strLoc(p, tmp), rdLoc(a)])) - linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, L]) + appends.add(ropecg(p.module, "#appendString($1, $2);\n", [strLoc(p, tmp), rdLoc(a)])) + linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);\n", [tmp.r, lens, L]) p.s(cpsStmts).add appends if d.k == locNone: d = tmp diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 63fb17527e..22428a749f 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -61,7 +61,7 @@ proc startBlockInternal(p: BProc): int {.discardable.} = p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16 p.blocks[result].nestedExceptStmts = p.inExceptBlockLen.int16 -template startBlock(p: BProc, start: FormatStr = "{$n", +template startBlock(p: BProc, start: FormatStr = "{\n", args: varargs[Rope]): int = lineCg(p, cpsStmts, start, args) startBlockInternal(p) @@ -173,7 +173,8 @@ proc endBlock(p: BProc) = if p.blocks[topBlock].label.len != 0: blockEnd.addf("} $1: ;$n", [p.blocks[topBlock].label]) else: - blockEnd.addf("}$n", []) + #blockEnd.addf("}$n", []) + blockEnd.add("}\n") endBlock(p, blockEnd) proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} = @@ -346,12 +347,12 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = assert(typ.len == typ.n.len) genOtherArg(p, value, i, typ, params, argsCounter) if params.len == 0: - lineF(p, cpsStmts, "$#;$n", [decl]) + lineF(p, cpsStmts, "$#;\n", [decl]) else: - lineF(p, cpsStmts, "$#($#);$n", [decl, params]) + lineF(p, cpsStmts, "$#($#);\n", [decl, params]) else: initLocExprSingleUse(p, value, tmp) - lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc]) + lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc]) return assignLocalVar(p, vn) initLocalVar(p, v, imm) @@ -446,9 +447,9 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = [rdLoc(a), lelse]) if p.module.compileToCpp: # avoid "jump to label crosses initialization" error: - p.s(cpsStmts).add "{" + p.s(cpsStmts).add "{\n" expr(p, it[1], d) - p.s(cpsStmts).add "}" + p.s(cpsStmts).add "}\n" else: expr(p, it[1], d) endBlock(p) @@ -607,13 +608,13 @@ proc genWhileStmt(p: BProc, t: PNode) = loopBody = loopBody[1] genComputedGoto(p, loopBody) else: - p.breakIdx = startBlock(p, "while (1) {$n") + p.breakIdx = startBlock(p, "while (1) {\n") p.blocks[p.breakIdx].isLoop = true initLocExpr(p, t[0], a) if (t[0].kind != nkIntLit) or (t[0].intVal == 0): lineF(p, cpsStmts, "if (!$1) goto ", [rdLoc(a)]) assignLabel(p.blocks[p.breakIdx], p.s(cpsStmts)) - appcg(p, cpsStmts, ";$n", []) + appcg(p, cpsStmts, ";\n", []) genStmts(p, loopBody) if optProfiler in p.options: @@ -977,8 +978,8 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) = of tyCstring: genStringCase(p, t, tyCstring, d) of tyFloat..tyFloat128: - genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n", - "if ($1 == $2) goto $3;$n") + genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;\n", + "if ($1 == $2) goto $3;\n") else: if t[0].kind == nkSym and sfGoto in t[0].sym.flags: genGotoForCase(p, t) @@ -989,9 +990,9 @@ proc genRestoreFrameAfterException(p: BProc) = if optStackTrace in p.module.config.options: if hasCurFramePointer notin p.flags: p.flags.incl hasCurFramePointer - p.procSec(cpsLocals).add(ropecg(p.module, "\tTFrame* _nimCurFrame;$n", [])) - p.procSec(cpsInit).add(ropecg(p.module, "\t_nimCurFrame = #getFrame();$n", [])) - linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n", []) + p.procSec(cpsLocals).add(ropecg(p.module, "\tTFrame* _nimCurFrame;\n", [])) + p.procSec(cpsInit).add(ropecg(p.module, "\t_nimCurFrame = #getFrame();\n", [])) + linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);\n", []) proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = #[ code to generate: @@ -1027,25 +1028,26 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = inc(p.labels, 2) let etmp = p.labels - p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;", [etmp])) + p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;\n", [etmp])) let fin = if t[^1].kind == nkFinally: t[^1] else: nil p.nestedTryStmts.add((fin, false, 0.Natural)) if t.kind == nkHiddenTryStmt: - lineCg(p, cpsStmts, "try {$n", []) + lineCg(p, cpsStmts, "try {\n", []) expr(p, t[0], d) - lineCg(p, cpsStmts, "}$n", []) + lineCg(p, cpsStmts, "}\n", []) else: - startBlock(p, "try {$n") + startBlock(p, "try {\n") expr(p, t[0], d) endBlock(p) - # First pass: handle Nim based exceptions: - lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1]) + # First pass: handle Nim based exceptions: + #lineCg(p, cpsStmts, "catch (#Exception* T$1_) {\n", [etmp+1]) + startBlock(p, "catch (#Exception* T$1_) {\n", rope(etmp+1)) genRestoreFrameAfterException(p) # an unhandled exception happened! - lineCg(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) + lineCg(p, cpsStmts, "T$1_ = std::current_exception();\n", [etmp]) p.nestedTryStmts[^1].inExcept = true var hasImportedCppExceptions = false var i = 1 @@ -1061,9 +1063,9 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = if hasIf: lineF(p, cpsStmts, "else ", []) startBlock(p) # we handled the error: - linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp]) + linefmt(p, cpsStmts, "T$1_ = nullptr;\n", [etmp]) expr(p, t[i][0], d) - linefmt(p, cpsStmts, "#popCurrentException();$n", []) + linefmt(p, cpsStmts, "#popCurrentException();\n", []) endBlock(p) else: var orExpr = newRopeAppender() @@ -1088,24 +1090,25 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = if orExpr.len != 0: if hasIf: - startBlock(p, "else if ($1) {$n", [orExpr]) + startBlock(p, "else if ($1) {\n", [orExpr]) else: - startBlock(p, "if ($1) {$n", [orExpr]) + startBlock(p, "if ($1) {\n", [orExpr]) hasIf = true if exvar != nil: fillLocalName(p, exvar.sym) fillLoc(exvar.sym.loc, locTemp, exvar, OnStack) - linefmt(p, cpsStmts, "$1 $2 = T$3_;$n", [getTypeDesc(p.module, exvar.sym.typ), + linefmt(p, cpsStmts, "$1 $2 = T$3_;\n", [getTypeDesc(p.module, exvar.sym.typ), rdLoc(exvar.sym.loc), rope(etmp+1)]) # we handled the error: - linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp]) + linefmt(p, cpsStmts, "T$1_ = nullptr;\n", [etmp]) expr(p, t[i][^1], d) - linefmt(p, cpsStmts, "#popCurrentException();$n", []) + linefmt(p, cpsStmts, "#popCurrentException();\n", []) endBlock(p) inc(i) if hasIf and not hasElse: - linefmt(p, cpsStmts, "else throw;$n", [etmp]) - linefmt(p, cpsStmts, "}$n", []) + linefmt(p, cpsStmts, "else throw;\n", [etmp]) + #linefmt(p, cpsStmts, "}\n", []) + endBlock(p) # Second pass: handle C++ based exceptions: template genExceptBranchBody(body: PNode) {.dirty.} = @@ -1124,7 +1127,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = if t[i].len == 1: # general except section: - startBlock(p, "catch (...) {", []) + startBlock(p, "catch (...) {\n", []) genExceptBranchBody(t[i][0]) endBlock(p) catchAllPresent = true @@ -1137,11 +1140,11 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:` fillLocalName(p, exvar.sym) fillLoc(exvar.sym.loc, locTemp, exvar, OnStack) - startBlock(p, "catch ($1& $2) {$n", getTypeDesc(p.module, typeNode.typ), rdLoc(exvar.sym.loc)) + startBlock(p, "catch ($1& $2) {\n", getTypeDesc(p.module, typeNode.typ), rdLoc(exvar.sym.loc)) genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type endBlock(p) elif isImportedException(typeNode.typ, p.config): - startBlock(p, "catch ($1&) {$n", getTypeDesc(p.module, t[i][j].typ)) + startBlock(p, "catch ($1&) {\n", getTypeDesc(p.module, t[i][j].typ)) genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type endBlock(p) @@ -1150,14 +1153,14 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = # general finally block: if t.len > 0 and t[^1].kind == nkFinally: if not catchAllPresent: - startBlock(p, "catch (...) {", []) + startBlock(p, "catch (...) {\n", []) genRestoreFrameAfterException(p) - linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) + linefmt(p, cpsStmts, "T$1_ = std::current_exception();\n", [etmp]) endBlock(p) startBlock(p) genStmts(p, t[^1][0]) - linefmt(p, cpsStmts, "if (T$1_) std::rethrow_exception(T$1_);$n", [etmp]) + linefmt(p, cpsStmts, "if (T$1_) std::rethrow_exception(T$1_);\n", [etmp]) endBlock(p) proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 1a9a5a766a..9757f6aa9f 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -524,14 +524,14 @@ proc genRecordFieldsAux(m: BModule; n: PNode, else: unionBody.addf("#pragma pack(push, 1)$nstruct{", []) unionBody.add(a) - unionBody.addf("} $1;$n", [structName]) + unionBody.addf("} $1;\n", [structName]) if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props: - unionBody.addf("#pragma pack(pop)$n", []) + unionBody.addf("#pragma pack(pop)\n", []) else: genRecordFieldsAux(m, k, rectype, check, unionBody, unionPrefix) else: internalError(m.config, "genRecordFieldsAux(record case branch)") if unionBody != "": - result.addf("union{$n$1};$n", [unionBody]) + result.addf("union{\n$1};\n", [unionBody]) of nkSym: let field = n.sym if field.typ.kind == tyVoid: return @@ -548,20 +548,20 @@ proc genRecordFieldsAux(m: BModule; n: PNode, let fieldType = field.loc.lode.typ.skipTypes(abstractInst) if fieldType.kind == tyUncheckedArray: - result.addf("$1 $2[SEQ_DECL_SIZE];$n", + result.addf("\t$1 $2[SEQ_DECL_SIZE];\n", [getTypeDescAux(m, fieldType.elemType, check, skField), sname]) elif fieldType.kind == tySequence: # we need to use a weak dependency here for trecursive_table. - result.addf("$1$3 $2;$n", [getTypeDescWeak(m, field.loc.t, check, skField), sname, noAlias]) + result.addf("\t$1$3 $2;\n", [getTypeDescWeak(m, field.loc.t, check, skField), sname, noAlias]) elif field.bitsize != 0: - result.addf("$1$4 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, rope($field.bitsize), noAlias]) + result.addf("\t$1$4 $2:$3;\n", [getTypeDescAux(m, field.loc.t, check, skField), sname, rope($field.bitsize), noAlias]) else: # don't use fieldType here because we need the # tyGenericInst for C++ template support if fieldType.isOrHasImportedCppType(): - result.addf("$1$3 $2{};$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) + result.addf("\t$1$3 $2{};\n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) else: - result.addf("$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) + result.addf("\t$1$3 $2;\n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) else: internalError(m.config, n.info, "genRecordFieldsAux()") proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope = @@ -595,36 +595,36 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope, if typ.kind == tyObject: if typ[0] == nil: if lacksMTypeField(typ): - appcg(m, result, " {$n", []) + appcg(m, result, " {\n", []) else: if optTinyRtti in m.config.globalOptions: - appcg(m, result, " {$n#TNimTypeV2* m_type;$n", []) + appcg(m, result, " {$n#TNimTypeV2* m_type;\n", []) else: - appcg(m, result, " {$n#TNimType* m_type;$n", []) + appcg(m, result, " {$n#TNimType* m_type;\n", []) hasField = true elif m.compileToCpp: - appcg(m, result, " : public $1 {$n", + appcg(m, result, " : public $1 {\n", [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)]) if typ.isException and m.config.exc == excCpp: when false: - appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions + appcg(m, result, "virtual void raise() { throw *this; }\n", []) # required for polymorphic exceptions if typ.sym.magic == mException: # Add cleanup destructor to Exception base class - appcg(m, result, "~$1();$n", [name]) + appcg(m, result, "~$1();\n", [name]) # define it out of the class body and into the procs section so we don't have to # artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR) - appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name]) + appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}\n", [name]) hasField = true else: - appcg(m, result, " {$n $1 Sup;$n", + appcg(m, result, " {$n $1 Sup;\n", [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)]) hasField = true else: - result.addf(" {$n", [name]) + result.addf(" {\n", [name]) let desc = getRecordFields(m, typ, check) if desc == "" and not hasField: - result.addf("char dummy;$n", []) + result.addf("char dummy;\n", []) else: result.add(desc) result.add("};\L") diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 960805e8d7..db2f280f1a 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -273,7 +273,16 @@ proc safeLineNm(info: TLineInfo): int = proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) = assert line >= 0 if optLineDir in conf.options and line > 0: - r.addf("$N#line $2 $1$N", + r.addf("\n#line $2 $1\n", + [rope(makeSingleLineCString(filename)), rope(line)]) + +proc genCLineDir(r: var Rope, filename: string, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex; lastLine: uint16) = + assert line >= 0 + if optLineDir in p.config.options and line > 0: + if lastFileIndex == info.fileIndex: + r.addf("\n#line $1\n", [rope(line)]) + else: + r.addf("\n#line $2 $1\n", [rope(makeSingleLineCString(filename)), rope(line)]) proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) = @@ -292,11 +301,18 @@ proc genLineDir(p: BProc, t: PNode) = if optEmbedOrigSrc in p.config.globalOptions: p.s(cpsStmts).add("//" & sourceLine(p.config, t.info) & "\L") - genCLineDir(p.s(cpsStmts), t.info, p.config) if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx: - if freshLineInfo(p, t.info): - linefmt(p, cpsStmts, "nimln_($1, $2);$n", + let lastFileIndex = p.lastLineInfo.fileIndex + let lastLine = p.lastLineInfo.line + let freshLine = freshLineInfo(p, t.info) + if freshLine: + genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p, t.info, lastFileIndex, lastLine) + if lastFileIndex == t.info.fileIndex: + linefmt(p, cpsStmts, "nimln_($1);\n", + [line]) + else: + linefmt(p, cpsStmts, "nimlf_($1, $2);\n", [line, quotedFilename(p.config, t.info)]) proc accessThreadLocalVar(p: BProc, s: PSym) @@ -457,9 +473,9 @@ proc resetLoc(p: BProc, loc: var TLoc) = let atyp = skipTypes(loc.t, abstractInst) if atyp.kind in {tyVar, tyLent}: - linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)]) + linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;\n", [rdLoc(loc)]) else: - linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) + linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;\n", [rdLoc(loc)]) elif not isComplexValueType(typ): if containsGcRef: var nilLoc: TLoc @@ -472,7 +488,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = if loc.storage != OnStack and containsGcRef: specializeReset(p, loc) when false: - linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", + linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);\n", [addrLoc(p.config, loc), genTypeInfoV1(p.module, loc.t, loc.lode.info)]) # XXX: generated reset procs should not touch the m_type # field, so disabling this should be safe: @@ -480,7 +496,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = else: # array passed as argument decayed into pointer, bug #7332 # so we use getTypeDesc here rather than rdLoc(loc) - linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", + linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));\n", [addrLoc(p.config, loc), getTypeDesc(p.module, loc.t, mapTypeChooser(loc))]) # XXX: We can be extra clever here and call memset only @@ -490,7 +506,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = let typ = loc.t if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}: - linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) + linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;\n", [rdLoc(loc)]) elif not isComplexValueType(typ): if containsGarbageCollectedRef(loc.t): var nilLoc: TLoc @@ -498,14 +514,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = nilLoc.r = rope("NIM_NIL") genRefAssign(p, loc, nilLoc) else: - linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc), + linefmt(p, cpsStmts, "$1 = ($2)0;\n", [rdLoc(loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))]) else: if not isTemp or containsGarbageCollectedRef(loc.t): # don't use nimZeroMem for temporary values for performance if we can # avoid it: if not isOrHasImportedCppType(typ): - linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", + linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));\n", [addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))]) genObjectInit(p, cpsStmts, loc.t, loc, constructObj) @@ -525,9 +541,9 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = inc(p.labels) result.r = "T" & rope(p.labels) & "_" if p.module.compileToCpp and isOrHasImportedCppType(t): - linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, skVar), result.r]) + linefmt(p, cpsLocals, "$1 $2{};\n", [getTypeDesc(p.module, t, skVar), result.r]) else: - linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r]) + linefmt(p, cpsLocals, "$1 $2;\n", [getTypeDesc(p.module, t, skVar), result.r]) result.k = locTemp result.lode = lodeTyp t result.storage = OnStack @@ -545,7 +561,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) = inc(p.labels) result.r = "T" & rope(p.labels) & "_" - linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value]) + linefmt(p, cpsStmts, "$1 $2 = $3;\n", [getTypeDesc(p.module, t, skVar), result.r, value]) result.k = locTemp result.lode = lodeTyp t result.storage = OnStack @@ -554,7 +570,7 @@ proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) = proc getIntTemp(p: BProc, result: var TLoc) = inc(p.labels) result.r = "T" & rope(p.labels) & "_" - linefmt(p, cpsLocals, "NI $1;$n", [result.r]) + linefmt(p, cpsLocals, "NI $1;\n", [result.r]) result.k = locTemp result.storage = OnStack result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt) @@ -569,7 +585,13 @@ proc localVarDecl(p: BProc; n: PNode): Rope = if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: result.addf("NIM_ALIGN($1) ", [rope(s.alignment)]) - genCLineDir(result, n.info, p.config) + if optLineDir in p.config.options: + let line = n.info.safeLineNm + let lastFileIndex = p.lastLineInfo.fileIndex + let lastLine = p.lastLineInfo.line + discard freshLineInfo(p, n.info) + genCLineDir(result, toFullPath(p.config, n.info), line, p, n.info, lastFileIndex, lastLine) + addIndent(p, result) result.add getTypeDesc(p.module, s.typ, skVar) if s.constraint.isNil: @@ -587,8 +609,8 @@ proc assignLocalVar(p: BProc, n: PNode) = #assert(s.loc.k == locNone) # not yet assigned # this need not be fulfilled for inline procs; they are regenerated # for each module that uses them! - let nl = if optLineDir in p.config.options: "" else: "\L" - let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl + #let nl = if optLineDir in p.config.options: "" else: "\n" + let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};\n" else: ";\n") line(p, cpsLocals, decl) include ccgthreadvars @@ -685,7 +707,8 @@ proc getLabel(p: BProc): TLabel = result = "LA" & rope(p.labels) & "_" proc fixLabel(p: BProc, labl: TLabel) = - lineF(p, cpsStmts, "$1: ;$n", [labl]) + #lineF(p, cpsStmts, "$1: ;$n", [labl]) + p.s(cpsStmts).add("$1: ;$n" % [labl]) proc genVarPrototype(m: BModule, n: PNode) proc requestConstImpl(p: BProc, sym: PSym) @@ -727,14 +750,18 @@ $1define nimfr_(proc, file) \ struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename;NI len;VarSlot s[slots];} FR_; \ FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; #nimFrame((TFrame*)&FR_); - $1define nimln_(n, file) \ + $1define nimln_(n) \ + FR_.line = n; + + $1define nimlf_(n, file) \ FR_.line = n; FR_.filename = file; + """ if p.module.s[cfsFrameDefines].len == 0: appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"]) cgsym(p.module, "nimFrame") - result = ropecg(p.module, "\tnimfr_($1, $2);$n", [procname, filename]) + result = ropecg(p.module, "\tnimfr_($1, $2);\n", [procname, filename]) proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope = cgsym(p.module, "nimFrame") @@ -747,7 +774,7 @@ proc deinitFrameNoDebug(p: BProc; frame: Rope): Rope = result = ropecg(p.module, "\t#popFrameOfAddr(&$1);$n", [frame]) proc deinitFrame(p: BProc): Rope = - result = ropecg(p.module, "\t#popFrame();$n", []) + result = ropecg(p.module, "\t#popFrame();\n", []) include ccgexprs @@ -1121,13 +1148,13 @@ proc genProcAux*(m: BModule, prc: PSym) = var decl = localVarDecl(p, resNode) var a: TLoc initLocExprSingleUse(p, val, a) - linefmt(p, cpsStmts, "$1 = $2;$n", [decl, rdLoc(a)]) + linefmt(p, cpsStmts, "$1 = $2;\n", [decl, rdLoc(a)]) else: # declare the result symbol: assignLocalVar(p, resNode) assert(res.loc.r != "") initLocalVar(p, res, immediateAsgn=false) - returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)]) + returnStmt = ropecg(p.module, "\treturn $1;\n", [rdLoc(res.loc)]) else: fillResult(p.config, resNode, prc.typ) assignParam(p, res, prc.typ[0]) @@ -1168,7 +1195,7 @@ proc genProcAux*(m: BModule, prc: PSym) = # This fixes the use of methods and also the case when 2 functions within the same module # call each other using directly the "_actual" versions (an optimization) - see issue #11608 m.s[cfsProcHeaders].addf("$1;\n", [header]) - generatedProc.add ropecg(p.module, "$1 {$n", [header]) + generatedProc.add ropecg(p.module, "$1 {\n", [header]) if optStackTrace in prc.options: generatedProc.add(p.s(cpsLocals)) var procname = makeCString(prc.name.s) @@ -1183,7 +1210,7 @@ proc genProcAux*(m: BModule, prc: PSym) = if beforeRetNeeded in p.flags: generatedProc.add("{") generatedProc.add(p.s(cpsInit)) generatedProc.add(p.s(cpsStmts)) - if beforeRetNeeded in p.flags: generatedProc.add("\t}BeforeRet_: ;\n") + if beforeRetNeeded in p.flags: generatedProc.add("\t}\nBeforeRet_: ;\n") if optStackTrace in prc.options: generatedProc.add(deinitFrame(p)) generatedProc.add(returnStmt) generatedProc.add("}\n") @@ -1452,19 +1479,19 @@ proc genMainProc(m: BModule) = "}$N$N" & "$4" & "N_LIB_PRIVATE void $3PreMain(void) {$N" & - "\t##if $5$N" & # 1 for volatile call, 0 for non-volatile + "##if $5$N" & # 1 for volatile call, 0 for non-volatile "\tvoid (*volatile inner)(void);$N" & "\tinner = $3PreMainInner;$N" & "$1" & "\t(*inner)();$N" & - "\t##else$N" & + "##else$N" & "$1" & "\t$3PreMainInner();$N" & - "\t##endif$N" & + "##endif$N" & "}$N$N" MainProcs = - "\t$^NimMain();$N" + "\t\t$^NimMain();$N" MainProcsWithResult = MainProcs & ("\treturn $1nim_program_result;$N") @@ -1475,17 +1502,17 @@ proc genMainProc(m: BModule) = NimMainProc = "N_CDECL(void, $5NimMain)(void) {$N" & - "\t##if $6$N" & # 1 for volatile call, 0 for non-volatile + "##if $6$N" & # 1 for volatile call, 0 for non-volatile "\tvoid (*volatile inner)(void);$N" & "$4" & "\tinner = $5NimMainInner;$N" & "$2" & "\t(*inner)();$N" & - "\t##else$N" & + "##else$N" & "$4" & "$2" & "\t$5NimMainInner();$N" & - "\t##endif$N" & + "##endif$N" & "}$N$N" NimMainBody = NimMainInner & NimMainProc @@ -1516,7 +1543,7 @@ proc genMainProc(m: BModule) = WinCDllMain = "BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" & " LPVOID lpvReserved) {$N" & - "\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" & + "\tif (fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "\t}$N" & "\treturn 1;$N}$N$N" PosixNimDllMain = WinNimDllMain @@ -1888,7 +1915,7 @@ proc genModule(m: BModule, cfile: Cfile): Rope = if m.s[cfsFrameDefines].len > 0: result.add(m.s[cfsFrameDefines]) else: - result.add("#define nimfr_(x, y)\n#define nimln_(x, y)\n") + result.add("#define nimfr_(x, y)\n#define nimln_(x)\n\n#define nimlf_(x, y)\n") for i in cfsForwardTypes..cfsProcs: if m.s[i].len > 0: From 43f29842fccadb1b282bf76883a6932f0c7af70d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 28 Apr 2023 20:26:21 +0800 Subject: [PATCH 029/489] closes #21745 (#21746) --- lib/pure/smtp.nim.cfg | 1 - 1 file changed, 1 deletion(-) delete mode 100644 lib/pure/smtp.nim.cfg diff --git a/lib/pure/smtp.nim.cfg b/lib/pure/smtp.nim.cfg deleted file mode 100644 index 521e21de41..0000000000 --- a/lib/pure/smtp.nim.cfg +++ /dev/null @@ -1 +0,0 @@ --d:ssl From 77093bf7b98539285aa358c0e22e6577387c2377 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sat, 29 Apr 2023 08:01:23 +0100 Subject: [PATCH 030/489] Save and restore ci_bench cache (#21750) --- .github/workflows/ci_bench.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci_bench.yml b/.github/workflows/ci_bench.yml index b044ab51f2..09f01242fd 100644 --- a/.github/workflows/ci_bench.yml +++ b/.github/workflows/ci_bench.yml @@ -73,22 +73,22 @@ jobs: id: minimize-cache uses: actions/cache/restore@v3 with: - path: minimize.sqlite + path: minimize.csv key: minimize-db-key - name: 'Update minimize db' shell: bash run: ./minimize/minimize update-db - # - name: 'Save minimize cached database' - #if: | - # github.event_name == 'push' && github.ref == 'refs/heads/devel' && - # matrix.target == 'linux' - # id: minimize-cache - # uses: actions/cache/save@v3 - # with: - # path: minimize.sqlite - # key: minimize-db-key + - name: 'Save minimize cached database' + if: | + github.event_name == 'push' && github.ref == 'refs/heads/devel' && + matrix.target == 'linux' + id: minimize-cache + uses: actions/cache/save@v3 + with: + path: minimize.csv + key: minimize-db-key - name: 'Generate minimize report' shell: bash From a593e40ad614158a35c7d6f777e783b0c910c9ed Mon Sep 17 00:00:00 2001 From: Al Hoang <13622+hoanga@users.noreply.github.com> Date: Sat, 29 Apr 2023 02:50:46 -0500 Subject: [PATCH 031/489] fix build on haiku (#21752) * missing maxDescriptors --- lib/pure/asyncdispatch.nim | 2 +- lib/pure/selectors.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 63062d8da5..24c1ec3d56 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -2035,7 +2035,7 @@ when defined(posix): import posix when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or - defined(solaris) or defined(zephyr) or defined(freertos) or defined(nuttx): + defined(solaris) or defined(zephyr) or defined(freertos) or defined(nuttx) or defined(haiku): proc maxDescriptors*(): int {.raises: OSError.} = ## Returns the maximum number of active file descriptors for the current ## process. This involves a system call. For now `maxDescriptors` is diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index b15a25a1db..fc65e0e9b5 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -328,7 +328,7 @@ else: doAssert(timeout >= -1, "Cannot select with a negative value, got: " & $timeout) when defined(linux) or defined(windows) or defined(macosx) or defined(bsd) or - defined(solaris) or defined(zephyr) or defined(freertos) or defined(nuttx): + defined(solaris) or defined(zephyr) or defined(freertos) or defined(nuttx) or defined(haiku): template maxDescriptors*(): int = ## Returns the maximum number of active file descriptors for the current ## process. This involves a system call. For now `maxDescriptors` is From 8e0f336f6dab061bd4dd0a07f4b436bbbe78138d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 29 Apr 2023 21:30:44 +0800 Subject: [PATCH 032/489] fixes #21483; fixes nim doc skips documentation of annotated elements of objects (#21743) * fixes #21483; skipPragmaExpr * add a test case for #21483 * fixes HTML --- compiler/renderer.nim | 2 +- nimdoc/testproject/expected/testproject.html | 29 ++++++++++++++++++++ nimdoc/testproject/expected/testproject.idx | 2 ++ nimdoc/testproject/expected/theindex.html | 8 ++++++ nimdoc/testproject/testproject.nim | 8 ++++++ 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 4ed9ec177e..ea5446cb1e 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1482,7 +1482,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = of nkRecList: indentNL(g) for i in 0..Foo
  • FooBuzz
  • +
  • MyObject
  • myfn
  • myfn()
  • + +
      testNimDocTrailingExample
    • testNimDocTrailingExample()
    • @@ -390,6 +397,17 @@ + + +
      +
      MyObject = object
      +  someString*: string        ## This is a string
      +  annotated* {.somePragma.}: string ## This is an annotated string
      +  
      +
      + + +
      @@ -1127,6 +1145,17 @@ bar
      + +
      +
      +
      template somePragma() {.pragma.}
      +
      + + Just some annotation + +
      +
      +
      diff --git a/nimdoc/testproject/expected/testproject.idx b/nimdoc/testproject/expected/testproject.idx index 46ffaee72c..c29223a833 100644 --- a/nimdoc/testproject/expected/testproject.idx +++ b/nimdoc/testproject/expected/testproject.idx @@ -64,5 +64,7 @@ nim Rectangle testproject.html#Rectangle Shapes.Rectangle 380 nim Shapes testproject.html#Shapes enum Shapes 380 nim anything testproject.html#anything proc anything() 387 nim T19396 testproject.html#T19396 object T19396 392 +nim somePragma testproject.html#somePragma.t template somePragma() 396 +nim MyObject testproject.html#MyObject object MyObject 400 nimgrp bar testproject.html#bar-procs-all proc 31 nimgrp baz testproject.html#baz-procs-all proc 34 diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index fd4666bf9a..24e3cff1c9 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -282,6 +282,10 @@
    • testproject: template myfn()
    +
    MyObject:
    p1:
    +
    somePragma:
    SomeType:
    • utils: enum SomeType
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index b5fa2ac37e..d08a12544f 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -392,3 +392,11 @@ when true: # issue #15184 type T19396* = object # bug #19396 a*: int b: float + +template somePragma*() {.pragma.} + ## Just some annotation + +type # bug #21483 + MyObject* = object + someString*: string ## This is a string + annotated* {.somePragma.}: string ## This is an annotated string From aec5a4c4744a81e19954daf330bafac948098835 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 1 May 2023 21:42:53 +0800 Subject: [PATCH 033/489] fixes #20144; fixes asyncnet ssl on bsds (#21763) fixes asyncnet on bsds --- lib/pure/asyncnet.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index d35dbdfaf2..2fc8d366e8 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -265,14 +265,17 @@ when defineSsl: ErrClearError() # Call the desired operation. opResult = op - + let err = + if opResult < 0: + getSslError(socket, opResult.cint) + else: + SSL_ERROR_NONE # Send any remaining pending SSL data. await sendPendingSslData(socket, flags) # If the operation failed, try to see if SSL has some data to read # or write. if opResult < 0: - let err = getSslError(socket, opResult.cint) let fut = appeaseSsl(socket, flags, err.cint) yield fut if not fut.read(): From 3e82a315fce0c0b11be5094092d8cf4b12b49299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Tue, 2 May 2023 09:10:51 +0100 Subject: [PATCH 034/489] implements #21747 (#21748) --- compiler/ccgtypes.nim | 60 ++++++++++++++++++++++++------------------- compiler/pragmas.nim | 2 +- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 9757f6aa9f..adefffc8b7 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -576,22 +576,11 @@ proc fillObjectFields*(m: BModule; typ: PType) = proc mangleDynLibProc(sym: PSym): Rope -proc getRecordDesc(m: BModule; typ: PType, name: Rope, - check: var IntSet): Rope = - # declare the record: - var hasField = false - - if tfPacked in typ.flags: - if hasAttribute in CC[m.config.cCompiler].props: - result = structOrUnion(typ) & " __attribute__((__packed__))" - else: - result = "#pragma pack(push, 1)\L" & structOrUnion(typ) - else: - result = structOrUnion(typ) - - result.add " " - result.add name - +template cgDeclFrmt*(s: PSym): string = + s.constraint.strVal + +proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope, + check: var IntSet, hasField:var bool): Rope = if typ.kind == tyObject: if typ[0] == nil: if lacksMTypeField(typ): @@ -603,8 +592,7 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope, appcg(m, result, " {$n#TNimType* m_type;\n", []) hasField = true elif m.compileToCpp: - appcg(m, result, " : public $1 {\n", - [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)]) + appcg(m, result, " : public $1 {\n", [baseType]) if typ.isException and m.config.exc == excCpp: when false: appcg(m, result, "virtual void raise() { throw *this; }\n", []) # required for polymorphic exceptions @@ -616,18 +604,38 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope, appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}\n", [name]) hasField = true else: - appcg(m, result, " {$n $1 Sup;\n", - [getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField)]) + appcg(m, result, " {$n $1 Sup;\n", [baseType]) hasField = true else: result.addf(" {\n", [name]) - let desc = getRecordFields(m, typ, check) - if desc == "" and not hasField: - result.addf("char dummy;\n", []) +proc getRecordDesc(m: BModule; typ: PType, name: Rope, + check: var IntSet): Rope = + # declare the record: + var hasField = false + var structOrUnion: string + if tfPacked in typ.flags: + if hasAttribute in CC[m.config.cCompiler].props: + structOrUnion = structOrUnion(typ) & " __attribute__((__packed__))" + else: + structOrUnion = "#pragma pack(push, 1)\L" & structOrUnion(typ) else: - result.add(desc) - result.add("};\L") + structOrUnion = structOrUnion(typ) + var baseType: string + if typ[0] != nil: + baseType = getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, skField) + if typ.sym == nil or typ.sym.constraint == nil: + result = structOrUnion & " " & name + result.add(getRecordDescAux(m, typ, name, baseType, check, hasField)) + let desc = getRecordFields(m, typ, check) + if desc == "" and not hasField: + result.addf("char dummy;\n", []) + else: + result.add(desc) + result.add("};\L") + else: + let desc = getRecordFields(m, typ, check) + result = runtimeFormat(typ.sym.cgDeclFrmt, [name, desc, baseType]) if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props: result.add "#pragma pack(pop)\L" @@ -956,8 +964,6 @@ proc finishTypeDescriptions(m: BModule) = inc(i) m.typeStack.setLen 0 -template cgDeclFrmt*(s: PSym): string = - s.constraint.strVal proc isReloadable(m: BModule; prc: PSym): bool = return m.hcrOn and sfNonReloadable notin prc.flags diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 22677ba015..a91f359d52 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -71,7 +71,7 @@ const wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow, wIncompleteStruct, wCompleteStruct, wByCopy, wByRef, wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, - wCppNonPod, wBorrow, wGcSafe, wPartial, wExplain, wPackage} + wCppNonPod, wBorrow, wGcSafe, wPartial, wExplain, wPackage, wCodegenDecl} fieldPragmas* = declPragmas + {wGuard, wBitsize, wCursor, wRequiresInit, wNoalias, wAlign} - {wExportNims, wNodecl} # why exclude these? varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar, From 2844ac8b5eb6efce18e10b246e874719b20d36b2 Mon Sep 17 00:00:00 2001 From: Amjad Ben Hedhili Date: Tue, 2 May 2023 09:41:59 +0100 Subject: [PATCH 035/489] Ignore pkgs folder (#21755) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d0c4558df7..89c67024e7 100644 --- a/.gitignore +++ b/.gitignore @@ -110,3 +110,4 @@ htmldocs nimdoc.out.css # except here: !/nimdoc/testproject/expected/* +pkgs/ From afc30ca87948c11f603f6686d4b10d3dcc27776a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 2 May 2023 16:49:17 +0800 Subject: [PATCH 036/489] fixes #19863; move sha1, md5 to nimble packages for 2.0 (#21702) * move sha1, md5 to nimble packages * boot the compiler * fixes tests * build the documentation * fixes docs * lol, I forgot koch.nim * add `nimHasChecksums` define * clone checksums but maybe copying is better * bump nimble hash * use ChecksumsStableCommit * fixes tests * deprecate them * fixes paths * fixes koch --- changelogs/changelog_2_0_0.md | 2 ++ compiler/ccgtypes.nim | 2 +- compiler/condsyms.nim | 2 ++ compiler/extccomp.nim | 4 ++- compiler/gorgeimpl.nim | 4 ++- compiler/ic/ic.nim | 4 ++- compiler/installer.ini | 1 + compiler/main.nim | 4 ++- compiler/modulegraphs.nim | 3 +- compiler/nimblecmd.nim | 4 ++- compiler/passes.nim | 2 +- compiler/sighashes.nim | 3 +- koch.nim | 19 ++++++++++++- lib/deprecated/pure/securehash.nim | 6 ---- lib/pure/md5.nim | 4 ++- lib/std/sha1.nim | 5 +++- nimsuggest/nimsuggest.nim | 3 +- testament/testament.nim | 4 ++- tests/effects/tstrict_funcs_imports.nim | 2 -- tests/js/tstdlib_imports.nim | 2 +- .../enet_server/server_utils.nim | 4 ++- .../keineschweine/lib/client_helpers.nim | 4 ++- tests/manyloc/keineschweine/lib/sg_assets.nim | 4 ++- .../manyloc/keineschweine/lib/sg_packets.nim | 4 ++- .../keineschweine/server/old_dirserver.nim | 4 +-- .../keineschweine/server/old_server_utils.nim | 4 ++- .../manyloc/keineschweine/server/sg_lobby.nim | 3 +- tests/stdlib/tmd5.nim | 18 ------------ tests/stdlib/tsha1.nim | 28 ------------------- tests/test_nimscript.nims | 2 +- tests/vm/tsignaturehash.nim | 2 +- tools/kochdocs.nim | 10 ------- tools/niminst/niminst.nim | 4 +-- 33 files changed, 80 insertions(+), 91 deletions(-) delete mode 100644 lib/deprecated/pure/securehash.nim delete mode 100644 tests/stdlib/tmd5.nim delete mode 100644 tests/stdlib/tsha1.nim diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 8a50197316..ae2f2ec6c0 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -126,6 +126,8 @@ - `std/db_mysql` => `db_connector/db_mysql` - `std/db_postgres` => `db_connector/db_postgres` - `std/db_odbc` => `db_connector/db_odbc` + - `std/md5` => `checksums/md5` + - `std/sha1` => `checksums/sha1` - Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of `foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`. diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index adefffc8b7..c164a80d71 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -12,7 +12,7 @@ # ------------------------- Name Mangling -------------------------------- import sighashes, modulegraphs -import std/md5 +import ../dist/checksums/src/checksums/md5 proc isKeyword(w: PIdent): bool = # Nim and C++ share some keywords diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index a499b71429..fa7f56504d 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -154,3 +154,5 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasGenericDefine") defineSymbol("nimHasDefineAliases") defineSymbol("nimHasWarnBareExcept") + + defineSymbol("nimHasChecksums") diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 45a531852c..040fe35e19 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -14,13 +14,15 @@ import ropes, platform, condsyms, options, msgs, lineinfos, pathutils, modulepaths -import std/[os, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils] +import std/[os, osproc, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils] import std / strutils except addf when defined(nimPreviewSlimSystem): import std/syncio +import ../dist/checksums/src/checksums/sha1 + type TInfoCCProp* = enum # properties of the C compiler: hasSwitchRange, # CC allows ranges in switch statements (GNU C) diff --git a/compiler/gorgeimpl.nim b/compiler/gorgeimpl.nim index 8fac069715..558a6c9a3d 100644 --- a/compiler/gorgeimpl.nim +++ b/compiler/gorgeimpl.nim @@ -9,12 +9,14 @@ ## Module that implements ``gorge`` for the compiler. -import msgs, std / sha1, os, osproc, streams, options, +import msgs, os, osproc, streams, options, lineinfos, pathutils when defined(nimPreviewSlimSystem): import std/syncio +import ../dist/checksums/src/checksums/sha1 + proc readOutput(p: Process): (string, int) = result[0] = "" var output = p.outputStream diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 793ece80a8..324782b546 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -7,13 +7,15 @@ # distribution, for details about the copyright. # -import hashes, tables, intsets, std/sha1 +import hashes, tables, intsets import packed_ast, bitabs, rodfiles import ".." / [ast, idents, lineinfos, msgs, ropes, options, pathutils, condsyms, packages, modulepaths] #import ".." / [renderer, astalgo] from os import removeFile, isAbsolute +import ../../dist/checksums/src/checksums/sha1 + when defined(nimPreviewSlimSystem): import std/[syncio, assertions, formatfloat] diff --git a/compiler/installer.ini b/compiler/installer.ini index 226682715c..4d0eab86d1 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -78,6 +78,7 @@ Files: "lib" [Other] Files: "examples" Files: "dist/nimble" +Files: "dist/checksums" Files: "tests" diff --git a/compiler/main.nim b/compiler/main.nim index ff870a14a0..bc4b89147e 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -13,7 +13,7 @@ when not defined(nimcore): {.error: "nimcore MUST be defined for Nim's core tooling".} import - std/[strutils, os, times, tables, sha1, with, json], + std/[strutils, os, times, tables, with, json], llstream, ast, lexer, syntaxes, options, msgs, condsyms, idents, extccomp, @@ -29,6 +29,8 @@ when defined(nimPreviewSlimSystem): import ic / [cbackend, integrity, navigator] from ic / ic import rodViewer +import ../dist/checksums/src/checksums/sha1 + import pipelines when not defined(leanCompiler): diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 4fdeb354e4..5cb6a1c34a 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -11,7 +11,8 @@ ## represents a complete Nim project. Single modules can either be kept in RAM ## or stored in a rod-file. -import intsets, tables, hashes, md5 +import intsets, tables, hashes +import ../dist/checksums/src/checksums/md5 import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages import ic / [packed_ast, ic] diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index b6b08ccd45..440d35fe52 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -10,11 +10,13 @@ ## Implements some helper procs for Nimble (Nim's package manager) support. import parseutils, strutils, os, options, msgs, sequtils, lineinfos, pathutils, - std/sha1, tables + tables when defined(nimPreviewSlimSystem): import std/[syncio, assertions] +import ../dist/checksums/src/checksums/sha1 + proc addPath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) = if not conf.searchPaths.contains(path): conf.searchPaths.insert(path, 0) diff --git a/compiler/passes.nim b/compiler/passes.nim index 536a64714e..87a9d05c8a 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -24,7 +24,7 @@ import ic/replayer export skipCodegen, resolveMod, prepareConfigNotes when defined(nimsuggest): - import std/sha1 + import ../dist/checksums/src/checksums/sha1 when defined(nimPreviewSlimSystem): import std/[syncio, assertions] diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 4f945da5f9..2d91fb2a01 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -9,9 +9,10 @@ ## Computes hash values for routine (proc, method etc) signatures. -import ast, tables, ropes, md5, modulegraphs, options, msgs, pathutils +import ast, tables, ropes, modulegraphs, options, msgs, pathutils from hashes import Hash import types +import ../dist/checksums/src/checksums/md5 when defined(nimPreviewSlimSystem): diff --git a/koch.nim b/koch.nim index d89d9fc931..3b9f08557b 100644 --- a/koch.nim +++ b/koch.nim @@ -10,9 +10,10 @@ # const - NimbleStableCommit = "7efb226ef908297e8791cade20d991784b4e8bfc" # master + NimbleStableCommit = "168416290e49023894fc26106799d6f1fc964a2d" # master # examples of possible values: #head, #ea82b54, 1.2.3 FusionStableHash = "#372ee4313827ef9f2ea388840f7d6b46c2b1b014" + ChecksumsStableCommit = "3fa15df7d27ecef624ed932d60f63d6a8949618d" HeadHash = "#head" when not defined(windows): const @@ -148,6 +149,8 @@ proc bundleNimbleExe(latest: bool, args: string) = let commit = if latest: "HEAD" else: NimbleStableCommit cloneDependency(distDir, "https://github.com/nim-lang/nimble.git", commit = commit, allowBundled = true) + cloneDependency(distDir / "nimble" / distDir, "https://github.com/nim-lang/checksums.git", + commit = ChecksumsStableCommit, allowBundled = true) # or copy it from dist? # installer.ini expects it under $nim/bin nimCompile("dist/nimble/src/nimble.nim", options = "-d:release --mm:refc --noNimblePath " & args) @@ -181,7 +184,12 @@ proc bundleWinTools(args: string) = nimCompile(r"tools\downloader.nim", options = r"--cc:vcc --app:gui -d:ssl --noNimblePath --path:..\ui " & args) +proc bundleChecksums(latest: bool) = + let commit = if latest: "HEAD" else: ChecksumsStableCommit + cloneDependency(distDir, "https://github.com/nim-lang/checksums.git", commit) + proc zip(latest: bool; args: string) = + bundleChecksums(latest) bundleNimbleExe(latest, args) bundleNimsuggest(args) bundleNimpretty(args) @@ -239,6 +247,7 @@ proc testTools(args: string = "") = outputName = "atlas") proc nsis(latest: bool; args: string) = + bundleChecksums(latest) bundleNimbleExe(latest, args) bundleNimsuggest(args) bundleWinTools(args) @@ -301,6 +310,9 @@ proc boot(args: string) = let smartNimcache = (if "release" in args or "danger" in args: "nimcache/r_" else: "nimcache/d_") & hostOS & "_" & hostCPU + if not dirExists("dist/checksums"): + bundleChecksums(false) + let nimStart = findStartNim().quoteShell() for i in 0..2: let defaultCommand = if useCpp: "cpp" else: "c" @@ -451,6 +463,9 @@ proc temp(args: string) = result[1].add " " & quoteShell(args[i]) inc i + if not dirExists("dist/checksums"): + bundleChecksums(false) + let d = getAppDir() let output = d / "compiler" / "nim".exe let finalDest = d / "bin" / "nim_temp".exe @@ -711,6 +726,8 @@ when isMainModule: of "tools": buildTools(op.cmdLineRest) bundleNimbleExe(latest, op.cmdLineRest) + of "checksums": + bundleChecksums(latest) of "pushcsource": quit "use this instead: https://github.com/nim-lang/csources_v1/blob/master/push_c_code.nim" of "valgrind": valgrind(op.cmdLineRest) diff --git a/lib/deprecated/pure/securehash.nim b/lib/deprecated/pure/securehash.nim deleted file mode 100644 index b4749ad758..0000000000 --- a/lib/deprecated/pure/securehash.nim +++ /dev/null @@ -1,6 +0,0 @@ -## This module is a deprecated alias for the `sha1` module. Deprecated since 0.18.1. - -{.deprecated: "use `std/sha1` instead".} - -import "../std/sha1" -export sha1 diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim index cd4d1e6b8e..81c85a07c2 100644 --- a/lib/pure/md5.nim +++ b/lib/pure/md5.nim @@ -18,6 +18,8 @@ ## * `hashes module`_ for efficient computations of hash values ## for diverse Nim types +{.deprecated: "use command `nimble install checksums` and import `checksums/md5` instead".} + when defined(nimHasStyleChecks): {.push styleChecks: off.} @@ -343,4 +345,4 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) = when defined(nimHasStyleChecks): - {.pop.} #{.push styleChecks: off.} + {.pop.} #{.push styleChecks: off.} \ No newline at end of file diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim index 50175024cd..a1a8c47823 100644 --- a/lib/std/sha1.nim +++ b/lib/std/sha1.nim @@ -26,6 +26,9 @@ runnableExamples("-r:off"): b = parseSecureHash("10DFAEBF6BFDBC7939957068E2EFACEC4972933C") assert a == b, "files don't match" + +{.deprecated: "use command `nimble install checksums` and import `checksums/sha1` instead".} + import strutils from endians import bigEndian32, bigEndian64 @@ -281,4 +284,4 @@ proc `==`*(a, b: SecureHash): bool = proc isValidSha1Hash*(s: string): bool = ## Checks if a string is a valid sha1 hash sum. - s.len == 40 and allCharsInSet(s, HexDigits) + s.len == 40 and allCharsInSet(s, HexDigits) \ No newline at end of file diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 685dbedb8d..7608052a6c 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -11,9 +11,10 @@ import compiler/renderer import strformat import algorithm import tables -import std/sha1 import times +import ../dist/checksums/src/checksums/sha1 + ## Nimsuggest is a tool that helps to give editors IDE like capabilities. when not defined(nimcore): diff --git a/testament/testament.nim b/testament/testament.nim index 296c313aa3..1ed5ef92a2 100644 --- a/testament/testament.nim +++ b/testament/testament.nim @@ -12,13 +12,15 @@ import strutils, pegs, os, osproc, streams, json, std/exitprocs, backend, parseopt, specs, htmlgen, browsers, terminal, - algorithm, times, md5, azure, intsets, macros + algorithm, times, azure, intsets, macros from std/sugar import dup import compiler/nodejs import lib/stdtest/testutils from lib/stdtest/specialpaths import splitTestFile from std/private/gitutils import diffStrings +import ../dist/checksums/src/checksums/md5 + proc trimUnitSep(x: var string) = let L = x.len if L > 0 and x[^1] == '\31': diff --git a/tests/effects/tstrict_funcs_imports.nim b/tests/effects/tstrict_funcs_imports.nim index 53f3462363..bf68b61b2e 100644 --- a/tests/effects/tstrict_funcs_imports.nim +++ b/tests/effects/tstrict_funcs_imports.nim @@ -66,7 +66,6 @@ import macros, marshal, math, - md5, memfiles, mersenne, mimetypes, @@ -155,7 +154,6 @@ import std/[ monotimes, packedsets, setutils, - sha1, socketstreams, stackframes, sums, diff --git a/tests/js/tstdlib_imports.nim b/tests/js/tstdlib_imports.nim index 214c0f7830..db851ba28d 100644 --- a/tests/js/tstdlib_imports.nim +++ b/tests/js/tstdlib_imports.nim @@ -62,7 +62,7 @@ import std/[ htmlgen, # Hashing: - base64, hashes, md5, + base64, hashes, # fails due to cstring cast/endians import: oids # fails due to copyMem/endians import: sha1 diff --git a/tests/manyloc/keineschweine/enet_server/server_utils.nim b/tests/manyloc/keineschweine/enet_server/server_utils.nim index 1fb8326edb..3940dcf015 100644 --- a/tests/manyloc/keineschweine/enet_server/server_utils.nim +++ b/tests/manyloc/keineschweine/enet_server/server_utils.nim @@ -1,4 +1,6 @@ -import enet, sg_packets, estreams, md5, zlib_helpers, client_helpers, strutils, +import ../../../../dist/checksums/src/checksums/md5 + +import enet, sg_packets, estreams, zlib_helpers, client_helpers, strutils, idgen, sg_assets, tables, os type PClient* = ref object diff --git a/tests/manyloc/keineschweine/lib/client_helpers.nim b/tests/manyloc/keineschweine/lib/client_helpers.nim index b535225dc1..b21e67cf72 100644 --- a/tests/manyloc/keineschweine/lib/client_helpers.nim +++ b/tests/manyloc/keineschweine/lib/client_helpers.nim @@ -1,6 +1,8 @@ +import ../../../../dist/checksums/src/checksums/md5 + import tables, sg_packets, enet, estreams, sg_gui, sfml, - zlib_helpers, md5, sg_assets, os + zlib_helpers, sg_assets, os type PServer* = ptr TServer TServer* = object diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim index 5929add434..96c962dc33 100644 --- a/tests/manyloc/keineschweine/lib/sg_assets.nim +++ b/tests/manyloc/keineschweine/lib/sg_assets.nim @@ -1,6 +1,8 @@ +import ../../../../dist/checksums/src/checksums/md5 + import re, json, strutils, tables, math, os, math_helpers, - sg_packets, md5, zlib_helpers + sg_packets, zlib_helpers when defined(NoSFML): import server_utils diff --git a/tests/manyloc/keineschweine/lib/sg_packets.nim b/tests/manyloc/keineschweine/lib/sg_packets.nim index 0727c699a6..797a60706c 100644 --- a/tests/manyloc/keineschweine/lib/sg_packets.nim +++ b/tests/manyloc/keineschweine/lib/sg_packets.nim @@ -1,4 +1,6 @@ -import genpacket_enet, nativesockets, net, md5, enet +import ../../../../dist/checksums/src/checksums/md5 + +import genpacket_enet, nativesockets, net, enet defPacketImports() type diff --git a/tests/manyloc/keineschweine/server/old_dirserver.nim b/tests/manyloc/keineschweine/server/old_dirserver.nim index cd2b60b261..70ae05b0bb 100644 --- a/tests/manyloc/keineschweine/server/old_dirserver.nim +++ b/tests/manyloc/keineschweine/server/old_dirserver.nim @@ -1,9 +1,9 @@ ## directory server ## handles client authorization and assets - +import ../../../dist/checksums/src/checksums/md5 import sockets, times, streams, streams_enh, tables, json, os, - sg_packets, sg_assets, md5, server_utils, map_filter + sg_packets, sg_assets, server_utils, map_filter type THandler = proc(client: PCLient; stream: PStream) var diff --git a/tests/manyloc/keineschweine/server/old_server_utils.nim b/tests/manyloc/keineschweine/server/old_server_utils.nim index 3da6e078c2..f389c08367 100644 --- a/tests/manyloc/keineschweine/server/old_server_utils.nim +++ b/tests/manyloc/keineschweine/server/old_server_utils.nim @@ -1,5 +1,7 @@ +import ../../../dist/checksums/src/checksums/md5 + import - streams, md5, sockets, + streams, sockets, sg_packets, zlib_helpers, idgen type TClientType* = enum diff --git a/tests/manyloc/keineschweine/server/sg_lobby.nim b/tests/manyloc/keineschweine/server/sg_lobby.nim index d7e01e6e67..04ce10f082 100644 --- a/tests/manyloc/keineschweine/server/sg_lobby.nim +++ b/tests/manyloc/keineschweine/server/sg_lobby.nim @@ -1,6 +1,7 @@ +import ../../../dist/checksums/src/checksums/md5 import - sockets, streams, tables, times, math, strutils, json, os, md5, + sockets, streams, tables, times, math, strutils, json, os, sfml, sfml_vector, sfml_colors, streams_enh, input_helpers, zlib_helpers, client_helpers, sg_packets, sg_assets, sg_gui type diff --git a/tests/stdlib/tmd5.nim b/tests/stdlib/tmd5.nim deleted file mode 100644 index 37c2f17d7e..0000000000 --- a/tests/stdlib/tmd5.nim +++ /dev/null @@ -1,18 +0,0 @@ -discard """ - matrix: "--mm:refc; --mm:orc" - targets: "c cpp js" -""" - -import md5 -import std/assertions - -proc main() {.raises: [].} = - doAssert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") == - "a3cca2b2aa1e3b5b3b5aad99a8529074") - doAssert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") == - "7e716d0e702df0505fc72e2b89467910") - doAssert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e") - -main() - -static: main() diff --git a/tests/stdlib/tsha1.nim b/tests/stdlib/tsha1.nim deleted file mode 100644 index 50bf392c59..0000000000 --- a/tests/stdlib/tsha1.nim +++ /dev/null @@ -1,28 +0,0 @@ -discard """ - matrix: "--mm:refc; --mm:orc" -""" - -import std/sha1 -import std/assertions - -let hash1 = secureHash("a93tgj0p34jagp9[agjp98ajrhp9aej]") -doAssert hash1 == hash1 -doAssert parseSecureHash($hash1) == hash1 - -template checkVector(s, exp: string) = - doAssert secureHash(s) == parseSecureHash(exp) - -checkVector("", "da39a3ee5e6b4b0d3255bfef95601890afd80709") -checkVector("abc", "a9993e364706816aba3e25717850c26c9cd0d89d") -checkVector("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - "84983e441c3bd26ebaae4aa1f95129e5e54670f1") - -proc testIsValidSha1Hash = - doAssert not isValidSha1Hash("") - doAssert not isValidSha1Hash("042D4BE2B90ED0672E717D71850ABDB0A2D19CD11") - doAssert not isValidSha1Hash("042G4BE2B90ED0672E717D71850ABDB0A2D19CD1") - doAssert isValidSha1Hash("042D4BE2B90ED0672E717D71850ABDB0A2D19CD1") - doAssert isValidSha1Hash("042d4be2b90ed0672e717d71850abdb0a2d19cd1") - doAssert isValidSha1Hash("042d4be2b90ed0672e717D71850ABDB0A2D19CD1") - -testIsValidSha1Hash() diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 725e75ebc0..32b7d1416e 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -64,7 +64,7 @@ import std/[ htmlgen, # Hashing: - base64, hashes, md5, + base64, hashes, # fails due to cstring cast/times import/endians import: oids # fails due to copyMem/endians import: sha1 diff --git a/tests/vm/tsignaturehash.nim b/tests/vm/tsignaturehash.nim index 42e0a15712..972ec6fb0a 100644 --- a/tests/vm/tsignaturehash.nim +++ b/tests/vm/tsignaturehash.nim @@ -1,7 +1,7 @@ # test sym digest is computable at compile time import macros, algorithm -import md5 +import ../../dist/checksums/src/checksums/md5 macro testmacro(s: typed{nkSym}): string = let s = getMD5(signaturehash(s) & " - " & symBodyHash(s)) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index f63aea030b..3953025f43 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -171,16 +171,6 @@ pkgs/db_connector/src/db_connector/odbcsql.nim pkgs/db_connector/src/db_connector/private/dbutils.nim """.splitWhitespace() -proc findName(name: string): string = - doAssert name[0..4] == "pkgs/" - var i = 5 - while i < name.len: - if name[i] != '/': - inc i - result.add name[i] - else: - break - when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo): proc isRelativeTo(path, base: string): bool = let path = path.normalizedPath diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index 81b46653d5..40ee798146 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -8,9 +8,9 @@ # import - os, strutils, parseopt, parsecfg, strtabs, streams, debcreation, - std / sha1 + os, strutils, parseopt, parsecfg, strtabs, streams, debcreation +import ../../dist/checksums/src/checksums/sha1 when defined(nimPreviewSlimSystem): import std/syncio From c2bcfd8cd908265c358c60c4da137783b10a8549 Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 2 May 2023 12:13:38 +0300 Subject: [PATCH 037/489] cheap fix for #10853 + better tuple subscript error message (#21767) * cheap fix for #10853 * also better tuple subscript error message * weird --- compiler/lowerings.nim | 2 +- compiler/semexprs.nim | 5 ++++- tests/errmsgs/tassignunpack.nim | 3 +++ tests/errmsgs/ttupleindexoutofbounds.nim | 2 ++ tests/types/tassignemptytuple.nim | 2 +- 5 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 tests/errmsgs/tassignunpack.nim create mode 100644 tests/errmsgs/ttupleindexoutofbounds.nim diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index bd81773a82..d70c713a15 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -132,7 +132,7 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; o var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3) vpart[0] = tempAsNode - vpart[1] = newNodeI(nkEmpty, value.info) + vpart[1] = newNodeI(nkTupleClassTy, value.info) vpart[2] = value v.add vpart result.add(v) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 930fd35163..a01466868b 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1646,7 +1646,10 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = {tyInt..tyInt64}: let idx = getOrdValue(n[1]) if idx >= 0 and idx < arr.len: n.typ = arr[toInt(idx)] - else: localError(c.config, n.info, "invalid index value for tuple subscript") + else: + localError(c.config, n.info, + "invalid index $1 in subscript for tuple of length $2" % + [$idx, $arr.len]) result = n else: result = nil diff --git a/tests/errmsgs/tassignunpack.nim b/tests/errmsgs/tassignunpack.nim new file mode 100644 index 0000000000..27413a42b6 --- /dev/null +++ b/tests/errmsgs/tassignunpack.nim @@ -0,0 +1,3 @@ +var a, b = 0 +(a, b) = 1 #[tt.Error + ^ type mismatch: got but expected 'tuple']# diff --git a/tests/errmsgs/ttupleindexoutofbounds.nim b/tests/errmsgs/ttupleindexoutofbounds.nim new file mode 100644 index 0000000000..ae634dddb9 --- /dev/null +++ b/tests/errmsgs/ttupleindexoutofbounds.nim @@ -0,0 +1,2 @@ +let a = (1, 2)[4] #[tt.Error + ^ invalid index 4 in subscript for tuple of length 2]# diff --git a/tests/types/tassignemptytuple.nim b/tests/types/tassignemptytuple.nim index 9d5a311baa..f3320dec7a 100644 --- a/tests/types/tassignemptytuple.nim +++ b/tests/types/tassignemptytuple.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "cannot infer the type of the tuple" + errormsg: "invalid type: 'empty' in this context: '(seq[empty], (seq[empty], set[empty]))' for let" file: "tassignemptytuple.nim" line: 11 """ From ca82b4ea16eb7d48b6851110bcb4667570a97f52 Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 2 May 2023 12:15:06 +0300 Subject: [PATCH 038/489] underscore as special word (#21766) * underscore as special word * fix really hard to notice error --- compiler/lookups.nim | 6 +++--- compiler/sempass2.nim | 2 +- compiler/semstmts.nim | 4 ++-- compiler/semtempl.nim | 4 ++-- compiler/semtypes.nim | 2 +- compiler/wordrecg.nim | 1 + 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 81ea63c328..188bb1a6b5 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -15,7 +15,7 @@ when defined(nimPreviewSlimSystem): import intsets, ast, astalgo, idents, semdata, types, msgs, options, - renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs, sets + renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs, sets, wordrecg proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) @@ -340,7 +340,7 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string; # xxx pending bootstrap >= 1.4, replace all those overloads with a single one: # proc addDecl*(c: PContext, sym: PSym, info = sym.info, scope = c.currentScope) {.inline.} = proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) = - if sym.name.s == "_": return + if sym.name.id == ord(wUnderscore): return let conflict = scope.addUniqueSym(sym) if conflict != nil: if sym.kind == skModule and conflict.kind == skModule: @@ -397,7 +397,7 @@ proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) = if fn.kind notin OverloadableSyms: internalError(c.config, fn.info, "addOverloadableSymAt") return - if fn.name.s != "_": + if fn.name.id != ord(wUnderscore): let check = strTableGet(scope.symbols, fn.name) if check != nil and check.kind notin OverloadableSyms: wrongRedefinition(c, fn.info, fn.name.s, check.info) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index f0e55887cf..baa37a45f9 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1117,7 +1117,7 @@ proc track(tracked: PEffects, n: PNode) = elif child.kind == nkVarTuple: for i in 0.. Date: Tue, 2 May 2023 12:28:52 +0300 Subject: [PATCH 039/489] line info for strformat + fix issue with typed templates (#21761) * line info in strformat * also fix #20381 --- lib/pure/strformat.nim | 30 +++++++++++++++++++++-------- tests/stdlib/tstrformat.nim | 10 ++++++++++ tests/stdlib/tstrformatlineinfo.nim | 8 ++++++++ 3 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 tests/stdlib/tstrformatlineinfo.nim diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 216c1ff11f..3fedff07b5 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -577,7 +577,8 @@ template formatValue(result: var string; value: char; specifier: string) = template formatValue(result: var string; value: cstring; specifier: string) = result.add value -proc strformatImpl(f: string; openChar, closeChar: char): NimNode = +proc strformatImpl(f: string; openChar, closeChar: char, + lineInfoNode: NimNode = nil): NimNode = template missingCloseChar = error("invalid format string: missing closing character '" & closeChar & "'") @@ -585,7 +586,7 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode = error "openChar and closeChar must not be ':'" var i = 0 let res = genSym(nskVar, "fmtRes") - result = newNimNode(nnkStmtListExpr) + result = newNimNode(nnkStmtListExpr, lineInfoNode) # XXX: https://github.com/nim-lang/Nim/issues/8405 # When compiling with -d:useNimRtl, certain procs such as `count` from the strutils # module are not accessible at compile-time: @@ -644,6 +645,7 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode = x = parseExpr(subexpr) except ValueError as e: error("could not parse `$#` in `$#`.\n$#" % [subexpr, f, e.msg]) + x.copyLineInfo(lineInfoNode) let formatSym = bindSym("formatValue", brOpen) var options = "" if f[i] == ':': @@ -669,10 +671,22 @@ proc strformatImpl(f: string; openChar, closeChar: char): NimNode = if strlit.len > 0: result.add newCall(bindSym"add", res, newLit(strlit)) result.add res + # workaround for #20381 + var blockExpr = newNimNode(nnkBlockExpr, lineInfoNode) + blockExpr.add(newEmptyNode()) + blockExpr.add(result) + result = blockExpr when defined(debugFmtDsl): echo repr result -macro fmt*(pattern: static string; openChar: static char, closeChar: static char): string = +macro fmt(pattern: static string; openChar: static char, closeChar: static char, lineInfoNode: untyped): string = + ## version of `fmt` with dummy untyped param for line info + strformatImpl(pattern, openChar, closeChar, lineInfoNode) + +when not defined(nimHasCallsitePragma): + {.pragma: callsite.} + +template fmt*(pattern: static string; openChar: static char, closeChar: static char): string {.callsite.} = ## Interpolates `pattern` using symbols in scope. runnableExamples: let x = 7 @@ -689,13 +703,13 @@ macro fmt*(pattern: static string; openChar: static char, closeChar: static char assert "".fmt('<', '>') == "7" assert "<<>>".fmt('<', '>') == "<7>" assert "`x`".fmt('`', '`') == "7" - strformatImpl(pattern, openChar, closeChar) + fmt(pattern, openChar, closeChar, dummyForLineInfo) -template fmt*(pattern: static string): untyped = +template fmt*(pattern: static string): untyped {.callsite.} = ## Alias for `fmt(pattern, '{', '}')`. - fmt(pattern, '{', '}') + fmt(pattern, '{', '}', dummyForLineInfo) -macro `&`*(pattern: string{lit}): string = +template `&`*(pattern: string{lit}): string {.callsite.} = ## `&pattern` is the same as `pattern.fmt`. ## For a specification of the `&` macro, see the module level documentation. # pending bug #18275, bug #18278, use `pattern: static string` @@ -707,4 +721,4 @@ macro `&`*(pattern: string{lit}): string = assert &"{x}\n" == "7\n" # regular string literal assert &"{x}\n" == "{x}\n".fmt # `fmt` can be used instead assert &"{x}\n" != fmt"{x}\n" # see `fmt` docs, this would use a raw string literal - strformatImpl(pattern.strVal, '{', '}') + fmt(pattern, '{', '}', dummyForLineInfo) diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index 0b163125bd..3c0d55c1db 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -562,6 +562,16 @@ proc main() = doAssert &"""{(if true: "'" & "'" & ')' else: "")}""" == "'')" doAssert &"{(if true: \"\'\" & \"'\" & ')' else: \"\")}" == "'')" doAssert fmt"""{(if true: "'" & ')' else: "")}""" == "')" + + block: # issue #20381 + var ss: seq[string] + template myTemplate(s: string) = + ss.add s + ss.add s + proc foo() = + myTemplate fmt"hello" + foo() + doAssert ss == @["hello", "hello"] static: main() main() diff --git a/tests/stdlib/tstrformatlineinfo.nim b/tests/stdlib/tstrformatlineinfo.nim new file mode 100644 index 0000000000..3a7bf0d330 --- /dev/null +++ b/tests/stdlib/tstrformatlineinfo.nim @@ -0,0 +1,8 @@ +# issue #21759 + +{.hint[ConvFromXToItselfNotNeeded]: on.} + +import std/strformat + +echo fmt"{string ""abc""}" #[tt.Hint + ^ conversion from string to itself is pointless]# From a1549505707804e1ff6e76cd4253a6fe5640845b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 3 May 2023 12:42:32 +0800 Subject: [PATCH 040/489] closes #10108; add a test case (#21770) --- tests/vm/tvmmisc.nim | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 14818375db..c29dd50108 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -16,7 +16,7 @@ block: static: var x = default(type(0)) -# #6379 +# bug #6379 import algorithm static: @@ -28,7 +28,7 @@ static: str.sort(cmp) doAssert str == "abc" -# #6086 +# bug #6086 import math, sequtils, sugar block: @@ -83,7 +83,7 @@ block: doAssert fileExists("MISSINGFILE") == false doAssert dirExists("MISSINGDIR") == false -# #7210 +# bug #7210 block: static: proc f(size: int): int = @@ -91,7 +91,7 @@ block: result = size doAssert f(4) == 4 -# #6689 +# bug #6689 block: static: proc foo(): int = 0 @@ -106,7 +106,7 @@ block: new(x) doAssert(not x.isNil) -# #7871 +# bug #7871 static: type Obj = object field: int @@ -116,11 +116,11 @@ static: o.field = 2 doAssert s[0].field == 0 -# #8125 +# bug #8125 static: let def_iter_var = ident("it") -# #8142 +# bug #8142 static: type Obj = object names: string @@ -136,7 +136,7 @@ static: o.pushName() doAssert o.names == "FOOBARFOOBAR" -# #8154 +# bug #8154 import parseutils static: @@ -149,7 +149,7 @@ static: static: doAssert foo().i == 1 -# #10333 +# bug #10333 block: const encoding: auto = [ @@ -160,7 +160,7 @@ block: ] doAssert encoding.len == 4 -# #10886 +# bug #10886 proc tor(): bool = result = true @@ -656,3 +656,15 @@ proc macroGlobal = static: macroGlobal() macroGlobal() + +block: # bug #10108 + template reject(x) = + static: doAssert(not compiles(x)) + + static: + let x: int = 2 + proc deliver_x(): int = x + var y2 = deliver_x() + discard y2 + reject: + const c5 = deliver_x() From 1d80dc7df64ba89696ff52bf5f5c7372589e3af4 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 3 May 2023 18:54:40 +0800 Subject: [PATCH 041/489] closes #21771; fixes the link (#21777) closes #21771 --- doc/nimc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/nimc.md b/doc/nimc.md index 4f715ee83a..3abc340c66 100644 --- a/doc/nimc.md +++ b/doc/nimc.md @@ -526,7 +526,7 @@ Define Effect This only works with `--mm:none`:option:, `--mm:arc`:option: and `--mm:orc`:option:. `useRealtimeGC` Enables support of Nim's GC for *soft* realtime - systems. See the documentation of the [mm](mm.html) + systems. See the documentation of the [refc](refc.html) for further information. `logGC` Enable GC logging to stdout. `nodejs` The JS target is actually ``node.js``. From f37ecbb9945ecdfbaf972c4f8ac631b43f9501c6 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 3 May 2023 19:25:07 +0800 Subject: [PATCH 042/489] closes #21778; document `threading/channels` (#21779) --- changelogs/changelog_2_0_0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index ae2f2ec6c0..5110693d4b 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -40,7 +40,7 @@ `ptr int32`, `ptr int64`, `ptr float32`, `ptr float64` - Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in - in the `system` module. + in the `system` module, which is replaced by [threading/channels](https://github.com/nim-lang/threading/blob/master/threading/channels.nim). Use the command "nimble install threading" and import `threading/channels`. - Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore. From 44736d26cdbb0ea5e6010a9ae2bbeadb635d62a1 Mon Sep 17 00:00:00 2001 From: metagn Date: Wed, 3 May 2023 15:18:55 +0300 Subject: [PATCH 043/489] error on user pragma args (#21776) closes #20978 --- compiler/pragmas.nim | 6 +++++- tests/pragmas/tuserpragmaargs.nim | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/pragmas/tuserpragmaargs.nim diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index a91f359d52..9f2eeb002f 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -826,7 +826,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, validPragmas: TSpecialWords, comesFromPush, isStatement: bool): bool = var it = n[i] - var key = if it.kind in nkPragmaCallKinds and it.len > 1: it[0] else: it + let keyDeep = it.kind in nkPragmaCallKinds and it.len > 1 + var key = if keyDeep: it[0] else: it if key.kind == nkBracketExpr: processNote(c, it) return @@ -852,6 +853,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, if c.instCounter > 100: globalError(c.config, it.info, "recursive dependency: " & userPragma.name.s) + if keyDeep: + localError(c.config, it.info, "user pragma cannot have arguments") + pragma(c, sym, userPragma.ast, validPragmas, isStatement) n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty diff --git a/tests/pragmas/tuserpragmaargs.nim b/tests/pragmas/tuserpragmaargs.nim new file mode 100644 index 0000000000..791d703acf --- /dev/null +++ b/tests/pragmas/tuserpragmaargs.nim @@ -0,0 +1,5 @@ +var foo {.exportc: "abc".} = 123 +{.pragma: importc2, importc.} +var bar {.importc2: "abc".}: int #[tt.Error + ^ user pragma cannot have arguments]# +echo bar From 34b78be3968f6344da1f530793d38fb8d36f5b70 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 4 May 2023 15:10:49 +0800 Subject: [PATCH 044/489] adds checksums to important packages (#21782) --- koch.nim | 2 +- testament/important_packages.nim | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 3b9f08557b..79ca54c811 100644 --- a/koch.nim +++ b/koch.nim @@ -186,7 +186,7 @@ proc bundleWinTools(args: string) = proc bundleChecksums(latest: bool) = let commit = if latest: "HEAD" else: ChecksumsStableCommit - cloneDependency(distDir, "https://github.com/nim-lang/checksums.git", commit) + cloneDependency(distDir, "https://github.com/nim-lang/checksums.git", commit, allowBundled = true) proc zip(latest: bool; args: string) = bundleChecksums(latest) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 2fe012b26d..c77acd99b0 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -50,6 +50,7 @@ pkg "bump", "nim c --gc:arc --path:. -r tests/tbump.nim", "https://github.com/di pkg "c2nim", "nim c testsuite/tester.nim" pkg "cascade" pkg "cello", url = "https://github.com/nim-lang/cello", useHead = true +pkg "checksums" pkg "chroma" pkg "chronicles", "nim c -o:chr -r chronicles.nim", url = "https://github.com/nim-lang/nim-chronicles" pkg "chronos", "nim c -r -d:release tests/testall" From c34950f8f5e064316148f367f7d997dc553a6806 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 4 May 2023 15:44:46 +0800 Subject: [PATCH 045/489] minor cleanup vmprofiler (#21783) --- compiler/vmprofiler.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/vmprofiler.nim b/compiler/vmprofiler.nim index f586c8ffe3..342b9aad9e 100644 --- a/compiler/vmprofiler.nim +++ b/compiler/vmprofiler.nim @@ -28,7 +28,7 @@ proc leave*(prof: var Profiler, c: PCtx) {.inline.} = proc dump*(conf: ConfigRef, pd: ProfileData): string = var data = pd.data - echo "\nprof: µs #instr location" + result = "\nprof: µs #instr location" for i in 0..<32: var tMax: float var infoMax: ProfileInfo From a929e513faf04094d947e462caa653e0dfef20f0 Mon Sep 17 00:00:00 2001 From: heterodoxic <122719743+heterodoxic@users.noreply.github.com> Date: Thu, 4 May 2023 14:09:53 +0200 Subject: [PATCH 046/489] amends #21690 to fix broken Nim to C++ source line mappings (#21784) resync fork --- compiler/ccgexprs.nim | 78 +++++++++++++++++++++---------------------- compiler/ccgstmts.nim | 67 ++++++++++++++++++------------------- compiler/ccgtypes.nim | 36 ++++++++++---------- compiler/cgen.nim | 68 +++++++++++++++++++------------------ 4 files changed, 125 insertions(+), 124 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 1767edb8c9..265ccb92c7 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -199,12 +199,12 @@ proc canMove(p: BProc, n: PNode; dest: TLoc): bool = proc genRefAssign(p: BProc, dest, src: TLoc) = if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config): - linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) elif dest.storage == OnHeap: - linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);\n", + linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n", [addrLoc(p.config, dest), rdLoc(src)]) else: - linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);\n", + linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", [addrLoc(p.config, dest), rdLoc(src)]) proc asgnComplexity(n: PNode): int = @@ -270,19 +270,19 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # (for objects, etc.): if optSeqDestructors in p.config.globalOptions: linefmt(p, cpsStmts, - "$1 = $2;\n", + "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) elif needToCopy notin flags or tfShallow in skipTypes(dest.t, abstractVarRange).flags: if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config): linefmt(p, cpsStmts, - "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));\n", + "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", [addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)]) else: - linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);\n", + linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n", [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) else: - linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);\n", + linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) = @@ -318,7 +318,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # the assignment operation in C. if src.t != nil and src.t.kind == tyPtr: # little HACK to support the new 'var T' as return type: - linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) return let ty = skipTypes(dest.t, abstractRange + tyUserTypeClasses + {tyStatic}) case ty.kind @@ -330,7 +330,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = elif (needToCopy notin flags and src.storage != OnStatic) or canMove(p, src.lode, dest): genRefAssign(p, dest, src) else: - linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);\n", + linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", [addrLoc(p.config, dest), rdLoc(src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tyString: @@ -340,16 +340,16 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = genRefAssign(p, dest, src) else: if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config): - linefmt(p, cpsStmts, "$1 = #copyString($2);\n", [dest.rdLoc, src.rdLoc]) + linefmt(p, cpsStmts, "$1 = #copyString($2);$n", [dest.rdLoc, src.rdLoc]) elif dest.storage == OnHeap: # we use a temporary to care for the dreaded self assignment: var tmp: TLoc getTemp(p, ty, tmp) - linefmt(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);\n", + linefmt(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);$n", [dest.rdLoc, src.rdLoc, tmp.rdLoc]) - linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);\n", [tmp.rdLoc]) + linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", [tmp.rdLoc]) else: - linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));\n", + linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n", [addrLoc(p.config, dest), rdLoc(src)]) of tyProc: if containsGarbageCollectedRef(dest.t): @@ -357,19 +357,19 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = let a = optAsgnLoc(dest, dest.t, "ClE_0".rope) let b = optAsgnLoc(src, dest.t, "ClE_0".rope) genRefAssign(p, a, b) - linefmt(p, cpsStmts, "$1.ClP_0 = $2.ClP_0;\n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1.ClP_0 = $2.ClP_0;$n", [rdLoc(dest), rdLoc(src)]) else: - linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tyTuple: if containsGarbageCollectedRef(dest.t): if dest.t.len <= 4: genOptAsgnTuple(p, dest, src, flags) else: genGenericAsgn(p, dest, src, flags) else: - linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tyObject: # XXX: check for subtyping? if ty.isImportedCppType: - linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) elif not isObjLackingTypeField(ty): genGenericAsgn(p, dest, src, flags) elif containsGarbageCollectedRef(ty): @@ -380,13 +380,13 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: genGenericAsgn(p, dest, src, flags) else: - linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tyArray: if containsGarbageCollectedRef(dest.t) and p.config.selectedGC notin {gcArc, gcOrc, gcHooks}: genGenericAsgn(p, dest, src, flags) else: linefmt(p, cpsStmts, - "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));\n", + "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", [rdLoc(dest), rdLoc(src), getTypeDesc(p.module, dest.t)]) of tyOpenArray, tyVarargs: # open arrays are always on the stack - really? What if a sequence is @@ -395,30 +395,30 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = genOpenArrayConv(p, dest, src) elif containsGarbageCollectedRef(dest.t): linefmt(p, cpsStmts, # XXX: is this correct for arrays? - "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);\n", + "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) else: linefmt(p, cpsStmts, # bug #4799, keep the nimCopyMem for a while #"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);\n", - "$1 = $2;\n", + "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tySet: if mapSetType(p.config, ty) == ctArray: - linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);\n", + linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: - linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCstring, tyInt..tyUInt64, tyRange, tyVar, tyLent, tyNil: - linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genAssignment: " & $ty.kind) if optMemTracker in p.options and dest.storage in {OnHeap, OnUnknown}: #writeStackTrace() #echo p.currLineInfo, " requesting" - linefmt(p, cpsStmts, "#memTrackerWrite((void*)$1, $2, $3, $4);\n", + linefmt(p, cpsStmts, "#memTrackerWrite((void*)$1, $2, $3, $4);$n", [addrLoc(p.config, dest), getSize(p.config, dest.t), makeCString(toFullPath(p.config, p.currLineInfo)), p.currLineInfo.safeLineNm]) @@ -437,32 +437,32 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = case ty.kind of tyPtr, tyRef, tyProc, tyTuple, tyObject, tyArray: # XXX optimize this - linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);\n", + linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", [addrLoc(p.config, dest), addrLocOrTemp(src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tySequence, tyString: if optTinyRtti in p.config.globalOptions: - linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);\n", + linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", [addrLoc(p.config, dest), addrLocOrTemp(src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) else: - linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);\n", + linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n", [addrLoc(p.config, dest), rdLoc(src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tyOpenArray, tyVarargs: linefmt(p, cpsStmts, - "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);\n", + "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", [addrLoc(p.config, dest), addrLocOrTemp(src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tySet: if mapSetType(p.config, ty) == ctArray: - linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);\n", + linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", [rdLoc(dest), rdLoc(src), getSize(p.config, dest.t)]) else: - linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) of tyPointer, tyChar, tyBool, tyEnum, tyCstring, tyInt..tyUInt64, tyRange, tyVar, tyLent: - linefmt(p, cpsStmts, "$1 = $2;\n", [rdLoc(dest), rdLoc(src)]) + linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) else: internalError(p.config, "genDeepCopy: " & $ty.kind) proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) = @@ -507,14 +507,14 @@ proc binaryStmt(p: BProc, e: PNode, d: var TLoc, op: string) = if d.k != locNone: internalError(p.config, e.info, "binaryStmt") initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) - lineCg(p, cpsStmts, "$1 $2 $3;\n", [rdLoc(a), op, rdLoc(b)]) + lineCg(p, cpsStmts, "$1 $2 $3;$n", [rdLoc(a), op, rdLoc(b)]) proc binaryStmtAddr(p: BProc, e: PNode, d: var TLoc, cpname: string) = var a, b: TLoc if d.k != locNone: internalError(p.config, e.info, "binaryStmtAddr") initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) - lineCg(p, cpsStmts, "#$1($2, $3);\n", [cpname, byRefLoc(p, a), rdLoc(b)]) + lineCg(p, cpsStmts, "#$1($2, $3);$n", [cpname, byRefLoc(p, a), rdLoc(b)]) template unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = var a: TLoc @@ -1193,9 +1193,9 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = expr(p, e[1], tmp) L = getLabel(p) if m == mOr: - lineF(p, cpsStmts, "if ($1) goto $2;\n", [rdLoc(tmp), L]) + lineF(p, cpsStmts, "if ($1) goto $2;$n", [rdLoc(tmp), L]) else: - lineF(p, cpsStmts, "if (!($1)) goto $2;\n", [rdLoc(tmp), L]) + lineF(p, cpsStmts, "if (!($1)) goto $2;$n", [rdLoc(tmp), L]) expr(p, e[2], tmp) fixLabel(p, L) if d.k == locNone: @@ -1276,15 +1276,15 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e[i + 1], a) if skipTypes(e[i + 1].typ, abstractVarRange).kind == tyChar: inc(L) - appends.add(ropecg(p.module, "#appendChar($1, $2);\n", [strLoc(p, tmp), rdLoc(a)])) + appends.add(ropecg(p.module, "#appendChar($1, $2);$n", [strLoc(p, tmp), rdLoc(a)])) else: if e[i + 1].kind in {nkStrLit..nkTripleStrLit}: inc(L, e[i + 1].strVal.len) else: lens.add(lenExpr(p, a)) lens.add(" + ") - appends.add(ropecg(p.module, "#appendString($1, $2);\n", [strLoc(p, tmp), rdLoc(a)])) - linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);\n", [tmp.r, lens, L]) + appends.add(ropecg(p.module, "#appendString($1, $2);$n", [strLoc(p, tmp), rdLoc(a)])) + linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, L]) p.s(cpsStmts).add appends if d.k == locNone: d = tmp diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 22428a749f..6ce632a2ae 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -61,7 +61,7 @@ proc startBlockInternal(p: BProc): int {.discardable.} = p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16 p.blocks[result].nestedExceptStmts = p.inExceptBlockLen.int16 -template startBlock(p: BProc, start: FormatStr = "{\n", +template startBlock(p: BProc, start: FormatStr = "{$n", args: varargs[Rope]): int = lineCg(p, cpsStmts, start, args) startBlockInternal(p) @@ -173,8 +173,7 @@ proc endBlock(p: BProc) = if p.blocks[topBlock].label.len != 0: blockEnd.addf("} $1: ;$n", [p.blocks[topBlock].label]) else: - #blockEnd.addf("}$n", []) - blockEnd.add("}\n") + blockEnd.addf("}$n", []) endBlock(p, blockEnd) proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} = @@ -447,9 +446,9 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = [rdLoc(a), lelse]) if p.module.compileToCpp: # avoid "jump to label crosses initialization" error: - p.s(cpsStmts).add "{\n" + p.s(cpsStmts).add "{" expr(p, it[1], d) - p.s(cpsStmts).add "}\n" + p.s(cpsStmts).add "}" else: expr(p, it[1], d) endBlock(p) @@ -608,13 +607,13 @@ proc genWhileStmt(p: BProc, t: PNode) = loopBody = loopBody[1] genComputedGoto(p, loopBody) else: - p.breakIdx = startBlock(p, "while (1) {\n") + p.breakIdx = startBlock(p, "while (1) {$n") p.blocks[p.breakIdx].isLoop = true initLocExpr(p, t[0], a) if (t[0].kind != nkIntLit) or (t[0].intVal == 0): lineF(p, cpsStmts, "if (!$1) goto ", [rdLoc(a)]) assignLabel(p.blocks[p.breakIdx], p.s(cpsStmts)) - appcg(p, cpsStmts, ";\n", []) + appcg(p, cpsStmts, ";$n", []) genStmts(p, loopBody) if optProfiler in p.options: @@ -978,8 +977,8 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) = of tyCstring: genStringCase(p, t, tyCstring, d) of tyFloat..tyFloat128: - genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;\n", - "if ($1 == $2) goto $3;\n") + genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n", + "if ($1 == $2) goto $3;$n") else: if t[0].kind == nkSym and sfGoto in t[0].sym.flags: genGotoForCase(p, t) @@ -990,9 +989,9 @@ proc genRestoreFrameAfterException(p: BProc) = if optStackTrace in p.module.config.options: if hasCurFramePointer notin p.flags: p.flags.incl hasCurFramePointer - p.procSec(cpsLocals).add(ropecg(p.module, "\tTFrame* _nimCurFrame;\n", [])) - p.procSec(cpsInit).add(ropecg(p.module, "\t_nimCurFrame = #getFrame();\n", [])) - linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);\n", []) + p.procSec(cpsLocals).add(ropecg(p.module, "\tTFrame* _nimCurFrame;$n", [])) + p.procSec(cpsInit).add(ropecg(p.module, "\t_nimCurFrame = #getFrame();$n", [])) + linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n", []) proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = #[ code to generate: @@ -1028,26 +1027,25 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = inc(p.labels, 2) let etmp = p.labels - p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;\n", [etmp])) + p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;$n", [etmp])) let fin = if t[^1].kind == nkFinally: t[^1] else: nil p.nestedTryStmts.add((fin, false, 0.Natural)) if t.kind == nkHiddenTryStmt: - lineCg(p, cpsStmts, "try {\n", []) + lineCg(p, cpsStmts, "try {$n", []) expr(p, t[0], d) - lineCg(p, cpsStmts, "}\n", []) + lineCg(p, cpsStmts, "}$n", []) else: - startBlock(p, "try {\n") + startBlock(p, "try {$n") expr(p, t[0], d) endBlock(p) # First pass: handle Nim based exceptions: - #lineCg(p, cpsStmts, "catch (#Exception* T$1_) {\n", [etmp+1]) - startBlock(p, "catch (#Exception* T$1_) {\n", rope(etmp+1)) + lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1]) genRestoreFrameAfterException(p) # an unhandled exception happened! - lineCg(p, cpsStmts, "T$1_ = std::current_exception();\n", [etmp]) + lineCg(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) p.nestedTryStmts[^1].inExcept = true var hasImportedCppExceptions = false var i = 1 @@ -1063,9 +1061,9 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = if hasIf: lineF(p, cpsStmts, "else ", []) startBlock(p) # we handled the error: - linefmt(p, cpsStmts, "T$1_ = nullptr;\n", [etmp]) + linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp]) expr(p, t[i][0], d) - linefmt(p, cpsStmts, "#popCurrentException();\n", []) + linefmt(p, cpsStmts, "#popCurrentException();$n", []) endBlock(p) else: var orExpr = newRopeAppender() @@ -1090,25 +1088,24 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = if orExpr.len != 0: if hasIf: - startBlock(p, "else if ($1) {\n", [orExpr]) + startBlock(p, "else if ($1) {$n", [orExpr]) else: - startBlock(p, "if ($1) {\n", [orExpr]) + startBlock(p, "if ($1) {$n", [orExpr]) hasIf = true if exvar != nil: fillLocalName(p, exvar.sym) fillLoc(exvar.sym.loc, locTemp, exvar, OnStack) - linefmt(p, cpsStmts, "$1 $2 = T$3_;\n", [getTypeDesc(p.module, exvar.sym.typ), + linefmt(p, cpsStmts, "$1 $2 = T$3_;$n", [getTypeDesc(p.module, exvar.sym.typ), rdLoc(exvar.sym.loc), rope(etmp+1)]) # we handled the error: - linefmt(p, cpsStmts, "T$1_ = nullptr;\n", [etmp]) + linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp]) expr(p, t[i][^1], d) - linefmt(p, cpsStmts, "#popCurrentException();\n", []) + linefmt(p, cpsStmts, "#popCurrentException();$n", []) endBlock(p) inc(i) if hasIf and not hasElse: - linefmt(p, cpsStmts, "else throw;\n", [etmp]) - #linefmt(p, cpsStmts, "}\n", []) - endBlock(p) + linefmt(p, cpsStmts, "else throw;$n", [etmp]) + linefmt(p, cpsStmts, "}$n", []) # Second pass: handle C++ based exceptions: template genExceptBranchBody(body: PNode) {.dirty.} = @@ -1127,7 +1124,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = if t[i].len == 1: # general except section: - startBlock(p, "catch (...) {\n", []) + startBlock(p, "catch (...) {$n", []) genExceptBranchBody(t[i][0]) endBlock(p) catchAllPresent = true @@ -1140,11 +1137,11 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = let exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:` fillLocalName(p, exvar.sym) fillLoc(exvar.sym.loc, locTemp, exvar, OnStack) - startBlock(p, "catch ($1& $2) {\n", getTypeDesc(p.module, typeNode.typ), rdLoc(exvar.sym.loc)) + startBlock(p, "catch ($1& $2) {$n", getTypeDesc(p.module, typeNode.typ), rdLoc(exvar.sym.loc)) genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type endBlock(p) elif isImportedException(typeNode.typ, p.config): - startBlock(p, "catch ($1&) {\n", getTypeDesc(p.module, t[i][j].typ)) + startBlock(p, "catch ($1&) {$n", getTypeDesc(p.module, t[i][j].typ)) genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type endBlock(p) @@ -1153,14 +1150,14 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = # general finally block: if t.len > 0 and t[^1].kind == nkFinally: if not catchAllPresent: - startBlock(p, "catch (...) {\n", []) + startBlock(p, "catch (...) {$n", []) genRestoreFrameAfterException(p) - linefmt(p, cpsStmts, "T$1_ = std::current_exception();\n", [etmp]) + linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp]) endBlock(p) startBlock(p) genStmts(p, t[^1][0]) - linefmt(p, cpsStmts, "if (T$1_) std::rethrow_exception(T$1_);\n", [etmp]) + linefmt(p, cpsStmts, "if (T$1_) std::rethrow_exception(T$1_);$n", [etmp]) endBlock(p) proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index c164a80d71..2d1f632a26 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -524,14 +524,14 @@ proc genRecordFieldsAux(m: BModule; n: PNode, else: unionBody.addf("#pragma pack(push, 1)$nstruct{", []) unionBody.add(a) - unionBody.addf("} $1;\n", [structName]) + unionBody.addf("} $1;$n", [structName]) if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props: - unionBody.addf("#pragma pack(pop)\n", []) + unionBody.addf("#pragma pack(pop)$n", []) else: genRecordFieldsAux(m, k, rectype, check, unionBody, unionPrefix) else: internalError(m.config, "genRecordFieldsAux(record case branch)") if unionBody != "": - result.addf("union{\n$1};\n", [unionBody]) + result.addf("union{\n$1};$n", [unionBody]) of nkSym: let field = n.sym if field.typ.kind == tyVoid: return @@ -548,20 +548,20 @@ proc genRecordFieldsAux(m: BModule; n: PNode, let fieldType = field.loc.lode.typ.skipTypes(abstractInst) if fieldType.kind == tyUncheckedArray: - result.addf("\t$1 $2[SEQ_DECL_SIZE];\n", + result.addf("\t$1 $2[SEQ_DECL_SIZE];$n", [getTypeDescAux(m, fieldType.elemType, check, skField), sname]) elif fieldType.kind == tySequence: # we need to use a weak dependency here for trecursive_table. - result.addf("\t$1$3 $2;\n", [getTypeDescWeak(m, field.loc.t, check, skField), sname, noAlias]) + result.addf("\t$1$3 $2;$n", [getTypeDescWeak(m, field.loc.t, check, skField), sname, noAlias]) elif field.bitsize != 0: - result.addf("\t$1$4 $2:$3;\n", [getTypeDescAux(m, field.loc.t, check, skField), sname, rope($field.bitsize), noAlias]) + result.addf("\t$1$4 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, rope($field.bitsize), noAlias]) else: # don't use fieldType here because we need the # tyGenericInst for C++ template support if fieldType.isOrHasImportedCppType(): - result.addf("\t$1$3 $2{};\n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) + result.addf("\t$1$3 $2{};$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) else: - result.addf("\t$1$3 $2;\n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) + result.addf("\t$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) else: internalError(m.config, n.info, "genRecordFieldsAux()") proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope = @@ -584,30 +584,30 @@ proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope, if typ.kind == tyObject: if typ[0] == nil: if lacksMTypeField(typ): - appcg(m, result, " {\n", []) + appcg(m, result, " {$n", []) else: if optTinyRtti in m.config.globalOptions: - appcg(m, result, " {$n#TNimTypeV2* m_type;\n", []) + appcg(m, result, " {$n#TNimTypeV2* m_type;$n", []) else: - appcg(m, result, " {$n#TNimType* m_type;\n", []) + appcg(m, result, " {$n#TNimType* m_type;$n", []) hasField = true elif m.compileToCpp: - appcg(m, result, " : public $1 {\n", [baseType]) + appcg(m, result, " : public $1 {$n", [baseType]) if typ.isException and m.config.exc == excCpp: when false: - appcg(m, result, "virtual void raise() { throw *this; }\n", []) # required for polymorphic exceptions + appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions if typ.sym.magic == mException: # Add cleanup destructor to Exception base class - appcg(m, result, "~$1();\n", [name]) + appcg(m, result, "~$1();$n", [name]) # define it out of the class body and into the procs section so we don't have to # artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR) - appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}\n", [name]) + appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name]) hasField = true else: - appcg(m, result, " {$n $1 Sup;\n", [baseType]) + appcg(m, result, " {$n $1 Sup;$n", [baseType]) hasField = true else: - result.addf(" {\n", [name]) + result.addf(" {$n", [name]) proc getRecordDesc(m: BModule; typ: PType, name: Rope, check: var IntSet): Rope = @@ -629,7 +629,7 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope, result.add(getRecordDescAux(m, typ, name, baseType, check, hasField)) let desc = getRecordFields(m, typ, check) if desc == "" and not hasField: - result.addf("char dummy;\n", []) + result.addf("char dummy;$n", []) else: result.add(desc) result.add("};\L") diff --git a/compiler/cgen.nim b/compiler/cgen.nim index db2f280f1a..a576542396 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -276,7 +276,7 @@ proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) = r.addf("\n#line $2 $1\n", [rope(makeSingleLineCString(filename)), rope(line)]) -proc genCLineDir(r: var Rope, filename: string, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex; lastLine: uint16) = +proc genCLineDir(r: var Rope, filename: string, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) = assert line >= 0 if optLineDir in p.config.options and line > 0: if lastFileIndex == info.fileIndex: @@ -296,18 +296,24 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool = p.lastLineInfo.fileIndex = info.fileIndex result = true +proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) = + if optLineDir in conf.options: + let lastFileIndex = p.lastLineInfo.fileIndex + if freshLineInfo(p, info): + genCLineDir(r, toFullPath(conf, info), info.safeLineNm, p, info, lastFileIndex) + proc genLineDir(p: BProc, t: PNode) = let line = t.info.safeLineNm if optEmbedOrigSrc in p.config.globalOptions: p.s(cpsStmts).add("//" & sourceLine(p.config, t.info) & "\L") + let lastFileIndex = p.lastLineInfo.fileIndex + let freshLine = freshLineInfo(p, t.info) + if freshLine: + genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p, t.info, lastFileIndex) if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx: - let lastFileIndex = p.lastLineInfo.fileIndex - let lastLine = p.lastLineInfo.line - let freshLine = freshLineInfo(p, t.info) if freshLine: - genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p, t.info, lastFileIndex, lastLine) if lastFileIndex == t.info.fileIndex: linefmt(p, cpsStmts, "nimln_($1);\n", [line]) @@ -473,9 +479,9 @@ proc resetLoc(p: BProc, loc: var TLoc) = let atyp = skipTypes(loc.t, abstractInst) if atyp.kind in {tyVar, tyLent}: - linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;\n", [rdLoc(loc)]) + linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)]) else: - linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;\n", [rdLoc(loc)]) + linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): if containsGcRef: var nilLoc: TLoc @@ -488,7 +494,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = if loc.storage != OnStack and containsGcRef: specializeReset(p, loc) when false: - linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);\n", + linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", [addrLoc(p.config, loc), genTypeInfoV1(p.module, loc.t, loc.lode.info)]) # XXX: generated reset procs should not touch the m_type # field, so disabling this should be safe: @@ -496,7 +502,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = else: # array passed as argument decayed into pointer, bug #7332 # so we use getTypeDesc here rather than rdLoc(loc) - linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));\n", + linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", [addrLoc(p.config, loc), getTypeDesc(p.module, loc.t, mapTypeChooser(loc))]) # XXX: We can be extra clever here and call memset only @@ -506,7 +512,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = let typ = loc.t if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}: - linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;\n", [rdLoc(loc)]) + linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): if containsGarbageCollectedRef(loc.t): var nilLoc: TLoc @@ -514,14 +520,14 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = nilLoc.r = rope("NIM_NIL") genRefAssign(p, loc, nilLoc) else: - linefmt(p, cpsStmts, "$1 = ($2)0;\n", [rdLoc(loc), + linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))]) else: if not isTemp or containsGarbageCollectedRef(loc.t): # don't use nimZeroMem for temporary values for performance if we can # avoid it: if not isOrHasImportedCppType(typ): - linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));\n", + linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", [addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))]) genObjectInit(p, cpsStmts, loc.t, loc, constructObj) @@ -541,9 +547,9 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = inc(p.labels) result.r = "T" & rope(p.labels) & "_" if p.module.compileToCpp and isOrHasImportedCppType(t): - linefmt(p, cpsLocals, "$1 $2{};\n", [getTypeDesc(p.module, t, skVar), result.r]) + linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, skVar), result.r]) else: - linefmt(p, cpsLocals, "$1 $2;\n", [getTypeDesc(p.module, t, skVar), result.r]) + linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r]) result.k = locTemp result.lode = lodeTyp t result.storage = OnStack @@ -561,7 +567,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) = inc(p.labels) result.r = "T" & rope(p.labels) & "_" - linefmt(p, cpsStmts, "$1 $2 = $3;\n", [getTypeDesc(p.module, t, skVar), result.r, value]) + linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value]) result.k = locTemp result.lode = lodeTyp t result.storage = OnStack @@ -570,7 +576,7 @@ proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) = proc getIntTemp(p: BProc, result: var TLoc) = inc(p.labels) result.r = "T" & rope(p.labels) & "_" - linefmt(p, cpsLocals, "NI $1;\n", [result.r]) + linefmt(p, cpsLocals, "NI $1;$n", [result.r]) result.k = locTemp result.storage = OnStack result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt) @@ -585,13 +591,7 @@ proc localVarDecl(p: BProc; n: PNode): Rope = if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: result.addf("NIM_ALIGN($1) ", [rope(s.alignment)]) - if optLineDir in p.config.options: - let line = n.info.safeLineNm - let lastFileIndex = p.lastLineInfo.fileIndex - let lastLine = p.lastLineInfo.line - discard freshLineInfo(p, n.info) - genCLineDir(result, toFullPath(p.config, n.info), line, p, n.info, lastFileIndex, lastLine) - addIndent(p, result) + genCLineDir(result, p, n.info, p.config) result.add getTypeDesc(p.module, s.typ, skVar) if s.constraint.isNil: @@ -609,8 +609,8 @@ proc assignLocalVar(p: BProc, n: PNode) = #assert(s.loc.k == locNone) # not yet assigned # this need not be fulfilled for inline procs; they are regenerated # for each module that uses them! - #let nl = if optLineDir in p.config.options: "" else: "\n" - let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};\n" else: ";\n") + let nl = if optLineDir in p.config.options: "" else: "\n" + let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl line(p, cpsLocals, decl) include ccgthreadvars @@ -707,7 +707,6 @@ proc getLabel(p: BProc): TLabel = result = "LA" & rope(p.labels) & "_" proc fixLabel(p: BProc, labl: TLabel) = - #lineF(p, cpsStmts, "$1: ;$n", [labl]) p.s(cpsStmts).add("$1: ;$n" % [labl]) proc genVarPrototype(m: BModule, n: PNode) @@ -761,7 +760,7 @@ $1define nimfr_(proc, file) \ appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"]) cgsym(p.module, "nimFrame") - result = ropecg(p.module, "\tnimfr_($1, $2);\n", [procname, filename]) + result = ropecg(p.module, "\tnimfr_($1, $2);$n", [procname, filename]) proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope = cgsym(p.module, "nimFrame") @@ -774,7 +773,7 @@ proc deinitFrameNoDebug(p: BProc; frame: Rope): Rope = result = ropecg(p.module, "\t#popFrameOfAddr(&$1);$n", [frame]) proc deinitFrame(p: BProc): Rope = - result = ropecg(p.module, "\t#popFrame();\n", []) + result = ropecg(p.module, "\t#popFrame();$n", []) include ccgexprs @@ -1137,6 +1136,9 @@ proc genProcAux*(m: BModule, prc: PSym) = if sfInjectDestructors in prc.flags: procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody) + let tmpInfo = prc.info + discard freshLineInfo(p, prc.info) + if sfPure notin prc.flags and prc.typ[0] != nil: if resultPos >= prc.ast.len: internalError(m.config, prc.info, "proc has no result symbol") @@ -1148,13 +1150,13 @@ proc genProcAux*(m: BModule, prc: PSym) = var decl = localVarDecl(p, resNode) var a: TLoc initLocExprSingleUse(p, val, a) - linefmt(p, cpsStmts, "$1 = $2;\n", [decl, rdLoc(a)]) + linefmt(p, cpsStmts, "$1 = $2;$n", [decl, rdLoc(a)]) else: # declare the result symbol: assignLocalVar(p, resNode) assert(res.loc.r != "") initLocalVar(p, res, immediateAsgn=false) - returnStmt = ropecg(p.module, "\treturn $1;\n", [rdLoc(res.loc)]) + returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)]) else: fillResult(p.config, resNode, prc.typ) assignParam(p, res, prc.typ[0]) @@ -1179,6 +1181,8 @@ proc genProcAux*(m: BModule, prc: PSym) = closureSetup(p, prc) genProcBody(p, procBody) + prc.info = tmpInfo + var generatedProc: Rope generatedProc.genCLineDir prc.info, m.config if isNoReturn(p.module, prc): @@ -1195,7 +1199,7 @@ proc genProcAux*(m: BModule, prc: PSym) = # This fixes the use of methods and also the case when 2 functions within the same module # call each other using directly the "_actual" versions (an optimization) - see issue #11608 m.s[cfsProcHeaders].addf("$1;\n", [header]) - generatedProc.add ropecg(p.module, "$1 {\n", [header]) + generatedProc.add ropecg(p.module, "$1 {$n", [header]) if optStackTrace in prc.options: generatedProc.add(p.s(cpsLocals)) var procname = makeCString(prc.name.s) @@ -1210,7 +1214,7 @@ proc genProcAux*(m: BModule, prc: PSym) = if beforeRetNeeded in p.flags: generatedProc.add("{") generatedProc.add(p.s(cpsInit)) generatedProc.add(p.s(cpsStmts)) - if beforeRetNeeded in p.flags: generatedProc.add("\t}\nBeforeRet_: ;\n") + if beforeRetNeeded in p.flags: generatedProc.add("\t}BeforeRet_: ;\n") if optStackTrace in prc.options: generatedProc.add(deinitFrame(p)) generatedProc.add(returnStmt) generatedProc.add("}\n") From acfa7849d3b45e217b998ae4734c759b2020c285 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Thu, 4 May 2023 13:30:58 +0100 Subject: [PATCH 047/489] Benchmark CI: drop id (#21787) --- .github/workflows/ci_bench.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci_bench.yml b/.github/workflows/ci_bench.yml index 09f01242fd..68f0007228 100644 --- a/.github/workflows/ci_bench.yml +++ b/.github/workflows/ci_bench.yml @@ -70,7 +70,6 @@ jobs: run: ./minimize/minimize ci-bench - name: 'Restore minimize cached database' - id: minimize-cache uses: actions/cache/restore@v3 with: path: minimize.csv @@ -84,7 +83,6 @@ jobs: if: | github.event_name == 'push' && github.ref == 'refs/heads/devel' && matrix.target == 'linux' - id: minimize-cache uses: actions/cache/save@v3 with: path: minimize.csv From 79ac242c7206b71ff1ea8ea8d1e499c610a1403f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 4 May 2023 16:42:04 +0200 Subject: [PATCH 048/489] fixes #21780 [backport:1.6] (#21785) * fixes #21780 [backport:1.6] * complete patch --- lib/system/seqs_v2.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index d7ace446d9..f176c0a4a7 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -91,7 +91,7 @@ proc grow*[T](x: var seq[T]; newLen: Natural; value: T) = #sysAssert newLen >= x.len, "invalid newLen parameter for 'grow'" if newLen <= oldLen: return var xu = cast[ptr NimSeqV2[T]](addr x) - if xu.p == nil or xu.p.cap < newLen: + if xu.p == nil or (xu.p.cap and not strlitFlag) < newLen: xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T), alignof(T))) xu.len = newLen for i in oldLen .. newLen-1: @@ -107,7 +107,7 @@ proc add*[T](x: var seq[T]; value: sink T) {.magic: "AppendSeqElem", noSideEffec {.cast(noSideEffect).}: let oldLen = x.len var xu = cast[ptr NimSeqV2[T]](addr x) - if xu.p == nil or xu.p.cap < oldLen+1: + if xu.p == nil or (xu.p.cap and not strlitFlag) < oldLen+1: xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, 1, sizeof(T), alignof(T))) xu.len = oldLen+1 # .nodestroy means `xu.p.data[oldLen] = value` is compiled into a @@ -124,7 +124,7 @@ proc setLen[T](s: var seq[T], newlen: Natural) = let oldLen = s.len if newlen <= oldLen: return var xu = cast[ptr NimSeqV2[T]](addr s) - if xu.p == nil or xu.p.cap < newlen: + if xu.p == nil or (xu.p.cap and not strlitFlag) < newlen: xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T))) xu.len = newlen for i in oldLen.. Date: Thu, 4 May 2023 23:40:37 +0800 Subject: [PATCH 049/489] build documentation for `checksums/md5` and `checksums/sha1` (#21791) * build documentation for md5 and sha1 * fixes documentation reference --- koch.nim | 2 +- lib/pure/hashes.nim | 2 +- lib/pure/md5.nim | 2 +- tools/kochdocs.nim | 6 +++++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/koch.nim b/koch.nim index 79ca54c811..b6788e6d06 100644 --- a/koch.nim +++ b/koch.nim @@ -13,7 +13,7 @@ const NimbleStableCommit = "168416290e49023894fc26106799d6f1fc964a2d" # master # examples of possible values: #head, #ea82b54, 1.2.3 FusionStableHash = "#372ee4313827ef9f2ea388840f7d6b46c2b1b014" - ChecksumsStableCommit = "3fa15df7d27ecef624ed932d60f63d6a8949618d" + ChecksumsStableCommit = "b4c73320253f78e3a265aec6d9e8feb83f97c77b" HeadHash = "#head" when not defined(windows): const diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 56c3601380..8e5770a71f 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -62,7 +62,7 @@ runnableExamples: ## ======== ## * `md5 module `_ for the MD5 checksum algorithm ## * `base64 module `_ for a Base64 encoder and decoder -## * `std/sha1 module `_ for the SHA-1 checksum algorithm +## * `sha1 module `_ for the SHA-1 checksum algorithm ## * `tables module `_ for hash tables import std/private/since diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim index 81c85a07c2..c65a9c2daf 100644 --- a/lib/pure/md5.nim +++ b/lib/pure/md5.nim @@ -14,7 +14,7 @@ ## See also ## ======== ## * `base64 module`_ for a Base64 encoder and decoder -## * `std/sha1 module `_ for the SHA-1 checksum algorithm +## * `sha1 module `_ for the SHA-1 checksum algorithm ## * `hashes module`_ for efficient computations of hash values ## for diverse Nim types diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 3953025f43..bab2de1e47 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -150,6 +150,8 @@ lib/posix/posix_other_consts.nim lib/posix/posix_freertos_consts.nim lib/posix/posix_openbsd_amd64.nim lib/posix/posix_haiku.nim +lib/pure/md5.nim +lib/std/sha1.nim """.splitWhitespace() officialPackagesList = """ @@ -161,6 +163,8 @@ pkgs/db_connector/src/db_connector/db_mysql.nim pkgs/db_connector/src/db_connector/db_odbc.nim pkgs/db_connector/src/db_connector/db_postgres.nim pkgs/db_connector/src/db_connector/db_sqlite.nim +pkgs/checksums/src/checksums/md5.nim +pkgs/checksums/src/checksums/sha1.nim """.splitWhitespace() officialPackagesListWithoutIndex = """ @@ -335,7 +339,7 @@ proc buildJS(): string = proc buildDocsDir*(args: string, dir: string) = let args = nimArgs & " " & args let docHackJsSource = buildJS() - gitClonePackages(@["asyncftpclient", "punycode", "smtp", "db_connector"]) + gitClonePackages(@["asyncftpclient", "punycode", "smtp", "db_connector", "checksums"]) createDir(dir) buildDocSamples(args, dir) From e92d7681bbdff1fbd28b50aa4c40270b13c48ca1 Mon Sep 17 00:00:00 2001 From: metagn Date: Fri, 5 May 2023 08:28:06 +0300 Subject: [PATCH 050/489] consistent use of scForceOpen for generic dot field symbols (#21738) * always force open generic dot field symbols? fixes #21724 but might break code * alternative, should fix CI * other alternative, add test for previous CI failure * not needed * make sure call doesn't compile too * ok actual second test * ok final actual correct test * apply performance idea * don't make fromDotExpr static --- compiler/semgnrc.nim | 22 ++++++------- tests/generics/mdotlookup.nim | 5 +++ tests/generics/tbaddeprecated.nim | 55 +++++++++++++++++++++++++++++++ tests/generics/timports.nim | 3 +- 4 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 tests/generics/tbaddeprecated.nim diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 7241a47020..543bd1132d 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -61,12 +61,19 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, fromDotExpr=false): PNode = semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody) incl(s.flags, sfUsed) + template maybeDotChoice(c: PContext, n: PNode, s: PSym, fromDotExpr: bool) = + if fromDotExpr: + result = symChoice(c, n, s, scForceOpen) + if result.len == 1: + result.transitionSonsKind(nkClosedSymChoice) + else: + result = symChoice(c, n, s, scOpen) case s.kind of skUnknown: # Introduced in this pass! Leave it as an identifier. result = n - of skProc, skFunc, skMethod, skIterator, skConverter, skModule: - result = symChoice(c, n, s, scOpen) + of skProc, skFunc, skMethod, skIterator, skConverter, skModule, skEnumField: + maybeDotChoice(c, n, s, fromDotExpr) of skTemplate, skMacro: # alias syntax, see semSym for skTemplate, skMacro if sfNoalias notin s.flags and not fromDotExpr: @@ -79,7 +86,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result = semGenericStmt(c, result, {}, ctx) discard c.friendModules.pop() else: - result = symChoice(c, n, s, scOpen) + maybeDotChoice(c, n, s, fromDotExpr) of skGenericParam: if s.typ != nil and s.typ.kind == tyStatic: if s.typ.n != nil: @@ -99,8 +106,6 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, else: result = n onUse(n.info, s) - of skEnumField: - result = symChoice(c, n, s, scOpen) else: result = newSymNode(s, n.info) onUse(n.info, s) @@ -157,12 +162,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, result = newDot(result, symChoice(c, n, s, scForceOpen)) else: let syms = semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true) - if syms.kind == nkSym: - let choice = symChoice(c, n, s, scForceOpen) - choice.transitionSonsKind(nkClosedSymChoice) - result = newDot(result, choice) - else: - result = newDot(result, syms) + result = newDot(result, syms) proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) = let s = newSymS(skUnknown, getIdentNode(c, n), c) diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim index 3112c133f1..b69a56dafd 100644 --- a/tests/generics/mdotlookup.nim +++ b/tests/generics/mdotlookup.nim @@ -14,3 +14,8 @@ var intset = initHashSet[int]() proc fn*[T](a: T) = if a in intset: echo("true") else: echo("false") + +import strutils + +proc doStrip*[T](a: T): string = + result = ($a).strip() diff --git a/tests/generics/tbaddeprecated.nim b/tests/generics/tbaddeprecated.nim new file mode 100644 index 0000000000..335234a25b --- /dev/null +++ b/tests/generics/tbaddeprecated.nim @@ -0,0 +1,55 @@ +discard """ + output: ''' +not deprecated +not deprecated +not error +not error +''' +""" + +# issue #21724 + +block: # deprecated + {.push warningAsError[Deprecated]: on.} + type + SomeObj = object + hey: bool + proc hey() {.deprecated: "Shouldn't use this".} = echo "hey" + proc gen(o: auto) = + doAssert not compiles(o.hey()) + if o.hey: + echo "not deprecated" + gen(SomeObj(hey: true)) + doAssert not (compiles do: + proc hey(o: SomeObj) {.deprecated: "Shouldn't use this".} = echo "hey" + proc gen2(o: auto) = + if o.hey(): + echo "not deprecated" + gen2(SomeObj(hey: true))) + proc hey(o: SomeObj) {.deprecated: "Shouldn't use this".} = echo "hey" + proc gen3(o: auto) = + if o.hey: + echo "not deprecated" + gen3(SomeObj(hey: true)) + {.pop.} +block: # error + type + SomeObj = object + hey: bool + proc hey() {.error: "Shouldn't use this".} = echo "hey" + proc gen(o: auto) = + doAssert not compiles(o.hey()) + if o.hey: + echo "not error" + gen(SomeObj(hey: true)) + doAssert not (compiles do: + proc hey(o: SomeObj) {.error: "Shouldn't use this".} = echo "hey" + proc gen2(o: auto) = + if o.hey(): + echo "not error" + gen2(SomeObj(hey: true))) + proc hey(o: SomeObj) {.error: "Shouldn't use this".} = echo "hey" + proc gen3(o: auto) = + if o.hey: + echo "not error" + gen3(SomeObj(hey: true)) diff --git a/tests/generics/timports.nim b/tests/generics/timports.nim index 800ae7f889..b619c48cf6 100644 --- a/tests/generics/timports.nim +++ b/tests/generics/timports.nim @@ -31,12 +31,13 @@ block tclosed_sym: proc same(r:R, d:int) = echo "TEST1" doIt(Data[int](d:123), R()) +import strutils, unicode # ambiguous `strip` block tdotlookup: foo(7) # bug #1444 fn(4) - + doAssert doStrip(123) == "123" block tmodule_same_as_proc: # bug #1965 From 724866b14fad9398d1d003839037fe7cb21547eb Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 5 May 2023 19:58:29 +0800 Subject: [PATCH 051/489] adds `koch --skipIntegrityCheck boot` support (#21795) add `koch --skipIntegrityCheck boot` support --- changelogs/changelog_2_0_0.md | 1 + koch.nim | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 5110693d4b..1e0b427b68 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -502,3 +502,4 @@ e.g. instead of `--includeFile` and `--excludeFile` we have `--filename` and `--notFilename` respectively. Also the semantics become consistent for such positive/negative filters. +- koch now supports the `--skipIntegrityCheck` option. The command `koch --skipIntegrityCheck boot -d:release` always builds the compiler twice. diff --git a/koch.nim b/koch.nim index b6788e6d06..fe5427d43a 100644 --- a/koch.nim +++ b/koch.nim @@ -63,6 +63,7 @@ Options: --nim:path use specified path for nim binary --localdocs[:path] only build local documentations. If a path is not specified (or empty), the default is used. + --skipIntegrityCheck skips integrity check when booting the compiler Possible Commands: boot [options] bootstraps with given command line options distrohelper [bindir] helper for distro packagers @@ -295,7 +296,7 @@ proc thVersion(i: int): string = template doUseCpp(): bool = getEnv("NIM_COMPILE_TO_CPP", "false") == "true" -proc boot(args: string) = +proc boot(args: string, skipIntegrityCheck: bool) = ## bootstrapping is a process that involves 3 steps: ## 1. use csourcesAny to produce nim1.exe. This nim1.exe is buggy but ## rock solid for building a Nim compiler. It shouldn't be used for anything else. @@ -314,7 +315,8 @@ proc boot(args: string) = bundleChecksums(false) let nimStart = findStartNim().quoteShell() - for i in 0..2: + let times = 2 - ord(skipIntegrityCheck) + for i in 0..times: let defaultCommand = if useCpp: "cpp" else: "c" let bootOptions = if args.len == 0 or args.startsWith("-"): defaultCommand else: "" echo "iteration: ", i+1 @@ -345,7 +347,9 @@ proc boot(args: string) = return copyExe(output, (i+1).thVersion) copyExe(output, finalDest) - when not defined(windows): echo "[Warning] executables are still not equal" + when not defined(windows): + if not skipIntegrityCheck: + echo "[Warning] executables are still not equal" # -------------- clean -------------------------------------------------------- @@ -681,6 +685,7 @@ when isMainModule: latest = false localDocsOnly = false localDocsOut = "" + skipIntegrityCheck = false while true: op.next() case op.kind @@ -694,10 +699,12 @@ when isMainModule: localDocsOnly = true if op.val.len > 0: localDocsOut = op.val.absolutePath + of "skipintegritycheck": + skipIntegrityCheck = true else: showHelp(success = false) of cmdArgument: case normalize(op.key) - of "boot": boot(op.cmdLineRest) + of "boot": boot(op.cmdLineRest, skipIntegrityCheck) of "clean": clean(op.cmdLineRest) of "doc", "docs": buildDocs(op.cmdLineRest & " --d:nimPreviewSlimSystem " & paCode, localDocsOnly, localDocsOut) of "doc0", "docs0": From 07233ceca0fa220418f1691e70c9e8d49e440737 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 5 May 2023 20:23:38 +0800 Subject: [PATCH 052/489] fixes #21792; enable checks for sum, prod, cumsummed and cumsum (#21793) * enable checks for sum, prod, cumsummed and cumsum * fixes #21792 * add test cases --- lib/pure/math.nim | 123 +++++++++++++++++++++-------------------- tests/stdlib/tmath.nim | 16 +++++- 2 files changed, 78 insertions(+), 61 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index bea655a0e1..fc45a66416 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -326,68 +326,8 @@ func nextPowerOfTwo*(x: int): int = result = result or (result shr 1) result += 1 + ord(x <= 0) -func sum*[T](x: openArray[T]): T = - ## Computes the sum of the elements in `x`. - ## - ## If `x` is empty, 0 is returned. - ## - ## **See also:** - ## * `prod func <#prod,openArray[T]>`_ - ## * `cumsum func <#cumsum,openArray[T]>`_ - ## * `cumsummed func <#cumsummed,openArray[T]>`_ - runnableExamples: - doAssert sum([1, 2, 3, 4]) == 10 - doAssert sum([-4, 3, 5]) == 4 - for i in items(x): result = result + i -func prod*[T](x: openArray[T]): T = - ## Computes the product of the elements in `x`. - ## - ## If `x` is empty, 1 is returned. - ## - ## **See also:** - ## * `sum func <#sum,openArray[T]>`_ - ## * `fac func <#fac,int>`_ - runnableExamples: - doAssert prod([1, 2, 3, 4]) == 24 - doAssert prod([-4, 3, 5]) == -60 - - result = T(1) - for i in items(x): result = result * i - -func cumsummed*[T](x: openArray[T]): seq[T] = - ## Returns the cumulative (aka prefix) summation of `x`. - ## - ## If `x` is empty, `@[]` is returned. - ## - ## **See also:** - ## * `sum func <#sum,openArray[T]>`_ - ## * `cumsum func <#cumsum,openArray[T]>`_ for the in-place version - runnableExamples: - doAssert cumsummed([1, 2, 3, 4]) == @[1, 3, 6, 10] - - let xLen = x.len - if xLen == 0: - return @[] - result.setLen(xLen) - result[0] = x[0] - for i in 1 ..< xLen: result[i] = result[i - 1] + x[i] - -func cumsum*[T](x: var openArray[T]) = - ## Transforms `x` in-place (must be declared as `var`) into its - ## cumulative (aka prefix) summation. - ## - ## **See also:** - ## * `sum func <#sum,openArray[T]>`_ - ## * `cumsummed func <#cumsummed,openArray[T]>`_ for a version which - ## returns a cumsummed sequence - runnableExamples: - var a = [1, 2, 3, 4] - cumsum(a) - doAssert a == @[1, 3, 6, 10] - - for i in 1 ..< x.len: x[i] = x[i - 1] + x[i] when not defined(js): # C func sqrt*(x: float32): float32 {.importc: "sqrtf", header: "".} @@ -1133,6 +1073,69 @@ func sgn*[T: SomeNumber](x: T): int {.inline.} = {.pop.} {.pop.} +func sum*[T](x: openArray[T]): T = + ## Computes the sum of the elements in `x`. + ## + ## If `x` is empty, 0 is returned. + ## + ## **See also:** + ## * `prod func <#prod,openArray[T]>`_ + ## * `cumsum func <#cumsum,openArray[T]>`_ + ## * `cumsummed func <#cumsummed,openArray[T]>`_ + runnableExamples: + doAssert sum([1, 2, 3, 4]) == 10 + doAssert sum([-4, 3, 5]) == 4 + + for i in items(x): result = result + i + +func prod*[T](x: openArray[T]): T = + ## Computes the product of the elements in `x`. + ## + ## If `x` is empty, 1 is returned. + ## + ## **See also:** + ## * `sum func <#sum,openArray[T]>`_ + ## * `fac func <#fac,int>`_ + runnableExamples: + doAssert prod([1, 2, 3, 4]) == 24 + doAssert prod([-4, 3, 5]) == -60 + + result = T(1) + for i in items(x): result = result * i + +func cumsummed*[T](x: openArray[T]): seq[T] = + ## Returns the cumulative (aka prefix) summation of `x`. + ## + ## If `x` is empty, `@[]` is returned. + ## + ## **See also:** + ## * `sum func <#sum,openArray[T]>`_ + ## * `cumsum func <#cumsum,openArray[T]>`_ for the in-place version + runnableExamples: + doAssert cumsummed([1, 2, 3, 4]) == @[1, 3, 6, 10] + + let xLen = x.len + if xLen == 0: + return @[] + result.setLen(xLen) + result[0] = x[0] + for i in 1 ..< xLen: result[i] = result[i - 1] + x[i] + +func cumsum*[T](x: var openArray[T]) = + ## Transforms `x` in-place (must be declared as `var`) into its + ## cumulative (aka prefix) summation. + ## + ## **See also:** + ## * `sum func <#sum,openArray[T]>`_ + ## * `cumsummed func <#cumsummed,openArray[T]>`_ for a version which + ## returns a cumsummed sequence + runnableExamples: + var a = [1, 2, 3, 4] + cumsum(a) + doAssert a == @[1, 3, 6, 10] + + for i in 1 ..< x.len: x[i] = x[i - 1] + x[i] + func `^`*[T: SomeNumber](x: T, y: Natural): T = ## Computes `x` to the power of `y`. ## diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 8ddb09bf58..2076a6efff 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -439,6 +439,20 @@ template main() = doAssert lgamma(-0.0) == Inf doAssert lgamma(-1.0) == Inf - static: main() main() + +when not defined(js) and not defined(danger): + block: # bug #21792 + block: + type Digit = 0..9 + var x = [Digit 4, 7] + + doAssertRaises(RangeDefect): + discard sum(x) + + block: + var x = [int8 124, 127] + + doAssertRaises(OverflowDefect): + discard sum(x) From 85dbfc68b5c2020b32be9e3dc0d711b749fb5c6f Mon Sep 17 00:00:00 2001 From: Daniel Belmes <3631206+DanielBelmes@users.noreply.github.com> Date: Fri, 5 May 2023 05:27:33 -0700 Subject: [PATCH 053/489] Update the Nim Manual compile pragma with the second tuple form (#21773) * Update the nim manual compile pragma with the second tuple form of * Incorrectly put 'two' forms --- doc/manual.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/manual.md b/doc/manual.md index 31e69d0acc..2b982488f0 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -7597,10 +7597,16 @@ Compile pragma The `compile` pragma can be used to compile and link a C/C++ source file with the project: +This pragma can take three forms. The first is a simple file input: ```Nim {.compile: "myfile.cpp".} ``` +The second form is a tuple where the second arg is the output name strutils formatter: + ```Nim + {.compile: ("file.c", "$1.o").} + ``` + **Note**: Nim computes a SHA1 checksum and only recompiles the file if it has changed. One can use the `-f`:option: command-line option to force the recompilation of the file. From 10328e50a5450174d1226f8f362bd83f93b2ba6d Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Sat, 6 May 2023 19:03:45 +0900 Subject: [PATCH 054/489] Document about size pragma (#21794) * Document about size pragma * Fix typos * Fix manual.md * Update doc/manual.md --------- Co-authored-by: Andreas Rumpf --- doc/manual.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/doc/manual.md b/doc/manual.md index 2b982488f0..cb2509bd28 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -7485,6 +7485,37 @@ generates: ``` +size pragma +----------- +Nim automatically determines the size of an enum. +But when wrapping a C enum type, it needs to be of a specific size. +The `size pragma` allows specifying the size of the enum type. + + ```Nim + type + EventType* {.size: sizeof(uint32).} = enum + QuitEvent, + AppTerminating, + AppLowMemory + + doAssert sizeof(EventType) == sizeof(uint32) + ``` + +The `size pragma` can also specify the size of an `importc` incomplete object type +so that one can get the size of it at compile time even if it was declared without fields. + + ```Nim + type + AtomicFlag* {.importc: "atomic_flag", header: "", size: 1.} = object + + static: + # if AtomicFlag didn't have the size pragma, this code would result in a compile time error. + echo sizeof(AtomicFlag) + ``` + +The `size pragma` accepts only the values 1, 2, 4 or 8. + + Align pragma ------------ From b74d49c037734079765770426d0f5c79dee6cf87 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 6 May 2023 17:58:00 +0200 Subject: [PATCH 055/489] ORC: make rootsThreshold thread local [backport] (#21799) --- lib/system/orc.nim | 10 +++++----- tests/arc/tasyncleak.nim | 2 +- tests/arc/topt_no_cursor.nim | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/system/orc.nim b/lib/system/orc.nim index a56a0c0574..2addefdcfe 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -350,7 +350,7 @@ const when defined(nimStressOrc): const rootsThreshold = 10 # broken with -d:nimStressOrc: 10 and for havlak iterations 1..8 else: - var rootsThreshold = defaultThreshold + var rootsThreshold {.threadvar.}: int proc partialCollect(lowMark: int) = when false: @@ -392,13 +392,13 @@ proc collectCycles() = # of the cycle collector's effectiveness: # we're effective when we collected 50% or more of the nodes # we touched. If we're effective, we can reset the threshold: - if j.keepThreshold and rootsThreshold <= defaultThreshold: + if j.keepThreshold and rootsThreshold <= 0: discard elif j.freed * 2 >= j.touched: when not defined(nimFixedOrc): rootsThreshold = max(rootsThreshold div 3 * 2, 16) else: - rootsThreshold = defaultThreshold + rootsThreshold = 0 #cfprintf(cstderr, "[collectCycles] freed %ld, touched %ld new threshold %ld\n", j.freed, j.touched, rootsThreshold) elif rootsThreshold < high(int) div 4: rootsThreshold = rootsThreshold * 3 div 2 @@ -411,7 +411,7 @@ proc registerCycle(s: Cell; desc: PNimTypeV2) = if roots.d == nil: init(roots) add(roots, s, desc) - if roots.len >= rootsThreshold: + if roots.len >= rootsThreshold+defaultThreshold: collectCycles() when logOrc: writeCell("[added root]", s, desc) @@ -427,7 +427,7 @@ proc GC_enableOrc*() = ## Enables the cycle collector subsystem of `--gc:orc`. This is a `--gc:orc` ## specific API. Check with `when defined(gcOrc)` for its existence. when not defined(nimStressOrc): - rootsThreshold = defaultThreshold + rootsThreshold = 0 proc GC_disableOrc*() = ## Disables the cycle collector subsystem of `--gc:orc`. This is a `--gc:orc` diff --git a/tests/arc/tasyncleak.nim b/tests/arc/tasyncleak.nim index eb0c452131..8e3a7b3e7b 100644 --- a/tests/arc/tasyncleak.nim +++ b/tests/arc/tasyncleak.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "(allocCount: 4302, deallocCount: 4300)" + outputsub: "(allocCount: 4050, deallocCount: 4048)" cmd: "nim c --gc:orc -d:nimAllocStats $file" """ diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index 50dfa26ac0..26dc254475 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -1,6 +1,6 @@ discard """ nimoutFull: true - cmd: '''nim c -r --warnings:off --hints:off --gc:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig --expandArc:mergeShadowScope --expandArc:check $file''' + cmd: '''nim c -r --warnings:off --hints:off --mm:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig --expandArc:mergeShadowScope --expandArc:check $file''' nimout: ''' --expandArc: newTarget From 53c15f24e923379f74506949eb49433d232b48ad Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 7 May 2023 00:04:08 +0800 Subject: [PATCH 056/489] fixes #21704; remove nfIsRef for genLit in VM (#21765) * fixes #21704; remove `nfIsRef` for genLit * remove nfIsRef from the output of macros * make the logic better * try again * act together * excl nfIsRef --- compiler/vmgen.nim | 1 + tests/vm/t21704.nim | 69 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/vm/t21704.nim diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 48792790d8..db3276aada 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -443,6 +443,7 @@ proc rawGenLiteral(c: PCtx; n: PNode): int = result = c.constants.len #assert(n.kind != nkCall) n.flags.incl nfAllConst + n.flags.excl nfIsRef c.constants.add n internalAssert c.config, result < regBxMax diff --git a/tests/vm/t21704.nim b/tests/vm/t21704.nim new file mode 100644 index 0000000000..27f4f5b061 --- /dev/null +++ b/tests/vm/t21704.nim @@ -0,0 +1,69 @@ +discard """ +matrix: "--hints:off" +nimout: ''' +Found 2 tests to run. +Found 3 benches to compile. + + --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow + + --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow + + --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow +''' +""" +# bug #21704 +import std/strformat + +const testDesc: seq[string] = @[ + "tests/t_hash_sha256_vs_openssl.nim", + "tests/t_cipher_chacha20.nim" +] +const benchDesc = [ + "bench_sha256", + "bench_hash_to_curve", + "bench_ethereum_bls_signatures" +] + +proc setupTestCommand(flags, path: string): string = + return "nim c -r " & + flags & + &" --nimcache:nimcache/{path} " & # Commenting this out also solves the issue + path + +proc testBatch(commands: var string, flags, path: string) = + commands &= setupTestCommand(flags, path) & '\n' + +proc setupBench(benchName: string): string = + var runFlags = if false: " -r " + else: " " # taking this branch is needed to trigger the bug + + echo runFlags # Somehow runflags isn't reset in corner cases + runFlags &= " --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow " + echo runFlags + + return "nim c " & + runFlags & + &" benchmarks/{benchName}.nim" + +proc buildBenchBatch(commands: var string, benchName: string) = + let command = setupBench(benchName) + commands &= command & '\n' + +proc addTestSet(cmdFile: var string) = + echo "Found " & $testDesc.len & " tests to run." + + for path in testDesc: + var flags = "" # This is important + cmdFile.testBatch(flags, path) + +proc addBenchSet(cmdFile: var string) = + echo "Found " & $benchDesc.len & " benches to compile." + for bd in benchDesc: + cmdFile.buildBenchBatch(bd) + +proc task_bug() = + var cmdFile: string + cmdFile.addTestSet() # Comment this out and there is no bug + cmdFile.addBenchSet() + +static: task_bug() From 365a753eed70f817b43fd8c76bdfaf28ab001561 Mon Sep 17 00:00:00 2001 From: quantimnot <54247259+quantimnot@users.noreply.github.com> Date: Sat, 6 May 2023 13:10:13 -0400 Subject: [PATCH 057/489] Fix some `styleCheck` bugs (#20095) refs #19822 Fixes these bugs: * Style check violations in generics defined in foreign packages are raised. * Builtin pragma usage style check violations in foreign packages are raised. * User pragma definition style check violations are not raised. Co-authored-by: quantimnot --- compiler/linter.nim | 14 +++--- compiler/pragmas.nim | 3 +- .../foreign_package/foreign_package.nim | 1 + .../foreign_package/foreign_package.nimble | 2 + tests/stylecheck/tforeign_package.nim | 16 +++++++ tests/stylecheck/thint.nim | 43 +++++++++++++++++++ 6 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 tests/stylecheck/foreign_package/foreign_package.nim create mode 100644 tests/stylecheck/foreign_package/foreign_package.nimble create mode 100644 tests/stylecheck/tforeign_package.nim create mode 100644 tests/stylecheck/thint.nim diff --git a/compiler/linter.nim b/compiler/linter.nim index 0c2aaef792..f3e2d62071 100644 --- a/compiler/linter.nim +++ b/compiler/linter.nim @@ -95,7 +95,7 @@ template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind) if optStyleCheck in ctx.config.options and # ignore if styleChecks are off {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # check only if hint/error is enabled hintName in ctx.config.notes and # ignore if name checks are not requested - ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages + ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages optStyleUsages notin ctx.config.globalOptions and # ignore if requested to only check name usage sym.kind != skResult and # ignore `result` sym.kind != skTemp and # ignore temporary variables created by the compiler @@ -136,7 +136,7 @@ template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) = ## Check symbol uses match their definition's style. if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off hintName in ctx.config.notes and # ignore if name checks are not requested - ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages + ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages sym.kind != skTemp and # ignore temporary variables created by the compiler sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols??? sfAnon notin sym.flags: # ignore temporary variables created by the compiler @@ -147,6 +147,10 @@ proc checkPragmaUseImpl(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragm if pragmaName != wanted: lintReport(conf, info, wanted, pragmaName) -template checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) = - if {optStyleHint, optStyleError} * conf.globalOptions != {}: - checkPragmaUseImpl(conf, info, w, pragmaName) +template checkPragmaUse*(ctx: PContext; info: TLineInfo; w: TSpecialWord; pragmaName: string, sym: PSym) = + ## Check builtin pragma uses match their definition's style. + ## Note: This only applies to builtin pragmas, not user pragmas. + if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off + hintName in ctx.config.notes and # ignore if name checks are not requested + (sym != nil and ctx.config.belongsToProjectPackage(sym)): # ignore foreign packages + checkPragmaUseImpl(ctx.config, info, w, pragmaName) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 9f2eeb002f..10d77a17e9 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -676,6 +676,7 @@ proc processPragma(c: PContext, n: PNode, i: int) = invalidPragma(c, n) var userPragma = newSym(skTemplate, it[1].ident, c.idgen, c.module, it.info, c.config.options) + styleCheckDef(c, userPragma) userPragma.ast = newTreeI(nkPragma, n.info, n.sons[i+1..^1]) strTableAdd(c.userPragmas, userPragma) @@ -863,7 +864,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, else: let k = whichKeyword(ident) if k in validPragmas: - checkPragmaUse(c.config, key.info, k, ident.s) + checkPragmaUse(c, key.info, k, ident.s, (if sym != nil: sym else: c.module)) case k of wExportc, wExportCpp: makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info) diff --git a/tests/stylecheck/foreign_package/foreign_package.nim b/tests/stylecheck/foreign_package/foreign_package.nim new file mode 100644 index 0000000000..f95be006c6 --- /dev/null +++ b/tests/stylecheck/foreign_package/foreign_package.nim @@ -0,0 +1 @@ +include ../thint \ No newline at end of file diff --git a/tests/stylecheck/foreign_package/foreign_package.nimble b/tests/stylecheck/foreign_package/foreign_package.nimble new file mode 100644 index 0000000000..a2c49e3898 --- /dev/null +++ b/tests/stylecheck/foreign_package/foreign_package.nimble @@ -0,0 +1,2 @@ +# See `tstyleCheck` +# Needed to mark `mstyleCheck` as a foreign package. diff --git a/tests/stylecheck/tforeign_package.nim b/tests/stylecheck/tforeign_package.nim new file mode 100644 index 0000000000..8594ad802e --- /dev/null +++ b/tests/stylecheck/tforeign_package.nim @@ -0,0 +1,16 @@ +discard """ + matrix: "--errorMax:0 --styleCheck:error" + action: compile +""" + +import foreign_package/foreign_package + +# This call tests that: +# - an instantiation of a generic in a foreign package doesn't raise errors +# when the generic body contains: +# - definition and usage violations +# - builtin pragma usage violations +# - user pragma usage violations +# - definition violations in foreign packages are ignored +# - usage violations in foreign packages are ignored +genericProc[int]() diff --git a/tests/stylecheck/thint.nim b/tests/stylecheck/thint.nim new file mode 100644 index 0000000000..c19aac1b89 --- /dev/null +++ b/tests/stylecheck/thint.nim @@ -0,0 +1,43 @@ +discard """ + matrix: "--styleCheck:hint" + action: compile +""" + +# Test violating ident definition: +{.pragma: user_pragma.} #[tt.Hint + ^ 'user_pragma' should be: 'userPragma' [Name] ]# + +# Test violating ident usage style matches definition style: +{.userPragma.} #[tt.Hint + ^ 'userPragma' should be: 'user_pragma' [template declared in thint.nim(7, 9)] [Name] ]# + +# Test violating builtin pragma usage style: +{.no_side_effect.}: #[tt.Hint + ^ 'no_side_effect' should be: 'noSideEffect' [Name] ]# + discard 0 + +# Test: +# - definition style violation +# - user pragma usage style violation +# - builtin pragma usage style violation +proc generic_proc*[T] {.no_destroy, userPragma.} = #[tt.Hint + ^ 'generic_proc' should be: 'genericProc' [Name]; tt.Hint + ^ 'no_destroy' should be: 'nodestroy' [Name]; tt.Hint + ^ 'userPragma' should be: 'user_pragma' [template declared in thint.nim(7, 9)] [Name] ]# + # Test definition style violation: + let snake_case = 0 #[tt.Hint + ^ 'snake_case' should be: 'snakeCase' [Name] ]# + # Test user pragma definition style violation: + {.pragma: another_user_pragma.} #[tt.Hint + ^ 'another_user_pragma' should be: 'anotherUserPragma' [Name] ]# + # Test user pragma usage style violation: + {.anotherUserPragma.} #[tt.Hint + ^ 'anotherUserPragma' should be: 'another_user_pragma' [template declared in thint.nim(31, 11)] [Name] ]# + # Test violating builtin pragma usage style: + {.no_side_effect.}: #[tt.Hint + ^ 'no_side_effect' should be: 'noSideEffect' [Name] ]# + # Test usage style violation: + discard snakeCase #[tt.Hint + ^ 'snakeCase' should be: 'snake_case' [let declared in thint.nim(28, 7)] [Name] ]# + +generic_proc[int]() From d0c62fa169f3970653ce0d5bbd16e123efb24251 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 6 May 2023 21:25:45 +0200 Subject: [PATCH 058/489] fixes #21753 [backport] (#21802) --- compiler/types.nim | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/types.nim b/compiler/types.nim index d2517127a9..2c2dec639c 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -396,9 +396,9 @@ proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = result = true elif not containsOrIncl(marker, t.id): for i in 0.. Date: Sat, 6 May 2023 22:27:28 +0300 Subject: [PATCH 059/489] some Token refactors (#21762) * test some Token refactors * fix CI * showcase for more reductions, will revert * Revert "showcase for more reductions, will revert" This reverts commit 5ba48591f4d53e8d83a27de8b03d26c6178dd3d1. * make line and column int32 * remove int32 change --- compiler/layouter.nim | 6 ++--- compiler/lexer.nim | 34 +++++++++++-------------- compiler/parser.nim | 17 ++++++------- nimpretty/tests/exhaustive.nim | 2 +- nimpretty/tests/expected/exhaustive.nim | 2 +- 5 files changed, 28 insertions(+), 33 deletions(-) diff --git a/compiler/layouter.nim b/compiler/layouter.nim index 6e8280e674..7cff98b11b 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -510,7 +510,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = rememberSplit(splitComma) wrSpace em of openPars: - if tok.strongSpaceA and not em.endsInWhite and + if tsLeading in tok.spacing and not em.endsInWhite and (not em.wasExportMarker or tok.tokType == tkCurlyDotLe): wrSpace em wr(em, $tok.tokType, ltSomeParLe) @@ -528,7 +528,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = wr(em, $tok.tokType, ltOther) if not em.inquote: wrSpace(em) of tkOpr, tkDotDot: - if em.inquote or (((not tok.strongSpaceA) and tok.strongSpaceB == tsNone) and + if em.inquote or (tok.spacing == {} and tok.ident.s notin ["<", ">", "<=", ">=", "==", "!="]): # bug #9504: remember to not spacify a keyword: lastTokWasTerse = true @@ -538,7 +538,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) = if not em.endsInWhite: wrSpace(em) wr(em, tok.ident.s, ltOpr) template isUnary(tok): bool = - tok.strongSpaceB == tsNone and tok.strongSpaceA + tok.spacing == {tsLeading} if not isUnary(tok): rememberSplit(splitBinary) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index a62d40e54c..67dafc59fa 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -94,19 +94,18 @@ type base2, base8, base16 TokenSpacing* = enum - tsNone, tsTrailing, tsEof + tsLeading, tsTrailing, tsEof Token* = object # a Nim token tokType*: TokType # the type of the token + base*: NumericalBase # the numerical base; only valid for int + # or float literals + spacing*: set[TokenSpacing] # spaces around token indent*: int # the indentation; != -1 if the token has been # preceded with indentation ident*: PIdent # the parsed identifier iNumber*: BiggestInt # the parsed integer literal fNumber*: BiggestFloat # the parsed floating point literal - base*: NumericalBase # the numerical base; only valid for int - # or float literals - strongSpaceA*: bool # leading spaces of an operator - strongSpaceB*: TokenSpacing # trailing spaces of an operator literal*: string # the parsed (string) literal; and # documentation comments are here too line*, col*: int @@ -178,7 +177,7 @@ proc initToken*(L: var Token) = L.tokType = tkInvalid L.iNumber = 0 L.indent = 0 - L.strongSpaceA = false + L.spacing = {} L.literal = "" L.fNumber = 0.0 L.base = base10 @@ -191,7 +190,7 @@ proc fillToken(L: var Token) = L.tokType = tkInvalid L.iNumber = 0 L.indent = 0 - L.strongSpaceA = false + L.spacing = {} setLen(L.literal, 0) L.fNumber = 0.0 L.base = base10 @@ -960,13 +959,15 @@ proc getOperator(L: var Lexer, tok: var Token) = tokenEnd(tok, pos-1) # advance pos but don't store it in L.bufpos so the next token (which might # be an operator too) gets the preceding spaces: - tok.strongSpaceB = tsNone + tok.spacing = tok.spacing - {tsTrailing, tsEof} + var trailing = false while L.buf[pos] == ' ': inc pos - if tok.strongSpaceB != tsTrailing: - tok.strongSpaceB = tsTrailing + trailing = true if L.buf[pos] in {CR, LF, nimlexbase.EndOfFile}: - tok.strongSpaceB = tsEof + tok.spacing.incl(tsEof) + elif trailing: + tok.spacing.incl(tsTrailing) proc getPrecedence*(tok: Token): int = ## Calculates the precedence of the given token. @@ -1077,7 +1078,6 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int; when defined(nimpretty): tok.literal.add "\L" if isDoc: when not defined(nimpretty): tok.literal.add "\n" - inc tok.iNumber var c = toStrip while L.buf[pos] == ' ' and c > 0: inc pos @@ -1096,8 +1096,6 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int; proc scanComment(L: var Lexer, tok: var Token) = var pos = L.bufpos tok.tokType = tkComment - # iNumber contains the number of '\n' in the token - tok.iNumber = 0 assert L.buf[pos+1] == '#' when defined(nimpretty): tok.commentOffsetA = L.offsetBase + pos @@ -1140,7 +1138,6 @@ proc scanComment(L: var Lexer, tok: var Token) = while L.buf[pos] == ' ' and c > 0: inc pos dec c - inc tok.iNumber else: if L.buf[pos] > ' ': L.indentAhead = indent @@ -1153,7 +1150,7 @@ proc scanComment(L: var Lexer, tok: var Token) = proc skip(L: var Lexer, tok: var Token) = var pos = L.bufpos tokenBegin(tok, pos) - tok.strongSpaceA = false + tok.spacing.excl(tsLeading) when defined(nimpretty): var hasComment = false var commentIndent = L.currLineIndent @@ -1164,8 +1161,7 @@ proc skip(L: var Lexer, tok: var Token) = case L.buf[pos] of ' ': inc(pos) - if not tok.strongSpaceA: - tok.strongSpaceA = true + tok.spacing.incl(tsLeading) of '\t': if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead") inc(pos) @@ -1187,7 +1183,7 @@ proc skip(L: var Lexer, tok: var Token) = pos = L.bufpos else: break - tok.strongSpaceA = false + tok.spacing.excl(tsLeading) when defined(nimpretty): if L.buf[pos] == '#' and tok.line < 0: commentIndent = indent if L.buf[pos] > ' ' and (L.buf[pos] != '#' or L.buf[pos+1] == '#'): diff --git a/compiler/parser.nim b/compiler/parser.nim index 26a442e238..babbb87fd4 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -301,14 +301,13 @@ proc isRightAssociative(tok: Token): bool {.inline.} = proc isUnary(tok: Token): bool = ## Check if the given token is a unary operator tok.tokType in {tkOpr, tkDotDot} and - tok.strongSpaceB == tsNone and - tok.strongSpaceA + tok.spacing == {tsLeading} proc checkBinary(p: Parser) {.inline.} = ## Check if the current parser token is a binary operator. # we don't check '..' here as that's too annoying if p.tok.tokType == tkOpr: - if p.tok.strongSpaceB == tsTrailing and not p.tok.strongSpaceA: + if p.tok.spacing == {tsTrailing}: parMessage(p, warnInconsistentSpacing, prettyTok(p.tok)) #| module = stmt ^* (';' / IND{=}) @@ -516,7 +515,7 @@ proc dotExpr(p: var Parser, a: PNode): PNode = optInd(p, result) result.add(a) result.add(parseSymbol(p, smAfterDot)) - if p.tok.tokType == tkBracketLeColon and not p.tok.strongSpaceA: + if p.tok.tokType == tkBracketLeColon and tsLeading notin p.tok.spacing: var x = newNodeI(nkBracketExpr, p.parLineInfo) # rewrite 'x.y[:z]()' to 'y[z](x)' x.add result[1] @@ -525,7 +524,7 @@ proc dotExpr(p: var Parser, a: PNode): PNode = var y = newNodeI(nkCall, p.parLineInfo) y.add x y.add result[0] - if p.tok.tokType == tkParLe and not p.tok.strongSpaceA: + if p.tok.tokType == tkParLe and tsLeading notin p.tok.spacing: exprColonEqExprListAux(p, tkParRi, y) result = y @@ -883,7 +882,7 @@ proc primarySuffix(p: var Parser, r: PNode, case p.tok.tokType of tkParLe: # progress guaranteed - if p.tok.strongSpaceA: + if tsLeading in p.tok.spacing: result = commandExpr(p, result, mode) break result = namedParams(p, result, nkCall, tkParRi) @@ -895,13 +894,13 @@ proc primarySuffix(p: var Parser, r: PNode, result = parseGStrLit(p, result) of tkBracketLe: # progress guaranteed - if p.tok.strongSpaceA: + if tsLeading in p.tok.spacing: result = commandExpr(p, result, mode) break result = namedParams(p, result, nkBracketExpr, tkBracketRi) of tkCurlyLe: # progress guaranteed - if p.tok.strongSpaceA: + if tsLeading in p.tok.spacing: result = commandExpr(p, result, mode) break result = namedParams(p, result, nkCurlyExpr, tkCurlyRi) @@ -2525,7 +2524,7 @@ proc parseAll(p: var Parser): PNode = setEndInfo() proc checkFirstLineIndentation*(p: var Parser) = - if p.tok.indent != 0 and p.tok.strongSpaceA: + if p.tok.indent != 0 and tsLeading in p.tok.spacing: parMessage(p, errInvalidIndentation) proc parseTopLevelStmt(p: var Parser): PNode = diff --git a/nimpretty/tests/exhaustive.nim b/nimpretty/tests/exhaustive.nim index 53ff0ea4d5..bcf8256656 100644 --- a/nimpretty/tests/exhaustive.nim +++ b/nimpretty/tests/exhaustive.nim @@ -267,7 +267,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = if not em.endsInWhite: wr(" ") wr(tok.ident.s) template isUnary(tok): bool = - tok.strongSpaceB == tsNone and tok.strongSpaceA + tok.spacing == {tsLeading} if not isUnary(tok) or em.lastTok in {tkOpr, tkDotDot}: wr(" ") diff --git a/nimpretty/tests/expected/exhaustive.nim b/nimpretty/tests/expected/exhaustive.nim index 266bcae06b..50ae92a62b 100644 --- a/nimpretty/tests/expected/exhaustive.nim +++ b/nimpretty/tests/expected/exhaustive.nim @@ -272,7 +272,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) = if not em.endsInWhite: wr(" ") wr(tok.ident.s) template isUnary(tok): bool = - tok.strongSpaceB == tsNone and tok.strongSpaceA + tok.spacing == {tsLeading} if not isUnary(tok) or em.lastTok in {tkOpr, tkDotDot}: wr(" ") From b562e1e6d85d5c64eec1d714257e2f728e60f12f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 7 May 2023 03:36:57 +0800 Subject: [PATCH 060/489] implement `=dup` hook eliminating `wasMoved` and `=copy` pairs (#21586) * import `=dup` hook eliminating `wasMoved` and `=copy` pairs * add dup * add a test for dup * fixes documentation * fixes signature * resolve comments * fixes tests * fixes tests * clean up --- compiler/ast.nim | 7 ++-- compiler/ccgexprs.nim | 10 +++++ compiler/condsyms.nim | 3 +- compiler/injectdestructors.nim | 27 ++++++++++--- compiler/jsgen.nim | 9 +++++ compiler/liftdestructors.nim | 26 +++++++++++-- compiler/semstmts.nim | 16 ++++++-- compiler/vmgen.nim | 6 +++ lib/system.nim | 6 +++ lib/system/arc.nim | 4 ++ tests/arc/tdup.nim | 70 ++++++++++++++++++++++++++++++++++ tests/arc/topt_no_cursor.nim | 3 +- 12 files changed, 170 insertions(+), 17 deletions(-) create mode 100644 tests/arc/tdup.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index bf942f7849..815cb00dc4 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -687,7 +687,7 @@ type mIsPartOf, mAstToStr, mParallel, mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq, mNewString, mNewStringOfCap, mParseBiggestFloat, - mMove, mWasMoved, mDestroy, mTrace, + mMove, mWasMoved, mDup, mDestroy, mTrace, mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, @@ -944,7 +944,8 @@ type attachedAsgn, attachedSink, attachedTrace, - attachedDeepCopy + attachedDeepCopy, + attachedDup TType* {.acyclic.} = object of TIdObj # \ # types are identical iff they have the @@ -1515,7 +1516,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode, const AttachedOpToStr*: array[TTypeAttachedOp, string] = [ - "=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy"] + "=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy", "=dup"] proc `$`*(s: PSym): string = if s != nil: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 265ccb92c7..e351e95b02 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2346,6 +2346,11 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) = genAssignment(p, d, a, {}) resetLoc(p, a) +proc genDup(p: BProc; src: TLoc; d: var TLoc; n: PNode) = + if d.k == locNone: getTemp(p, n.typ, d) + linefmt(p, cpsStmts, "#nimDupRef((void**)$1, (void*)$2);$n", + [addrLoc(p.config, d), rdLoc(src)]) + proc genDestroy(p: BProc; n: PNode) = if optSeqDestructors in p.config.globalOptions: let arg = n[1].skipAddr @@ -2597,6 +2602,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mAccessTypeField: genAccessTypeField(p, e, d) of mSlice: genSlice(p, e, d) of mTrace: discard "no code to generate" + of mDup: + var a: TLoc + let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1] + initLocExpr(p, x, a) + genDup(p, a, d, e) else: when defined(debugMagics): echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index fa7f56504d..8e0e2f3004 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -154,5 +154,6 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasGenericDefine") defineSymbol("nimHasDefineAliases") defineSymbol("nimHasWarnBareExcept") - + defineSymbol("nimHasDup") defineSymbol("nimHasChecksums") + diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index ccb19720df..d9a2da5a08 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -425,11 +425,28 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) let tmp = c.getTemp(s, n.typ, n.info) if hasDestructor(c, n.typ): - result.add c.genWasMoved(tmp) - var m = c.genCopy(tmp, n, {}) - m.add p(n, c, s, normal) - c.finishCopy(m, n, isFromSink = true) - result.add m + let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink}) + let op = getAttachedOp(c.graph, typ, attachedDup) + if op != nil: + let src = p(n, c, s, normal) + result.add newTreeI(nkFastAsgn, + src.info, tmp, + genOp(c, op, src) + ) + elif typ.kind == tyRef: + let src = p(n, c, s, normal) + result.add newTreeI(nkFastAsgn, + src.info, tmp, + newTreeIT(nkCall, src.info, src.typ, + newSymNode(createMagic(c.graph, c.idgen, "`=dup`", mDup)), + src) + ) + else: + result.add c.genWasMoved(tmp) + var m = c.genCopy(tmp, n, {}) + m.add p(n, c, s, normal) + c.finishCopy(m, n, isFromSink = true) + result.add m if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0: message(c.graph.config, n.info, hintPerformance, ("passing '$1' to a sink parameter introduces an implicit copy; " & diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 6195559699..45b0baec0c 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2174,6 +2174,13 @@ proc genMove(p: PProc; n: PNode; r: var TCompRes) = genReset(p, n) #lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc]) +proc genDup(p: PProc; n: PNode; r: var TCompRes) = + var a: TCompRes + r.kind = resVal + r.res = p.getTemp() + gen(p, n[1], a) + lineF(p, "$1 = $2;$n", [r.rdLoc, a.rdLoc]) + proc genJSArrayConstr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes r.res = rope("[") @@ -2368,6 +2375,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = r.kind = resExpr of mMove: genMove(p, n, r) + of mDup: + genDup(p, n, r) else: genCall(p, n, r) #else internalError(p.config, e.info, 'genMagic: ' + magicToStr[op]); diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 3fd3c5f378..3a997af82b 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -463,6 +463,9 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = body.add genWasMovedCall(c, op, x) result = true + of attachedDup: + assert false, "cannot happen" + proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info) temp.typ = getSysType(c.g, body.info, tyInt) @@ -546,6 +549,8 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # follow all elements: forallElements(c, t, body, x, y) of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedDup: + assert false, "cannot happen" proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = createTypeBoundOps(c.g, c.c, t, body.info, c.idgen) @@ -584,6 +589,8 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = return # protect from recursion body.add newHookCall(c, op, x, y) of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedDup: + assert false, "cannot happen" proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind @@ -600,6 +607,8 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedTrace: discard "strings are atomic and have no inner elements that are to trace" of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedDup: + assert false, "cannot happen" proc cyclicType*(t: PType): bool = case t.kind @@ -699,7 +708,8 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y) #echo "can follow ", elemType, " static ", isFinal(elemType) of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) - + of attachedDup: + assert false, "cannot happen" proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = ## Closures are really like refs except they always use a virtual destructor @@ -749,6 +759,8 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedTrace: body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y) of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedDup: + assert false, "cannot happen" proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind @@ -774,6 +786,8 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedDup: + assert false, "cannot happen" proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = var actions = newNodeI(nkStmtList, c.info) @@ -800,6 +814,8 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedDup: + assert false, "cannot happen" proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if c.kind == attachedDeepCopy: @@ -835,6 +851,8 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedDup: + assert false, "cannot happen" proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let xx = genBuiltin(c, mAccessEnv, "accessEnv", x) @@ -851,6 +869,8 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedDup: + assert false, "cannot happen" proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind @@ -966,7 +986,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp result.typ = newProcType(info, nextTypeId(idgen), owner) result.typ.addParam dest - if kind notin {attachedDestructor, attachedWasMoved}: + if kind notin {attachedDestructor, attachedWasMoved, attachedDup}: result.typ.addParam src if kind == attachedAsgn and g.config.selectedGC == gcOrc and @@ -1006,7 +1026,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; let dest = result.typ.n[1].sym let d = newDeref(newSymNode(dest)) - let src = if kind in {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer)) + let src = if kind in {attachedDestructor, attachedWasMoved, attachedDup}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer)) else: newSymNode(result.typ.n[2].sym) # register this operation already: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index e6fade5285..126d1aa654 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1815,9 +1815,12 @@ proc whereToBindTypeHook(c: PContext; t: PType): PType = proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) = let t = s.typ var noError = false - let cond = if op in {attachedDestructor, attachedWasMoved}: + let cond = case op + of {attachedDestructor, attachedWasMoved}: t.len == 2 and t[0] == nil and t[1].kind == tyVar - elif op == attachedTrace: + of attachedDup: + t.len == 2 and t[0] != nil and t[1].kind == tyVar + of attachedTrace: t.len == 3 and t[0] == nil and t[1].kind == tyVar and t[2].kind == tyPointer else: t.len >= 2 and t[0] == nil @@ -1843,9 +1846,13 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) = localError(c.config, n.info, errGenerated, "type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")") if not noError and sfSystemModule notin s.owner.flags: - if op == attachedTrace: + case op + of attachedTrace: localError(c.config, n.info, errGenerated, "signature for '=trace' must be proc[T: object](x: var T; env: pointer)") + of attachedDup: + localError(c.config, n.info, errGenerated, + "signature for '=dup' must be proc[T: object](x: var T): T") else: localError(c.config, n.info, errGenerated, "signature for '" & s.name.s & "' must be proc[T: object](x: var T)") @@ -1938,6 +1945,9 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = of "=wasmoved": if s.magic != mWasMoved: bindTypeHook(c, s, n, attachedWasMoved) + of "=dup": + if s.magic != mDup: + bindTypeHook(c, s, n, attachedDup) else: if sfOverriden in s.flags: localError(c.config, n.info, errGenerated, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index db3276aada..25ff62bcc7 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1401,6 +1401,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = # c.gABx(n, opcNodeToReg, a, a) # c.genAsgnPatch(arg, a) c.freeTemp(a) + of mDup: + let arg = n[1] + let a = c.genx(arg) + if dest < 0: dest = c.getTemp(arg.typ) + gABC(c, arg, whichAsgnOpc(arg, requiresCopy=false), dest, a) + c.freeTemp(a) of mNodeId: c.genUnaryABC(n, dest, opcNodeId) else: diff --git a/lib/system.nim b/lib/system.nim index f232423152..8bb50ba5d4 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -347,6 +347,12 @@ proc arrPut[I: Ordinal;T,S](a: T; i: I; proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} = ## Generic `destructor`:idx: implementation that can be overridden. discard + +when defined(nimHasDup): + proc `=dup`*[T](x: ref T): ref T {.inline, magic: "Dup".} = + ## Generic `dup` implementation that can be overridden. + discard + proc `=sink`*[T](x: var T; y: T) {.inline, nodestroy, magic: "Asgn".} = ## Generic `sink`:idx: implementation that can be overridden. when defined(gcArc) or defined(gcOrc): diff --git a/lib/system/arc.nim b/lib/system/arc.nim index d8527e1e45..55c4c412af 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -185,6 +185,10 @@ proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} = when traceCollector: cprintf("[DeCREF] %p\n", cell) +proc nimDupRef(dest: ptr pointer, src: pointer) {.compilerRtl, inl.} = + dest[] = src + if src != nil: nimIncRef src + proc GC_unref*[T](x: ref T) = ## New runtime only supports this operation for 'ref T'. var y {.cursor.} = x diff --git a/tests/arc/tdup.nim b/tests/arc/tdup.nim new file mode 100644 index 0000000000..3f64061fbe --- /dev/null +++ b/tests/arc/tdup.nim @@ -0,0 +1,70 @@ +discard """ + cmd: "nim c --mm:arc --expandArc:foo --hints:off $file" + nimout: ''' +--expandArc: foo + +var + x + :tmpD + s + :tmpD_1 +x = Ref(id: 8) +inc: + :tmpD = `=dup`(x) + :tmpD +inc: + let blitTmp = x + blitTmp +var id_1 = 777 +s = RefCustom(id_2: addr(id_1)) +inc_1 : + :tmpD_1 = `=dup`(s) + :tmpD_1 +inc_1 : + let blitTmp_1 = s + blitTmp_1 +-- end of expandArc ------------------------ +''' +""" + +type + Ref = ref object + id: int + + RefCustom = object + id: ptr int + +proc inc(x: sink Ref) = + inc x.id + +proc inc(x: sink RefCustom) = + inc x.id[] + +proc `=dup`(x: var RefCustom): RefCustom = + result.id = x.id + +proc foo = + var x = Ref(id: 8) + inc(x) + inc(x) + var id = 777 + var s = RefCustom(id: addr id) + inc s + inc s + +foo() + +proc foo2 = + var x = Ref(id: 8) + inc(x) + doAssert x.id == 9 + inc(x) + doAssert x.id == 10 + var id = 777 + var s = RefCustom(id: addr id) + inc s + doAssert s.id[] == 778 + inc s + doAssert s.id[] == 779 + +foo2() diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index 26dc254475..32652b60a5 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -113,8 +113,7 @@ block :tmp: var :tmpD sym = shadowScope.symbols[i] addInterfaceDecl(c): - `=wasMoved`(:tmpD) - `=copy_1`(:tmpD, sym) + :tmpD = `=dup`(sym) :tmpD inc(i, 1) `=destroy`(shadowScope) From 8cf5643621600aaa869935721227fc3b7ee5f881 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 7 May 2023 03:38:17 +0800 Subject: [PATCH 061/489] fixes #21280; Enum with int64.high() value crashes compiler (#21285) * fixes #21280; Enum with int64.high() value crashes compiler * Update tests/enum/tenum.nim * Update tests/enum/tenum.nim * fixes tests * Update tests/enum/tenum.nim --------- Co-authored-by: Andreas Rumpf --- compiler/semtypes.nim | 7 ++++++- tests/enum/tenum.nim | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index e54de80a82..38d040946f 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -16,6 +16,7 @@ const errIntLiteralExpected = "integer literal expected" errWrongNumberOfVariables = "wrong number of variables" errInvalidOrderInEnumX = "invalid order in enum '$1'" + errOverflowInEnumX = "The enum '$1' exceeds its maximum value ($2)" errOrdinalTypeExpected = "ordinal type expected; given: $1" errSetTooBig = "set is too large; use `std/sets` for ordinal types with more than 2^16 elements" errBaseTypeMustBeOrdinal = "base type of a set must be an ordinal" @@ -147,7 +148,11 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = declarePureEnumField(c, e) if (let conflict = strTableInclReportConflict(symbols, e); conflict != nil): wrongRedefinition(c, e.info, e.name.s, conflict.info) - inc(counter) + if counter == high(typeof(counter)): + if i > 1 and result.n[i-2].sym.position == high(int): + localError(c.config, n[i].info, errOverflowInEnumX % [e.name.s, $high(typeof(counter))]) + else: + inc(counter) if isPure and sfExported in result.sym.flags: addPureEnum(c, LazySym(sym: result.sym)) if tfNotNil in e.typ.flags and not hasNull: diff --git a/tests/enum/tenum.nim b/tests/enum/tenum.nim index 88d85ddcc4..8046c65890 100644 --- a/tests/enum/tenum.nim +++ b/tests/enum/tenum.nim @@ -176,3 +176,11 @@ block: # bug #12589 when not defined(gcRefc): doAssert $typ() == "wkbPoint25D" + + block: # bug #21280 + type + Test = enum + B = 19 + A = int64.high() + + doAssert ord(A) == int64.high() From 4a94f3606e2e3c47cf416755c4b3d2cd7eddef9c Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 7 May 2023 15:22:42 +0800 Subject: [PATCH 062/489] revert #21799 and #21802 which don't pass the tests (#21804) * Revert "ORC: make rootsThreshold thread local [backport] (#21799)" This reverts commit b74d49c037734079765770426d0f5c79dee6cf87. * Revert "fixes #21752 [backport] (#21802)" This reverts commit d0c62fa169f3970653ce0d5bbd16e123efb24251. --- compiler/types.nim | 9 +++------ lib/system/orc.nim | 10 +++++----- tests/arc/tasyncleak.nim | 2 +- tests/arc/topt_no_cursor.nim | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/compiler/types.nim b/compiler/types.nim index 2c2dec639c..d2517127a9 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -396,9 +396,9 @@ proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = result = true elif not containsOrIncl(marker, t.id): for i in 0..= j.touched: when not defined(nimFixedOrc): rootsThreshold = max(rootsThreshold div 3 * 2, 16) else: - rootsThreshold = 0 + rootsThreshold = defaultThreshold #cfprintf(cstderr, "[collectCycles] freed %ld, touched %ld new threshold %ld\n", j.freed, j.touched, rootsThreshold) elif rootsThreshold < high(int) div 4: rootsThreshold = rootsThreshold * 3 div 2 @@ -411,7 +411,7 @@ proc registerCycle(s: Cell; desc: PNimTypeV2) = if roots.d == nil: init(roots) add(roots, s, desc) - if roots.len >= rootsThreshold+defaultThreshold: + if roots.len >= rootsThreshold: collectCycles() when logOrc: writeCell("[added root]", s, desc) @@ -427,7 +427,7 @@ proc GC_enableOrc*() = ## Enables the cycle collector subsystem of `--gc:orc`. This is a `--gc:orc` ## specific API. Check with `when defined(gcOrc)` for its existence. when not defined(nimStressOrc): - rootsThreshold = 0 + rootsThreshold = defaultThreshold proc GC_disableOrc*() = ## Disables the cycle collector subsystem of `--gc:orc`. This is a `--gc:orc` diff --git a/tests/arc/tasyncleak.nim b/tests/arc/tasyncleak.nim index 8e3a7b3e7b..eb0c452131 100644 --- a/tests/arc/tasyncleak.nim +++ b/tests/arc/tasyncleak.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "(allocCount: 4050, deallocCount: 4048)" + outputsub: "(allocCount: 4302, deallocCount: 4300)" cmd: "nim c --gc:orc -d:nimAllocStats $file" """ diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index 32652b60a5..ddcc549d1f 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -1,6 +1,6 @@ discard """ nimoutFull: true - cmd: '''nim c -r --warnings:off --hints:off --mm:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig --expandArc:mergeShadowScope --expandArc:check $file''' + cmd: '''nim c -r --warnings:off --hints:off --gc:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig --expandArc:mergeShadowScope --expandArc:check $file''' nimout: ''' --expandArc: newTarget From 71f2e1a502ad231e3356217398e2d7fcd6137967 Mon Sep 17 00:00:00 2001 From: Jordan Gillard Date: Sun, 7 May 2023 03:25:25 -0400 Subject: [PATCH 063/489] =?UTF-8?q?=F0=9F=9A=80=20Enhancing=20CellSeq=20fo?= =?UTF-8?q?r=20Better=20Readability=20and=20Maintainability=20(#21797)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor and improve readability of CellSeq in system directory * Use half-open range in the contains procedure for better readability and to avoid potential off-by-one errors * Extract resizing logic from add procedure into a separate resize procedure for better code readability and separation of concerns --- lib/system/cellseqs_v1.nim | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/system/cellseqs_v1.nim b/lib/system/cellseqs_v1.nim index 1952491b37..1a305aa428 100644 --- a/lib/system/cellseqs_v1.nim +++ b/lib/system/cellseqs_v1.nim @@ -16,18 +16,21 @@ type d: PCellArray proc contains(s: CellSeq, c: PCell): bool {.inline.} = - for i in 0 .. s.len-1: - if s.d[i] == c: return true + for i in 0 ..< s.len: + if s.d[i] == c: + return true return false +proc resize(s: var CellSeq) = + s.cap = s.cap * 3 div 2 + let d = cast[PCellArray](alloc(s.cap * sizeof(PCell))) + copyMem(d, s.d, s.len * sizeof(PCell)) + dealloc(s.d) + s.d = d + proc add(s: var CellSeq, c: PCell) {.inline.} = if s.len >= s.cap: - s.cap = s.cap * 3 div 2 - var d = cast[PCellArray](alloc(s.cap * sizeof(PCell))) - copyMem(d, s.d, s.len * sizeof(PCell)) - dealloc(s.d) - s.d = d - # XXX: realloc? + resize(s) s.d[s.len] = c inc(s.len) From ebdff1c7d36683c13b7b692e7d2f16aa3b13027f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 8 May 2023 19:52:28 +0800 Subject: [PATCH 064/489] fixes #21801; object field initialization with overloaded functions (#21805) * fixes #21801; object field initialization with overloaded functions * use the correct type --- compiler/semtypes.nim | 2 +- tests/objects/tobject_default_value.nim | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 38d040946f..750ab2216b 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -227,8 +227,8 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool = proc fitDefaultNode(c: PContext, n: PNode): PType = let expectedType = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil - let oldType = n[^1].typ n[^1] = semConstExpr(c, n[^1], expectedType = expectedType) + let oldType = n[^1].typ n[^1].flags.incl nfSem if n[^2].kind != nkEmpty: if expectedType != nil and oldType != expectedType: diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim index 59af943e0c..97e3a207d7 100644 --- a/tests/objects/tobject_default_value.nim +++ b/tests/objects/tobject_default_value.nim @@ -591,6 +591,29 @@ template main {.dirty.} = mainSync() + block: # bug #21801 + func evaluate(i: int): float = + 0.0 + + func evaluate(): float = + 0.0 + + type SearchOptions = object + evaluation: proc(): float = evaluate + + block: + func evaluate(): float = + 0.0 + + type SearchOptions = object + evaluation: proc(): float = evaluate + + block: + func evaluate(i: int): float = + 0.0 + + type SearchOptions = object + evaluation = evaluate static: main() main() From 4533e894ad0e113c6057d336290d2c903383e406 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 8 May 2023 22:25:47 +0800 Subject: [PATCH 065/489] adds an experimental `mm:atomicArc` switch (#21798) --- compiler/btrees.nim | 4 ++-- compiler/ccgcalls.nim | 2 +- compiler/ccgexprs.nim | 6 +++--- compiler/cgen.nim | 8 ++++---- compiler/commands.nim | 24 +++++++++++++----------- compiler/dfa.nim | 2 +- compiler/injectdestructors.nim | 8 ++++---- compiler/liftdestructors.nim | 10 +++++----- compiler/msgs.nim | 4 ++-- compiler/nimfix/prettybase.nim | 4 ++-- compiler/options.nim | 1 + compiler/pragmas.nim | 2 +- compiler/scriptconfig.nim | 2 +- compiler/semexprs.nim | 2 +- compiler/sempass2.nim | 2 +- compiler/semtypes.nim | 2 +- compiler/spawn.nim | 4 ++-- compiler/vm.nim | 4 ++-- lib/system/arc.nim | 33 ++++++++++++++++++++++++--------- 19 files changed, 71 insertions(+), 53 deletions(-) diff --git a/compiler/btrees.nim b/compiler/btrees.nim index c79442249d..92f07f6b09 100644 --- a/compiler/btrees.nim +++ b/compiler/btrees.nim @@ -68,7 +68,7 @@ proc copyHalf[Key, Val](h, result: Node[Key, Val]) = result.links[j] = h.links[Mhalf + j] else: for j in 0..") let initStackBottomCall = - if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcOrc}: "".rope + if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcAtomicArc, gcOrc}: "".rope else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []) inc(m.labels) - let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcOrc}: "1" else: "0" + let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}: "1" else: "0" appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit, m.config.nimMainPrefix, posixCmdLine, isVolatile]) if m.config.target.targetOS == osWindows and @@ -1725,7 +1725,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) = if sfSystemModule in m.module.flags: if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone: g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", [])) - if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}: + if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}: g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])) if m.s[cfsInitProc].len > 0: @@ -2177,7 +2177,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode = cgsym(m, "rawWrite") # raise dependencies on behalf of genMainProc - if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}: + if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}: cgsym(m, "initStackBottomWith") if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone: cgsym(m, "initThreadVarsEmulation") diff --git a/compiler/commands.nim b/compiler/commands.nim index c31476b45f..93a36e714b 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -238,7 +238,7 @@ proc processCompile(conf: ConfigRef; filename: string) = extccomp.addExternalFileToCompile(conf, found) const - errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found" + errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found" errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found" errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found" errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found" @@ -262,6 +262,7 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo of "go": result = conf.selectedGC == gcGo of "none": result = conf.selectedGC == gcNone of "stack", "regions": result = conf.selectedGC == gcRegions + of "atomicarc": result = conf.selectedGC == gcAtomicArc else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) of "opt": case arg.normalize @@ -516,14 +517,7 @@ proc initOrcDefines*(conf: ConfigRef) = if conf.exc == excNone and conf.backend != backendCpp: conf.exc = excGoto -proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef, isOrc: bool) = - if isOrc: - conf.selectedGC = gcOrc - defineSymbol(conf.symbols, "gcorc") - else: - conf.selectedGC = gcArc - defineSymbol(conf.symbols, "gcarc") - +proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef) = defineSymbol(conf.symbols, "gcdestructors") incl conf.globalOptions, optSeqDestructors incl conf.globalOptions, optTinyRtti @@ -562,9 +556,17 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass, conf.selectedGC = gcMarkAndSweep defineSymbol(conf.symbols, "gcmarkandsweep") of "destructors", "arc": - registerArcOrc(pass, conf, false) + conf.selectedGC = gcArc + defineSymbol(conf.symbols, "gcarc") + registerArcOrc(pass, conf) of "orc": - registerArcOrc(pass, conf, true) + conf.selectedGC = gcOrc + defineSymbol(conf.symbols, "gcorc") + registerArcOrc(pass, conf) + of "atomicarc": + conf.selectedGC = gcAtomicArc + defineSymbol(conf.symbols, "gcatomicarc") + registerArcOrc(pass, conf) of "hooks": conf.selectedGC = gcHooks defineSymbol(conf.symbols, "gchooks") diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 61a921ba0e..d145e31c33 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -493,7 +493,7 @@ proc constructCfg*(s: PSym; body: PNode; root: PSym): ControlFlowGraph = gen(c, body) if root.kind == skResult: genImplicitReturn(c) - when defined(gcArc) or defined(gcOrc): + when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc): result = c.code # will move else: shallowCopy(result, c.code) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index d9a2da5a08..ab0fa02d91 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -66,7 +66,7 @@ proc hasDestructor(c: Con; t: PType): bool {.inline.} = result = ast.hasDestructor(t) when toDebug.len > 0: # for more effective debugging - if not result and c.graph.config.selectedGC in {gcArc, gcOrc}: + if not result and c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: assert(not containsGarbageCollectedRef(t)) proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = @@ -452,7 +452,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = ("passing '$1' to a sink parameter introduces an implicit copy; " & "if possible, rearrange your program's control flow to prevent it") % $n) else: - if c.graph.config.selectedGC in {gcArc, gcOrc}: + if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: assert(not containsManagedMemory(n.typ)) if n.typ.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}: localError(c.graph.config, n.info, "cannot create an implicit openArray copy to be passed to a sink parameter") @@ -495,7 +495,7 @@ proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode = result = arg proc cycleCheck(n: PNode; c: var Con) = - if c.graph.config.selectedGC != gcArc: return + if c.graph.config.selectedGC notin {gcArc, gcAtomicArc}: return var value = n[1] if value.kind == nkClosure: value = value[1] @@ -838,7 +838,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}: result[0] = copyTree(n[0]) - if c.graph.config.selectedGC in {gcHooks, gcArc, gcOrc}: + if c.graph.config.selectedGC in {gcHooks, gcArc, gcAtomicArc, gcOrc}: let destroyOld = c.genDestroy(result[1]) result = newTree(nkStmtList, destroyOld, result) else: diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 3a997af82b..34ab3cc8e1 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -159,7 +159,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) let f = n.sym let b = if c.kind == attachedTrace: y else: y.dotField(f) if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and - c.g.config.selectedGC in {gcArc, gcOrc, gcHooks}) or + c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or enforceDefaultOp: defaultOp(c, f.typ, body, x.dotField(f), b) else: @@ -827,7 +827,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = call[1] = y body.add newAsgnStmt(x, call) elif (optOwnedRefs in c.g.config.globalOptions and - optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcOrc}: + optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}: let xx = genBuiltin(c, mAccessEnv, "accessEnv", x) xx.typ = getSysType(c.g, c.info, tyPointer) case c.kind @@ -879,7 +879,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = tyPtr, tyUncheckedArray, tyVar, tyLent: defaultOp(c, t, body, x, y) of tyRef: - if c.g.config.selectedGC in {gcArc, gcOrc}: + if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: atomicRefOp(c, t, body, x, y) elif (optOwnedRefs in c.g.config.globalOptions and optRefCheck in c.g.config.options): @@ -888,7 +888,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = defaultOp(c, t, body, x, y) of tyProc: if t.callConv == ccClosure: - if c.g.config.selectedGC in {gcArc, gcOrc}: + if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: atomicClosureOp(c, t, body, x, y) else: closureOp(c, t, body, x, y) @@ -1039,7 +1039,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; result.ast[bodyPos].add newAsgnStmt(d, src) else: var tk: TTypeKind - if g.config.selectedGC in {gcArc, gcOrc, gcHooks}: + if g.config.selectedGC in {gcArc, gcOrc, gcHooks, gcAtomicArc}: tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind else: tk = tyNone # no special casing for strings and seqs diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 8e391f2fb4..05ace315e3 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -226,7 +226,7 @@ proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: AbsoluteFile) proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) = assert fileIdx.int32 >= 0 - when defined(gcArc) or defined(gcOrc): + when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc): conf.m.fileInfos[fileIdx.int32].hash = hash else: shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash) @@ -234,7 +234,7 @@ proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) = proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string = assert fileIdx.int32 >= 0 - when defined(gcArc) or defined(gcOrc): + when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc): result = conf.m.fileInfos[fileIdx.int32].hash else: shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash) diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim index 78c24bae30..b5a7ba42b5 100644 --- a/compiler/nimfix/prettybase.nim +++ b/compiler/nimfix/prettybase.nim @@ -22,7 +22,7 @@ proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PIdent let last = first+identLen(line, first)-1 if cmpIgnoreStyle(line[first..last], oldSym.s) == 0: var x = line.substr(0, first-1) & newSym.s & line.substr(last+1) - when defined(gcArc) or defined(gcOrc): + when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc): conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x else: system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x) @@ -38,7 +38,7 @@ proc replaceComment*(conf: ConfigRef; info: TLineInfo) = if line[first] != '#': inc first var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape - when defined(gcArc) or defined(gcOrc): + when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc): conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x else: system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x) diff --git a/compiler/options.nim b/compiler/options.nim index da9c9cbbb9..a9f1e75424 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -184,6 +184,7 @@ type gcRegions = "regions" gcArc = "arc" gcOrc = "orc" + gcAtomicArc = "atomicArc" gcMarkAndSweep = "markAndSweep" gcHooks = "hooks" gcRefc = "refc" diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 10d77a17e9..31414063a5 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -535,7 +535,7 @@ proc processCompile(c: PContext, n: PNode) = n[i] = c.semConstExpr(c, n[i]) case n[i].kind of nkStrLit, nkRStrLit, nkTripleStrLit: - when defined(gcArc) or defined(gcOrc): + when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc): result = n[i].strVal else: shallowCopy(result, n[i].strVal) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 27ea94aae8..21b0eb1956 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -227,7 +227,7 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; if optOwnedRefs in oldGlobalOptions: conf.globalOptions.incl {optTinyRtti, optOwnedRefs, optSeqDestructors} defineSymbol(conf.symbols, "nimv2") - if conf.selectedGC in {gcArc, gcOrc}: + if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}: conf.globalOptions.incl {optTinyRtti, optSeqDestructors} defineSymbol(conf.symbols, "nimv2") diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a01466868b..4dd7840f14 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -249,7 +249,7 @@ proc isCastable(c: PContext; dst, src: PType, info: TLineInfo): bool = if skipTypes(dst, abstractInst).kind == tyBuiltInTypeClass: return false let conf = c.config - if conf.selectedGC in {gcArc, gcOrc}: + if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}: let d = skipTypes(dst, abstractInst) let s = skipTypes(src, abstractInst) if d.kind == tyRef and s.kind == tyRef and s[0].isFinal != d[0].isFinal: diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index baa37a45f9..7024c99fe7 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1480,7 +1480,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = let param = params[i].sym let typ = param.typ if isSinkTypeForParam(typ) or - (t.config.selectedGC in {gcArc, gcOrc} and + (t.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and (isClosure(typ.skipTypes(abstractInst)) or param.id in t.escapingParams)): createTypeBoundOps(t, typ, param.info) if isOutParam(typ) and param.id notin t.init: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 750ab2216b..f4b284f7e1 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -968,7 +968,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = t.rawAddSonNoPropagationOfTypeFlags result result = t else: discard - if result.kind == tyRef and c.config.selectedGC in {gcArc, gcOrc}: + if result.kind == tyRef and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: result.flags.incl tfHasAsgn proc findEnforcedStaticType(t: PType): PType = diff --git a/compiler/spawn.nim b/compiler/spawn.nim index add36759da..7423fdfaa4 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -37,7 +37,7 @@ proc spawnResult*(t: PType; inParallel: bool): TSpawnResult = else: srFlowVar proc flowVarKind(c: ConfigRef, t: PType): TFlowVarKind = - if c.selectedGC in {gcArc, gcOrc}: fvBlob + if c.selectedGC in {gcArc, gcOrc, gcAtomicArc}: fvBlob elif t.skipTypes(abstractInst).kind in {tyRef, tyString, tySequence}: fvGC elif containsGarbageCollectedRef(t): fvInvalid else: fvBlob @@ -66,7 +66,7 @@ proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; idgen: IdGenerator; vpart[2] = if varInit.isNil: v else: vpart[1] varSection.add vpart if varInit != nil: - if g.config.selectedGC in {gcArc, gcOrc}: + if g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: # inject destructors pass will do its own analysis varInit.add newFastMoveStmt(g, newSymNode(result), v) else: diff --git a/compiler/vm.nim b/compiler/vm.nim index dbb02cffa8..ba3677cf1b 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -121,7 +121,7 @@ template decodeBx(k: untyped) {.dirty.} = ensureKind(k) template move(a, b: untyped) {.dirty.} = - when defined(gcArc) or defined(gcOrc): + when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc): a = move b else: system.shallowCopy(a, b) @@ -550,7 +550,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = # Used to keep track of where the execution is resumed. var savedPC = -1 var savedFrame: PStackFrame - when defined(gcArc) or defined(gcOrc): + when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc): template updateRegsAlias = discard template regs: untyped = tos.slots else: diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 55c4c412af..acb07174b0 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -57,6 +57,21 @@ elif defined(nimArcIds): const traceId = -1 +when defined(gcAtomicArc) and hasThreadSupport: + template decrement(cell: Cell): untyped = + discard atomicDec(cell.rc, rcIncrement) + template increment(cell: Cell): untyped = + discard atomicInc(cell.rc, rcIncrement) + template count(x: Cell): untyped = + atomicLoadN(x.rc.addr, ATOMIC_ACQUIRE) shr rcShift +else: + template decrement(cell: Cell): untyped = + dec(cell.rc, rcIncrement) + template increment(cell: Cell): untyped = + inc(cell.rc, rcIncrement) + template count(x: Cell): untyped = + x.rc shr rcShift + proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} = let hdrSize = align(sizeof(RefHeader), alignment) let s = size + hdrSize @@ -69,7 +84,7 @@ proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} = atomicInc gRefId if head(result).refId == traceId: writeStackTrace() - cfprintf(cstderr, "[nimNewObj] %p %ld\n", result, head(result).rc shr rcShift) + cfprintf(cstderr, "[nimNewObj] %p %ld\n", result, head(result).count) when traceCollector: cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) @@ -90,21 +105,21 @@ proc nimNewObjUninit(size, alignment: int): pointer {.compilerRtl.} = atomicInc gRefId if head(result).refId == traceId: writeStackTrace() - cfprintf(cstderr, "[nimNewObjUninit] %p %ld\n", result, head(result).rc shr rcShift) + cfprintf(cstderr, "[nimNewObjUninit] %p %ld\n", result, head(result).count) when traceCollector: cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) proc nimDecWeakRef(p: pointer) {.compilerRtl, inl.} = - dec head(p).rc, rcIncrement + decrement head(p) proc nimIncRef(p: pointer) {.compilerRtl, inl.} = when defined(nimArcDebug): if head(p).refId == traceId: writeStackTrace() - cfprintf(cstderr, "[IncRef] %p %ld\n", p, head(p).rc shr rcShift) + cfprintf(cstderr, "[IncRef] %p %ld\n", p, head(p).count) - inc head(p).rc, rcIncrement + increment head(p) when traceCollector: cprintf("[INCREF] %p\n", head(p)) @@ -173,17 +188,17 @@ proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} = when defined(nimArcDebug): if cell.refId == traceId: writeStackTrace() - cfprintf(cstderr, "[DecRef] %p %ld\n", p, cell.rc shr rcShift) + cfprintf(cstderr, "[DecRef] %p %ld\n", p, cell.count) - if (cell.rc and not rcMask) == 0: + if cell.count == 0: result = true when traceCollector: cprintf("[ABOUT TO DESTROY] %p\n", cell) else: - dec cell.rc, rcIncrement + decrement cell # According to Lins it's correct to do nothing else here. when traceCollector: - cprintf("[DeCREF] %p\n", cell) + cprintf("[DECREF] %p\n", cell) proc nimDupRef(dest: ptr pointer, src: pointer) {.compilerRtl, inl.} = dest[] = src From e45eb39ef7c194ee16a9fd3c2d08997f62c44375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Mon, 8 May 2023 16:04:27 +0100 Subject: [PATCH 066/489] documents codegendecl for object types (#21811) --- doc/manual.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/doc/manual.md b/doc/manual.md index cb2509bd28..93f13f8181 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -8072,8 +8072,8 @@ CodegenDecl pragma ------------------ The `codegenDecl` pragma can be used to directly influence Nim's code -generator. It receives a format string that determines how the variable -or proc is declared in the generated code. +generator. It receives a format string that determines how the variable, +proc or object type is declared in the generated code. For variables, $1 in the format string represents the type of the variable, $2 is the name of the variable, and each appearance of $# represents $1/$2 @@ -8108,7 +8108,30 @@ will generate this code: ```c __interrupt void myinterrupt() ``` + +For object types, the $1 represents the name of the object type, $2 is the list of +fields and $3 is the base type. +```nim + +const strTemplate = """ + struct $1 { + $2 + }; +""" +type Foo {.codegenDecl:strTemplate.} = object + a, b: int +``` + +will generate this code: + + +```c +struct Foo { + NI a; + NI b; +}; +``` `cppNonPod` pragma ------------------ From ec3bca8fab723563bc9fb99ce9d5161652ce6945 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 8 May 2023 18:52:47 +0200 Subject: [PATCH 067/489] =?UTF-8?q?Windows:=20use=20=5F=5Fdeclspec(thread)?= =?UTF-8?q?=20TLS=20implementation,=20it=20is=20MUCH=20faster=E2=80=A6=20(?= =?UTF-8?q?#21810)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Windows: use __declspec(thread) TLS implementation, it is MUCH faster than _Thread_local [backport] * Update lib/nimbase.h * better fix --- lib/nimbase.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/nimbase.h b/lib/nimbase.h index b9b2695c9a..570b50b081 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -125,7 +125,13 @@ __AVR__ NIM_THREADVAR declaration based on http://stackoverflow.com/questions/18298280/how-to-declare-a-variable-as-thread-local-portably */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__ +#if defined _WIN32 +# if defined _MSC_VER || defined __DMC__ || defined __BORLANDC__ +# define NIM_THREADVAR __declspec(thread) +# else +# define NIM_THREADVAR __thread +# endif +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__ # define NIM_THREADVAR _Thread_local #elif defined _WIN32 && ( \ defined _MSC_VER || \ From 4ee70165f1f0646df34ae35b7c98bd8b7d1d6d5d Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Mon, 8 May 2023 13:53:32 -0300 Subject: [PATCH 068/489] Add build-id=none for GCC when build for Release (#21808) * Add build-id=none to GCC/Clang, unneeded metadata in binaries * Add build-id=none to GCC/Clang, unneeded metadata in binaries * Add build-id=none to Clang * Fix * Fix * Add build-id=none to GCC --- changelogs/changelog_2_0_0.md | 1 + config/nim.cfg | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 1e0b427b68..8852e398fa 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -454,6 +454,7 @@ static libraries. - When compiling for Release the flag `-fno-math-errno` is used for GCC. +- When compiling for Release the flag `--build-id=none` is used for GCC Linker. ## Docgen diff --git a/config/nim.cfg b/config/nim.cfg index 13665936b6..cc27d5a3d6 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -364,3 +364,9 @@ tcc.options.always = "-w" clang.options.linker %= "${clang.options.linker} -s" clang.cpp.options.linker %= "${clang.cpp.options.linker} -s" @end + +# Linker: Skip "Build-ID metadata strings" in binaries when build for release. +@if release or danger: + gcc.options.linker %= "${gcc.options.linker} -Wl,--build-id=none" + gcc.cpp.options.linker %= "${gcc.cpp.options.linker} -Wl,--build-id=none" +@end From 5491e0c27419c13a0566ab3ed99ebeedccaf9a5c Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 9 May 2023 16:37:32 +0300 Subject: [PATCH 069/489] re-enable badssl test (#21775) test reenable badssl --- tests/untestable/thttpclient_ssl_remotenetwork.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/untestable/thttpclient_ssl_remotenetwork.nim b/tests/untestable/thttpclient_ssl_remotenetwork.nim index 65f7cc8d61..3cb7595162 100644 --- a/tests/untestable/thttpclient_ssl_remotenetwork.nim +++ b/tests/untestable/thttpclient_ssl_remotenetwork.nim @@ -32,8 +32,8 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win good, bad, dubious, good_broken, bad_broken, dubious_broken CertTest = tuple[url:string, category:Category, desc: string] - # XXX re-enable when badssl fixes certs, some expired as of 2023-04-23 (#21709) - when false: + # badssl certs sometimes expire, set to false when that happens + when true: const certificate_tests: array[0..54, CertTest] = [ ("https://wrong.host.badssl.com/", bad, "wrong.host"), ("https://captive-portal.badssl.com/", bad, "captive-portal"), @@ -196,8 +196,8 @@ when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(win type NetSocketTest = tuple[hostname: string, port: Port, category:Category, desc: string] - # XXX re-enable when badssl fixes certs, some expired as of 2023-04-23 (#21709) - when false: + # badssl certs sometimes expire, set to false when that happens + when true: const net_tests:array[0..3, NetSocketTest] = [ ("imap.gmail.com", 993.Port, good, "IMAP"), ("wrong.host.badssl.com", 443.Port, bad, "wrong.host"), From b169dad1e5083eae333ba9a7e11fed74a05385de Mon Sep 17 00:00:00 2001 From: Jordan Gillard Date: Tue, 9 May 2023 14:33:35 -0400 Subject: [PATCH 070/489] Improve and refactor cellseqs_v2 in Nim standard library (#21796) * Refactor and optimize cellseqs_v2 in Nim standard library * Extract resizing logic into a separate 'resize' procedure for better readability and separation of concerns * Implement realloc for non-threaded cases to improve memory operations efficiency * Use ',' instead of ';' between parameters in 'add' procedure for consistency with other Nim code * Respond to Araq's feedback: Refactor resize function to use reallocShared This commit replaces the usage of allocShared and deallocShared with reallocShared to optimize memory allocation and deallocation while resizing the CellSeq. --- lib/system/cellseqs_v2.nim | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/system/cellseqs_v2.nim b/lib/system/cellseqs_v2.nim index 27be48d78e..c6c7b1a8e2 100644 --- a/lib/system/cellseqs_v2.nim +++ b/lib/system/cellseqs_v2.nim @@ -16,20 +16,17 @@ type len, cap: int d: CellArray[T] -proc add[T](s: var CellSeq[T], c: T; t: PNimTypeV2) {.inline.} = +proc resize[T](s: var CellSeq[T]) = + s.cap = s.cap * 3 div 2 + var newSize = s.cap * sizeof(CellTuple[T]) + when compileOption("threads"): + s.d = cast[CellArray[T]](reallocShared(s.d, newSize)) + else: + s.d = cast[CellArray[T]](realloc(s.d, newSize)) + +proc add[T](s: var CellSeq[T], c: T, t: PNimTypeV2) {.inline.} = if s.len >= s.cap: - s.cap = s.cap * 3 div 2 - when compileOption("threads"): - var d = cast[CellArray[T]](allocShared(uint(s.cap * sizeof(CellTuple[T])))) - else: - var d = cast[CellArray[T]](alloc(s.cap * sizeof(CellTuple[T]))) - copyMem(d, s.d, s.len * sizeof(CellTuple[T])) - when compileOption("threads"): - deallocShared(s.d) - else: - dealloc(s.d) - s.d = d - # XXX: realloc? + s.resize() s.d[s.len] = (c, t) inc(s.len) From 5592d1ef2c7ab61e8f7a1401bc89cf4e090126be Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 9 May 2023 21:34:39 +0300 Subject: [PATCH 071/489] fix nimrtl and nimhcr on arc/orc (#21814) * fix/workaround for nimrtl and nimhcr on arc/orc fixes #21803 * try fix clang, debug linux failure * just make duplicated procs not rtl * actual fix for duplicated procs --- lib/nimhcr.nim | 16 ++++++++++------ lib/system/arc.nim | 2 +- lib/system/seqs_v2.nim | 2 +- lib/system/strs_v2.nim | 4 ++-- testament/categories.nim | 21 +++++++++------------ 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/lib/nimhcr.nim b/lib/nimhcr.nim index 8bccfc22e5..2a74cc92de 100644 --- a/lib/nimhcr.nim +++ b/lib/nimhcr.nim @@ -305,7 +305,7 @@ when defined(createNimHcr): hash: string gen: int lastModification: Time - handlers: seq[tuple[isBefore: bool, cb: proc ()]] + handlers: seq[tuple[isBefore: bool, cb: proc () {.nimcall.}]] proc newModuleDesc(): ModuleDesc = result.procs = initTable[string, ProcSym]() @@ -557,8 +557,12 @@ when defined(createNimHcr): # Future versions of NIMHCR won't use the GC, because all globals and the # metadata needed to access them will be placed in shared memory, so they # can be manipulated from external programs without reloading. - GC_disable() - defer: GC_enable() + when declared(GC_disable): + GC_disable() + defer: GC_enable() + elif declared(GC_disableOrc): + GC_disableOrc() + defer: GC_enableOrc() inc(generation) trace "HCR RELOADING: ", generation @@ -598,7 +602,7 @@ when defined(createNimHcr): hashToModuleMap.del(modules[name].hash) modules.del(name) - proc hcrAddEventHandler*(isBefore: bool, cb: proc ()) {.nimhcr.} = + proc hcrAddEventHandler*(isBefore: bool, cb: proc () {.nimcall.}) {.nimhcr.} = modules[currentModule].handlers.add( (isBefore: isBefore, cb: cb)) @@ -649,7 +653,7 @@ elif defined(hotcodereloading) or defined(testNimHcr): proc hcrPerformCodeReload*() {.nimhcr.} - proc hcrAddEventHandler*(isBefore: bool, cb: proc ()) {.nimhcr.} + proc hcrAddEventHandler*(isBefore: bool, cb: proc () {.nimcall.}) {.nimhcr.} proc hcrMarkGlobals*() {.raises: [], nimhcr, nimcall, gcsafe.} @@ -661,7 +665,7 @@ elif defined(hotcodereloading) or defined(testNimHcr): # TODO false - proc hcrAddEventHandler*(isBefore: bool, cb: proc ()) = + proc hcrAddEventHandler*(isBefore: bool, cb: proc () {.nimcall.}) = # TODO discard diff --git a/lib/system/arc.nim b/lib/system/arc.nim index acb07174b0..cc93eb9fca 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -226,5 +226,5 @@ template tearDownForeignThreadGc* = ## With `--gc:arc` a nop. discard -proc isObjDisplayCheck(source: PNimTypeV2, targetDepth: int16, token: uint32): bool {.compilerRtl, inline.} = +proc isObjDisplayCheck(source: PNimTypeV2, targetDepth: int16, token: uint32): bool {.compilerRtl, inl.} = result = targetDepth <= source.depth and source.display[targetDepth] == token diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index f176c0a4a7..4bebf4a827 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -48,7 +48,7 @@ template `-!`(p: pointer, s: int): pointer = cast[pointer](cast[int](p) -% s) proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {. - noSideEffect, raises: [], compilerRtl.} = + noSideEffect, tags: [], raises: [], compilerRtl.} = {.noSideEffect.}: let headerSize = align(sizeof(NimSeqPayloadBase), elemAlign) if addlen <= 0: diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index 429724dab6..296aae045f 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -62,7 +62,7 @@ proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} = s.p = cast[ptr NimStrPayload](realloc0(s.p, contentSize(oldCap), contentSize(newCap))) s.p.cap = newCap -proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl, inline.} = +proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl, inl.} = #if (s.p == nil) or (s.len+1 > s.p.cap and not strlitFlag): prepareAdd(s, 1) s.p.data[s.len] = c @@ -165,7 +165,7 @@ proc nimPrepareStrMutationImpl(s: var NimStringV2) = s.p.cap = s.len copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1) -proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl, inline.} = +proc nimPrepareStrMutationV2(s: var NimStringV2) {.compilerRtl, inl.} = if s.p != nil and (s.p.cap and strlitFlag) == strlitFlag: nimPrepareStrMutationImpl(s) diff --git a/testament/categories.nim b/testament/categories.nim index c428ffc04c..d554ebe349 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -53,18 +53,16 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string, isOrc = else: "" - if not defined(windows) or not isOrc: # todo fix me on windows - var test1 = makeTest("lib/nimrtl.nim", options & " --outdir:tests/dll", cat) - test1.spec.action = actionCompile - testSpec c, test1 + var test1 = makeTest("lib/nimrtl.nim", options & " --outdir:tests/dll", cat) + test1.spec.action = actionCompile + testSpec c, test1 var test2 = makeTest("tests/dll/server.nim", options & " --threads:on" & rpath, cat) test2.spec.action = actionCompile testSpec c, test2 - if not isOrc: - var test3 = makeTest("lib/nimhcr.nim", options & " --threads:off --outdir:tests/dll" & rpath, cat) - test3.spec.action = actionCompile - testSpec c, test3 + var test3 = makeTest("lib/nimhcr.nim", options & " --threads:off --outdir:tests/dll" & rpath, cat) + test3.spec.action = actionCompile + testSpec c, test3 var test4 = makeTest("tests/dll/visibility.nim", options & " --threads:off --app:lib" & rpath, cat) test4.spec.action = actionCompile testSpec c, test4 @@ -79,9 +77,8 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string, isOrc = putEnv(libpathenv, "tests/dll" & (if libpath.len > 0: ":" & libpath else: "")) defer: putEnv(libpathenv, libpath) - if not isOrc: - testSpec r, makeTest("tests/dll/client.nim", options & " --threads:on" & rpath, cat) - testSpec r, makeTest("tests/dll/nimhcr_unit.nim", options & " --threads:off" & rpath, cat) + testSpec r, makeTest("tests/dll/client.nim", options & " --threads:on" & rpath, cat) + testSpec r, makeTest("tests/dll/nimhcr_unit.nim", options & " --threads:off" & rpath, cat) testSpec r, makeTest("tests/dll/visibility.nim", options & " --threads:off" & rpath, cat) if "boehm" notin options: @@ -686,7 +683,7 @@ proc processCategory(r: var TResults, cat: Category, else: jsTests(r, cat, options) of "dll": - dllTests(r, cat, options) + dllTests(r, cat, options & " -d:nimDebugDlOpen") of "gc": gcTests(r, cat, options) of "debugger": From 4b76037e5fe14f75ac5381a0d08ad509f450cf56 Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 9 May 2023 22:44:47 +0300 Subject: [PATCH 072/489] ignore inline hint for dynlib procs in codegen [backport] (#21817) --- compiler/cgen.nim | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 65f8040f5b..17b0350b6c 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1270,6 +1270,20 @@ proc genProcNoForward(m: BModule, prc: PSym) = if lfNoDecl in prc.loc.flags: fillProcLoc(m, prc.ast[namePos]) genProcPrototype(m, prc) + elif lfDynamicLib in prc.loc.flags: + var q = findPendingModule(m, prc) + fillProcLoc(q, prc.ast[namePos]) + genProcPrototype(m, prc) + if q != nil and not containsOrIncl(q.declaredThings, prc.id): + symInDynamicLib(q, prc) + # register the procedure even though it is in a different dynamic library and will not be + # reloadable (and has no _actual suffix) - other modules will need to be able to get it through + # the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded) + if isReloadable(q, prc): + q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n", + [prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)]) + else: + symInDynamicLibPartial(m, prc) elif prc.typ.callConv == ccInline: # We add inline procs to the calling module to enable C based inlining. # This also means that a check with ``q.declaredThings`` is wrong, we need @@ -1288,20 +1302,6 @@ proc genProcNoForward(m: BModule, prc: PSym) = # prc.loc.r = mangleName(m, prc) genProcPrototype(m, prc) genProcAux(m, prc) - elif lfDynamicLib in prc.loc.flags: - var q = findPendingModule(m, prc) - fillProcLoc(q, prc.ast[namePos]) - genProcPrototype(m, prc) - if q != nil and not containsOrIncl(q.declaredThings, prc.id): - symInDynamicLib(q, prc) - # register the procedure even though it is in a different dynamic library and will not be - # reloadable (and has no _actual suffix) - other modules will need to be able to get it through - # the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded) - if isReloadable(q, prc): - q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n", - [prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)]) - else: - symInDynamicLibPartial(m, prc) elif sfImportc notin prc.flags: var q = findPendingModule(m, prc) fillProcLoc(q, prc.ast[namePos]) From deaf6843752112cfaadc688302c94779d633c686 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 10 May 2023 17:06:14 +0800 Subject: [PATCH 073/489] fix #9423 followup #17594: distinct generics now work in VM (#21816) * fix #9423 distinct generics now work in vm * fixes cpp tests --------- Co-authored-by: Timothee Cour --- compiler/vmgen.nim | 15 ++++++++++++--- lib/pure/json.nim | 8 +------- lib/std/jsonutils.nim | 7 +------ tests/distinct/tdistinct.nim | 26 +++++++++++++++++++++++++- tests/stdlib/tjsonutils.nim | 3 +-- 5 files changed, 40 insertions(+), 19 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 25ff62bcc7..067965469c 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -850,7 +850,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) = let targ2 = arg.typ.skipTypes({tyDistinct}) proc implicitConv(): bool = - if sameType(t2, targ2): return true + if sameBackendType(t2, targ2): return true # xxx consider whether to use t2 and targ2 here if n.typ.kind == arg.typ.kind and arg.typ.kind == tyProc: # don't do anything for lambda lifting conversions: @@ -1416,7 +1416,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = proc unneededIndirection(n: PNode): bool = n.typ.skipTypes(abstractInstOwned-{tyTypeDesc}).kind == tyRef -proc canElimAddr(n: PNode): PNode = +proc canElimAddr(n: PNode; idgen: IdGenerator): PNode = case n[0].kind of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: var m = n[0][0] @@ -1424,19 +1424,28 @@ proc canElimAddr(n: PNode): PNode = # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x) result = copyNode(n[0]) result.add m[0] + if n.typ.skipTypes(abstractVar).kind != tyOpenArray: + result.typ = n.typ + elif n.typ.skipTypes(abstractInst).kind in {tyVar}: + result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen) of nkHiddenStdConv, nkHiddenSubConv, nkConv: var m = n[0][1] if m.kind in {nkDerefExpr, nkHiddenDeref}: # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x) result = copyNode(n[0]) + result.add n[0][0] result.add m[0] + if n.typ.skipTypes(abstractVar).kind != tyOpenArray: + result.typ = n.typ + elif n.typ.skipTypes(abstractInst).kind in {tyVar}: + result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, idgen) else: if n[0].kind in {nkDerefExpr, nkHiddenDeref}: # addr ( deref ( x )) --> x result = n[0][0] proc genAddr(c: PCtx, n: PNode, dest: var TDest, flags: TGenFlags) = - if (let m = canElimAddr(n); m != nil): + if (let m = canElimAddr(n, c.idgen); m != nil): gen(c, m, dest, flags) return diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 7ccd3c43f5..b68ddd6604 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1211,13 +1211,7 @@ macro assignDistinctImpl[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: v let baseTyp = typImpl[0] result = quote do: - when nimvm: - # workaround #12282 - var tmp: `baseTyp` - initFromJson( tmp, `jsonNode`, `jsonPath`) - `dst` = `typInst`(tmp) - else: - initFromJson( `baseTyp`(`dst`), `jsonNode`, `jsonPath`) + initFromJson(`baseTyp`(`dst`), `jsonNode`, `jsonPath`) proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) = assignDistinctImpl(dst, jsonNode, jsonPath) diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 71f4389054..f17407f20e 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -222,12 +222,7 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = elif T is uint|uint64: a = T(to(b, uint64)) elif T is Ordinal: a = cast[T](to(b, int)) elif T is pointer: a = cast[pointer](to(b, int)) - elif T is distinct: - when nimvm: - # bug, potentially related to https://github.com/nim-lang/Nim/issues/12282 - a = T(jsonTo(b, distinctBase(T))) - else: - a.distinctBase.fromJson(b) + elif T is distinct: a.distinctBase.fromJson(b) elif T is string|SomeNumber: a = to(b,T) elif T is cstring: case b.kind diff --git a/tests/distinct/tdistinct.nim b/tests/distinct/tdistinct.nim index 8ec0830208..b6ba7aa993 100644 --- a/tests/distinct/tdistinct.nim +++ b/tests/distinct/tdistinct.nim @@ -159,7 +159,7 @@ block: #17322 type Foo = distinct string -template main() = +proc main() = # proc instead of template because of MCS/UFCS. # xxx put everything here to test under RT + VM block: # bug #12282 block: @@ -199,5 +199,29 @@ template main() = var c: B + block: # bug #9423 + block: + type Foo = seq[int] + type Foo2 = distinct Foo + template fn() = + var a = Foo2(@[1]) + a.Foo.add 2 + doAssert a.Foo == @[1, 2] + fn() + + block: + type Stack[T] = distinct seq[T] + proc newStack[T](): Stack[T] = + Stack[T](newSeq[T]()) + proc push[T](stack: var Stack[T], elem: T) = + seq[T](stack).add(elem) + proc len[T](stack: Stack[T]): int = + seq[T](stack).len + proc fn() = + var stack = newStack[int]() + stack.push(5) + doAssert stack.len == 1 + fn() + static: main() main() diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim index d6f9023018..9acf4c9e54 100644 --- a/tests/stdlib/tjsonutils.nim +++ b/tests/stdlib/tjsonutils.nim @@ -61,8 +61,7 @@ template fn() = testRoundtrip(pointer(nil)): """0""" testRoundtrip(cast[pointer](nil)): """0""" - # causes workaround in `fromJson` potentially related to - # https://github.com/nim-lang/Nim/issues/12282 + # refs bug #9423 testRoundtrip(Foo(1.5)): """1.5""" block: # OrderedTable From f3a4cc584e778378d7f0d84e352076ca01068170 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 10 May 2023 12:54:43 +0200 Subject: [PATCH 074/489] make ORC threadlocal, take two (#21818) * ORC: make rootsThreshold thread local [backport] * fixes the regression --- lib/system/orc.nim | 12 ++++++------ tests/arc/tasyncleak.nim | 2 +- tests/arc/topt_no_cursor.nim | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/system/orc.nim b/lib/system/orc.nim index a56a0c0574..1935407102 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -350,7 +350,7 @@ const when defined(nimStressOrc): const rootsThreshold = 10 # broken with -d:nimStressOrc: 10 and for havlak iterations 1..8 else: - var rootsThreshold = defaultThreshold + var rootsThreshold {.threadvar.}: int proc partialCollect(lowMark: int) = when false: @@ -392,16 +392,16 @@ proc collectCycles() = # of the cycle collector's effectiveness: # we're effective when we collected 50% or more of the nodes # we touched. If we're effective, we can reset the threshold: - if j.keepThreshold and rootsThreshold <= defaultThreshold: + if j.keepThreshold: discard elif j.freed * 2 >= j.touched: when not defined(nimFixedOrc): rootsThreshold = max(rootsThreshold div 3 * 2, 16) else: - rootsThreshold = defaultThreshold + rootsThreshold = 0 #cfprintf(cstderr, "[collectCycles] freed %ld, touched %ld new threshold %ld\n", j.freed, j.touched, rootsThreshold) elif rootsThreshold < high(int) div 4: - rootsThreshold = rootsThreshold * 3 div 2 + rootsThreshold = (if rootsThreshold <= 0: defaultThreshold else: rootsThreshold) * 3 div 2 when logOrc: cfprintf(cstderr, "[collectCycles] end; freed %ld new threshold %ld touched: %ld mem: %ld rcSum: %ld edges: %ld\n", j.freed, rootsThreshold, j.touched, getOccupiedMem(), j.rcSum, j.edges) @@ -411,7 +411,7 @@ proc registerCycle(s: Cell; desc: PNimTypeV2) = if roots.d == nil: init(roots) add(roots, s, desc) - if roots.len >= rootsThreshold: + if roots.len >= rootsThreshold+defaultThreshold: collectCycles() when logOrc: writeCell("[added root]", s, desc) @@ -427,7 +427,7 @@ proc GC_enableOrc*() = ## Enables the cycle collector subsystem of `--gc:orc`. This is a `--gc:orc` ## specific API. Check with `when defined(gcOrc)` for its existence. when not defined(nimStressOrc): - rootsThreshold = defaultThreshold + rootsThreshold = 0 proc GC_disableOrc*() = ## Disables the cycle collector subsystem of `--gc:orc`. This is a `--gc:orc` diff --git a/tests/arc/tasyncleak.nim b/tests/arc/tasyncleak.nim index eb0c452131..8e3a7b3e7b 100644 --- a/tests/arc/tasyncleak.nim +++ b/tests/arc/tasyncleak.nim @@ -1,5 +1,5 @@ discard """ - outputsub: "(allocCount: 4302, deallocCount: 4300)" + outputsub: "(allocCount: 4050, deallocCount: 4048)" cmd: "nim c --gc:orc -d:nimAllocStats $file" """ diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index ddcc549d1f..32652b60a5 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -1,6 +1,6 @@ discard """ nimoutFull: true - cmd: '''nim c -r --warnings:off --hints:off --gc:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig --expandArc:mergeShadowScope --expandArc:check $file''' + cmd: '''nim c -r --warnings:off --hints:off --mm:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig --expandArc:mergeShadowScope --expandArc:check $file''' nimout: ''' --expandArc: newTarget From 71439c2891ff1e6b685210f043677b0f7562b429 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 11 May 2023 15:00:30 +0800 Subject: [PATCH 075/489] fixes links of generic `define` pragma (#21828) --- changelogs/changelog_2_0_0.md | 2 +- doc/manual.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 8852e398fa..17e3d32e56 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -364,7 +364,7 @@ ``` - A generic `define` pragma for constants has been added that interprets the value of the define based on the type of the constant value. - See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-define-pragma) + See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-nimdefine-pragma) for a list of supported types. - [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes: diff --git a/doc/manual.md b/doc/manual.md index 93f13f8181..ed225e51bd 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -8196,7 +8196,7 @@ define names. This helps disambiguate define names in different packages. -See also the [generic `define` pragma](manual_experimental.html#generic-define-pragma) +See also the [generic `define` pragma](manual_experimental.html#generic-nimdefine-pragma) for a version of these pragmas that detects the type of the define based on the constant value. From 055a00a6eff6fabd0f5fdf061d0eb28d07aa41a9 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 11 May 2023 15:02:29 +0800 Subject: [PATCH 076/489] make `reset` use the `=destroy` and `wasMoved` pair (#21821) * make reset use the `=destroy` and `waMoved` pair * fixes a space * fixes `shrink` instead * tiny fix * fixes vm * suppress the annotations since it breaks some important packages --- lib/system.nim | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 8bb50ba5d4..e8664d7a47 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -906,7 +906,15 @@ proc default*[T](_: typedesc[T]): T {.magic: "Default", noSideEffect.} = proc reset*[T](obj: var T) {.noSideEffect.} = ## Resets an object `obj` to its default value. - obj = default(typeof(obj)) + when nimvm: + obj = default(typeof(obj)) + else: + when defined(gcDestructors): + {.cast(noSideEffect), cast(raises: []), cast(tags: []).}: + `=destroy`(obj) + wasMoved(obj) + else: + obj = default(typeof(obj)) proc setLen*[T](s: var seq[T], newlen: Natural) {. magic: "SetLengthSeq", noSideEffect.} From 3a08e2e6ace20f086ba24360c7139852a75b93b2 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 11 May 2023 05:10:51 -0300 Subject: [PATCH 077/489] Remove LineTooLong (#21819) * LineTooLong refactor to make it actually useful * Improve error message * changelog wording * Fix typo --- changelogs/changelog_2_0_0.md | 2 ++ compiler/lexer.nim | 5 ----- compiler/lineinfos.nim | 2 -- compiler/options.nim | 1 + config/nim.cfg | 1 - doc/manual.md | 20 ++++++++++---------- doc/nimc.md | 1 - 7 files changed, 13 insertions(+), 19 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 17e3d32e56..e89cb6b624 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -455,6 +455,8 @@ - When compiling for Release the flag `-fno-math-errno` is used for GCC. - When compiling for Release the flag `--build-id=none` is used for GCC Linker. +- Removed deprecated `LineTooLong` hint. + ## Docgen diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 67dafc59fa..5962c8b9bb 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -23,7 +23,6 @@ when defined(nimPreviewSlimSystem): import std/[assertions, formatfloat] const - MaxLineLength* = 80 # lines longer than this lead to a warning numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'} SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'} SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} @@ -736,10 +735,6 @@ proc handleCRLF(L: var Lexer, pos: int): int = template registerLine = let col = L.getColNumber(pos) - when not defined(nimpretty): - if col > MaxLineLength: - lexMessagePos(L, hintLineTooLong, pos) - case L.buf[pos] of CR: registerLine() diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 7a51a4db7e..f6d0d62640 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -94,7 +94,6 @@ type # hints hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC", - hintLineTooLong = "LineTooLong", hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintDuplicateModuleImport = "DuplicateModuleImport", hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded", hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX", @@ -198,7 +197,6 @@ const # keep in sync with `testament.isSuccess` hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output", hintCC: "CC: $1", - hintLineTooLong: "line too long", hintXDeclaredButNotUsed: "'$1' is declared but not used", hintDuplicateModuleImport: "$1", hintXCannotRaiseY: "$1", diff --git a/compiler/options.nim b/compiler/options.nim index a9f1e75424..c0b99744c3 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -416,6 +416,7 @@ type expandNodeResult*: string expandPosition*: TLineInfo + proc parseNimVersion*(a: string): NimVer = # could be moved somewhere reusable if a.len > 0: diff --git a/config/nim.cfg b/config/nim.cfg index cc27d5a3d6..656885e0c3 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -14,7 +14,6 @@ cc = gcc # additional options always passed to the compiler: --parallel_build: "0" # 0 to auto-detect number of processors -hint[LineTooLong]=off @if nimHasAmbiguousEnumHint: # not needed if hint is a style check hint[AmbiguousEnum]=off diff --git a/doc/manual.md b/doc/manual.md index ed225e51bd..7fe9923f41 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -6889,7 +6889,7 @@ iterator in which case the overloading resolution takes place: var x = 4 write(stdout, x) # not ambiguous: uses the module C's x ``` -Modules can share their name, however, when trying to qualify a identifier with the module name the compiler will fail with ambiguous identifier error. One can qualify the identifier by aliasing the module. +Modules can share their name, however, when trying to qualify a identifier with the module name the compiler will fail with ambiguous identifier error. One can qualify the identifier by aliasing the module. ```nim @@ -6914,7 +6914,7 @@ C.fb() # Error: ambiguous identifier: 'fb' ```nim import A/C as fizz -import B/C +import B/C fizz.fb() # Works ``` @@ -7253,7 +7253,7 @@ echo foo() # 2 template foo: int = 3 ``` -This is mostly intended for macro generated code. +This is mostly intended for macro generated code. compilation option pragmas -------------------------- @@ -7323,7 +7323,7 @@ but are used to override the settings temporarily. Example: template example(): string = "https://nim-lang.org" {.pop.} - {.push deprecated, hint[LineTooLong]: off, used, stackTrace: off.} + {.push deprecated, used, stackTrace: off.} proc sample(): bool = true {.pop.} ``` @@ -7362,14 +7362,14 @@ and before any variable in a module that imports it. Disabling certain messages -------------------------- -Nim generates some warnings and hints ("line too long") that may annoy the +Nim generates some warnings and hints that may annoy the user. A mechanism for disabling certain messages is provided: Each hint and warning message is associated with a symbol. This is the message's identifier, which can be used to enable or disable the message by putting it in brackets following the pragma: ```Nim - {.hint[LineTooLong]: off.} # turn off the hint about too long lines + {.hint[XDeclaredButNotUsed]: off.} # Turn off the hint about declared but not used symbols. ``` This is often better than disabling all warnings at once. @@ -8072,7 +8072,7 @@ CodegenDecl pragma ------------------ The `codegenDecl` pragma can be used to directly influence Nim's code -generator. It receives a format string that determines how the variable, +generator. It receives a format string that determines how the variable, proc or object type is declared in the generated code. For variables, $1 in the format string represents the type of the variable, @@ -8108,7 +8108,7 @@ will generate this code: ```c __interrupt void myinterrupt() ``` - + For object types, the $1 represents the name of the object type, $2 is the list of fields and $3 is the base type. @@ -8117,7 +8117,7 @@ fields and $3 is the base type. const strTemplate = """ struct $1 { $2 - }; + }; """ type Foo {.codegenDecl:strTemplate.} = object a, b: int @@ -8130,7 +8130,7 @@ will generate this code: struct Foo { NI a; NI b; -}; +}; ``` `cppNonPod` pragma diff --git a/doc/nimc.md b/doc/nimc.md index 3abc340c66..7c42c7c1b7 100644 --- a/doc/nimc.md +++ b/doc/nimc.md @@ -115,7 +115,6 @@ 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. From 02be212daee78e3fca9f6b9524c4f3b221e552f3 Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 11 May 2023 11:23:52 +0300 Subject: [PATCH 078/489] clean up SOME pending/xxx/issue link comments (#21826) * clean up SOME pending/xxx/issue link comments * great --- compiler/condsyms.nim | 3 +- compiler/nim.nim | 5 +-- compiler/options.nim | 8 ---- compiler/renderer.nim | 8 +--- config/config.nims | 2 +- lib/pure/os.nim | 12 +++--- lib/std/exitprocs.nim | 1 - lib/std/jsbigints.nim | 4 +- lib/std/jsonutils.nim | 1 - lib/std/private/osfiles.nim | 12 ++++-- lib/std/strbasics.nim | 4 +- lib/std/sysrand.nim | 6 ++- testament/important_packages.nim | 5 +-- tests/errmsgs/t8794.nim | 28 +++----------- tests/exception/t13115.nim | 7 ---- tests/float/tfloats.nim | 3 +- tests/importalls/m4.nim | 1 - tests/lent/tbasic_lent_check.nim | 2 +- tests/macros/ttemplatesymbols.nim | 2 - tests/metatype/tcompositetypeclasses.nim | 2 +- tests/misc/tcsharpusingstatement.nim | 26 ++++--------- tests/misc/tspellsuggest.nim | 4 +- tests/misc/tspellsuggest2.nim | 4 +- tests/misc/tspellsuggest3.nim | 4 +- tests/nimdoc/trunnableexamples.nim | 13 +++---- tests/nimdoc/trunnableexamples2.nim | 11 ------ tests/overload/tstatic_with_converter.nim | 6 +-- tests/parallel/tblocking_channel.nim | 4 +- tests/stdlib/tdecls.nim | 22 +++++------ tests/stdlib/tosproc.nim | 8 ++-- tests/stdlib/trandom.nim | 45 +++++++++++++++-------- tests/stdlib/tssl.nim | 8 ++-- tests/system/tdollars.nim | 3 +- tests/vm/tvmmisc.nim | 2 +- tools/kochdocs.nim | 11 ++---- 35 files changed, 110 insertions(+), 177 deletions(-) delete mode 100644 tests/nimdoc/trunnableexamples2.nim diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 8e0e2f3004..3d14408a3c 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -47,8 +47,7 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimparsebiggestfloatmagic") # deadcode defineSymbol("nimalias") # deadcode defineSymbol("nimlocks") # deadcode - defineSymbol("nimnode") # deadcode pending `nimnode` reference in opengl package - # refs https://github.com/nim-lang/opengl/pull/79 + defineSymbol("nimnode") # deadcode defineSymbol("nimvarargstyped") # deadcode defineSymbol("nimtypedescfixed") # deadcode defineSymbol("nimKnowsNimvm") # deadcode diff --git a/compiler/nim.nim b/compiler/nim.nim index 420579b970..b28e8b20c6 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -12,10 +12,7 @@ import std/[os, strutils, parseopt] when defined(nimPreviewSlimSystem): import std/assertions -when defined(windows) and not defined(nimKochBootstrap): - # remove workaround pending bootstrap >= 1.5.1 - # refs https://github.com/nim-lang/Nim/issues/18334#issuecomment-867114536 - # alternative would be to prepend `currentSourcePath.parentDir.quoteShell` +when defined(windows): when defined(gcc): when defined(x86): {.link: "../icons/nim.res".} diff --git a/compiler/options.nim b/compiler/options.nim index c0b99744c3..e78dd72f25 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -867,14 +867,6 @@ template patchModule(conf: ConfigRef) {.dirty.} = let ov = conf.moduleOverrides[key] if ov.len > 0: result = AbsoluteFile(ov) -when (NimMajor, NimMinor) < (1, 1) or not declared(isRelativeTo): - proc isRelativeTo(path, base: string): bool = - # pending #13212 use os.isRelativeTo - let path = path.normalizedPath - let base = base.normalizedPath - let ret = relativePath(path, base) - result = path.len > 0 and not ret.startsWith ".." - const stdlibDirs* = [ "pure", "core", "arch", "pure/collections", diff --git a/compiler/renderer.nim b/compiler/renderer.nim index ea5446cb1e..f0ad21815c 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1380,15 +1380,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = of nkAccQuoted: put(g, tkAccent, "`") for i in 0.. 0 and tmp[0] in {'a'..'z', 'A'..'Z'} var useSpace = false if i == 1 and n[0].kind == nkIdent and n[0].ident.s in ["=", "'"]: diff --git a/config/config.nims b/config/config.nims index 4f3e2b13f1..5c9c88e8ad 100644 --- a/config/config.nims +++ b/config/config.nims @@ -11,7 +11,7 @@ cppDefine "NAN" when defined(nimStrictMode): # xxx add more flags here, and use `-d:nimStrictMode` in more contexts in CI. - # pending bug #14246, enable this: + # enable this: # when defined(nimHasWarningAsError): # switch("warningAsError", "UnusedImport") diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 0569e6cabe..e9408f8262 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1016,10 +1016,8 @@ func isValidFilename*(filename: string, maxLen = 259.Positive): bool {.since: (1 # deprecated declarations -when not defined(nimscript): - when not defined(js): # `noNimJs` doesn't work with templates, this should improve. - template existsFile*(args: varargs[untyped]): untyped {.deprecated: "use fileExists".} = - fileExists(args) - template existsDir*(args: varargs[untyped]): untyped {.deprecated: "use dirExists".} = - dirExists(args) - # {.deprecated: [existsFile: fileExists].} # pending bug #14819; this would avoid above mentioned issue +when not weirdTarget: + template existsFile*(args: varargs[untyped]): untyped {.deprecated: "use fileExists".} = + fileExists(args) + template existsDir*(args: varargs[untyped]): untyped {.deprecated: "use dirExists".} = + dirExists(args) diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim index 36f22a5d1a..736bf06d1b 100644 --- a/lib/std/exitprocs.nim +++ b/lib/std/exitprocs.nim @@ -81,7 +81,6 @@ when not defined(nimscript): doAssert false proc setProgramResult*(a: int) = - # pending https://github.com/nim-lang/Nim/issues/14674 when defined(js) and defined(nodejs): asm """ process.exitCode = `a`; diff --git a/lib/std/jsbigints.nim b/lib/std/jsbigints.nim index fda299e7b3..067de78b5b 100644 --- a/lib/std/jsbigints.nim +++ b/lib/std/jsbigints.nim @@ -110,7 +110,7 @@ func `==`*(x, y: JsBigInt): bool {.importjs: "(# == #)".} = doAssert big"42" == big"42" func `**`*(x, y: JsBigInt): JsBigInt {.importjs: "((#) $1 #)".} = - # (#) needed, refs https://github.com/nim-lang/Nim/pull/16409#issuecomment-760550812 + # (#) needed due to unary minus runnableExamples: doAssert big"2" ** big"64" == big"18446744073709551616" doAssert big"-2" ** big"3" == big"-8" @@ -120,8 +120,6 @@ func `**`*(x, y: JsBigInt): JsBigInt {.importjs: "((#) $1 #)".} = try: discard big"2" ** big"-1" # raises foreign `RangeError` except: ok = true doAssert ok - # pending https://github.com/nim-lang/Nim/pull/15940, simplify to: - # doAssertRaises: discard big"2" ** big"-1" # raises foreign `RangeError` func `and`*(x, y: JsBigInt): JsBigInt {.importjs: "(# & #)".} = runnableExamples: diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index f17407f20e..847761e2f8 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -371,7 +371,6 @@ proc toJsonHook*[K: string|cstring, V](t: (Table[K, V] | OrderedTable[K, V]), op ## ## See also: ## * `fromJsonHook proc<#fromJsonHook,,JsonNode>`_ - # pending PR #9217 use: toSeq(a) instead of `collect` in `runnableExamples`. runnableExamples: import std/[tables, json, sugar] let foo = ( diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim index 7f822ffcc4..78afd35dac 100644 --- a/lib/std/private/osfiles.nim +++ b/lib/std/private/osfiles.nim @@ -155,10 +155,14 @@ when hasCCopyfile: proc copyfile_state_alloc(): copyfile_state_t proc copyfile_state_free(state: copyfile_state_t): cint proc c_copyfile(src, dst: cstring, state: copyfile_state_t, flags: copyfile_flags_t): cint {.importc: "copyfile".} - # replace with `let` pending bootstrap >= 1.4.0 - var - COPYFILE_DATA {.nodecl.}: copyfile_flags_t - COPYFILE_XATTR {.nodecl.}: copyfile_flags_t + when (NimMajor, NimMinor) >= (1, 4): + let + COPYFILE_DATA {.nodecl.}: copyfile_flags_t + COPYFILE_XATTR {.nodecl.}: copyfile_flags_t + else: + var + COPYFILE_DATA {.nodecl.}: copyfile_flags_t + COPYFILE_XATTR {.nodecl.}: copyfile_flags_t {.pop.} type diff --git a/lib/std/strbasics.nim b/lib/std/strbasics.nim index be1dd7a586..b2c36a4bef 100644 --- a/lib/std/strbasics.nim +++ b/lib/std/strbasics.nim @@ -23,8 +23,8 @@ proc add*(x: var string, y: openArray[char]) = # Use `{.noalias.}` ? let n = x.len x.setLen n + y.len - # pending https://github.com/nim-lang/Nim/issues/14655#issuecomment-643671397 - # use x.setLen(n + y.len, isInit = false) + # pending #19727 + # setLen unnecessarily zeros memory var i = 0 while i < y.len: x[n + i] = y[i] diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim index d57f2845e5..7943f2e1ba 100644 --- a/lib/std/sysrand.nim +++ b/lib/std/sysrand.nim @@ -168,8 +168,10 @@ elif defined(windows): result = randomBytes(addr dest[0], size) elif defined(linux) and not defined(nimNoGetRandom) and not defined(emscripten): - # TODO using let, pending bootstrap >= 1.4.0 - var SYS_getrandom {.importc: "SYS_getrandom", header: "".}: clong + when (NimMajor, NimMinor) >= (1, 4): + let SYS_getrandom {.importc: "SYS_getrandom", header: "".}: clong + else: + var SYS_getrandom {.importc: "SYS_getrandom", header: "".}: clong const syscallHeader = """#include #include """ diff --git a/testament/important_packages.nim b/testament/important_packages.nim index c77acd99b0..7e030e92cd 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -43,7 +43,7 @@ pkg "awk" pkg "bigints" pkg "binaryheap", "nim c -r binaryheap.nim" pkg "BipBuffer" -pkg "blscurve", allowFailure = true # pending https://github.com/status-im/nim-blscurve/issues/39 +pkg "blscurve", allowFailure = true pkg "bncurve" pkg "brainfuck", "nim c -d:release -r tests/compile.nim" pkg "bump", "nim c --gc:arc --path:. -r tests/tbump.nim", "https://github.com/disruptek/bump", allowFailure = true @@ -58,7 +58,7 @@ pkg "cligen", "nim c --path:. -r cligen.nim" pkg "combparser", "nimble test --gc:orc" pkg "compactdict" pkg "comprehension", "nimble test", "https://github.com/alehander92/comprehension" -pkg "criterion", allowFailure = true # pending https://github.com/disruptek/criterion/issues/3 (wrongly closed) +pkg "criterion", allowFailure = true # needs testing binary pkg "datamancer" pkg "dashing", "nim c tests/functional.nim" pkg "delaunay" @@ -104,7 +104,6 @@ pkg "NimData", "nim c -o:nimdataa src/nimdata.nim" pkg "nimes", "nim c src/nimes.nim" pkg "nimfp", "nim c -o:nfp -r src/fp.nim" pkg "nimgame2", "nim c --mm:refc nimgame2/nimgame.nim" - # XXX Doesn't work with deprecated 'randomize', will create a PR. pkg "nimgen", "nim c -o:nimgenn -r src/nimgen/runcfg.nim" pkg "nimib" pkg "nimlsp" diff --git a/tests/errmsgs/t8794.nim b/tests/errmsgs/t8794.nim index 9db54a9c70..36f05dbad9 100644 --- a/tests/errmsgs/t8794.nim +++ b/tests/errmsgs/t8794.nim @@ -1,33 +1,16 @@ discard """ cmd: "nim check $options $file" - errormsg: "" - nimout: ''' -t8794.nim(39, 27) Error: undeclared field: 'a3' for type m8794.Foo3 [type declared in m8794.nim(1, 6)] -''' """ - - - - - - - - - - - -## line 20 - ## issue #8794 import m8794 -when false: # pending https://github.com/nim-lang/Nim/pull/10091 add this - type Foo = object - a1: int +type Foo = object + a1: int - discard Foo().a2 +discard Foo().a2 #[tt.Error + ^ undeclared field: 'a2' for type t8794.Foo [type declared in t8794.nim(9, 6)]]# type Foo3b = Foo3 var x2: Foo3b @@ -36,4 +19,5 @@ proc getFun[T](): T = var a: T a -discard getFun[type(x2)]().a3 +discard getFun[type(x2)]().a3 #[tt.Error + ^ undeclared field: 'a3' for type m8794.Foo3 [type declared in m8794.nim(1, 6)]]# diff --git a/tests/exception/t13115.nim b/tests/exception/t13115.nim index ee1daed268..5db8f91075 100644 --- a/tests/exception/t13115.nim +++ b/tests/exception/t13115.nim @@ -13,13 +13,6 @@ else: const nim = getCurrentCompilerExe() const file = currentSourcePath for b in "c js cpp".split: - when defined(openbsd): - if b == "js": - # xxx bug: pending #13115 - # remove special case once nodejs updated >= 12.16.2 - # refs https://github.com/nim-lang/Nim/pull/16167#issuecomment-738270751 - continue - # save CI time by avoiding mostly redundant combinations as far as this bug is concerned var opts = case b of "c": @["", "-d:nim_t13115_static", "-d:danger", "-d:debug"] diff --git a/tests/float/tfloats.nim b/tests/float/tfloats.nim index 480396e81c..967605c53d 100644 --- a/tests/float/tfloats.nim +++ b/tests/float/tfloats.nim @@ -41,8 +41,7 @@ template main = test ".1", 0.1 test "-.1", -0.1 test "-0", -0.0 - when false: # pending bug #18246 - test "-0", -0.0 + test "-0", -0'f # see #18246, -0 won't work test ".1e-1", 0.1e-1 test "0_1_2_3.0_1_2_3E+0_1_2", 123.0123e12 test "0_1_2.e-0", 12e0 diff --git a/tests/importalls/m4.nim b/tests/importalls/m4.nim index b682b766ad..77ec65c614 100644 --- a/tests/importalls/m4.nim +++ b/tests/importalls/m4.nim @@ -1,4 +1,3 @@ -{.warning[UnusedImport]: off.} # xxx bug: this shouldn't be needed since we have `export m3` import ./m3 {.all.} import ./m3 as m3b export m3b diff --git a/tests/lent/tbasic_lent_check.nim b/tests/lent/tbasic_lent_check.nim index 92d731451e..ce9b89adf3 100644 --- a/tests/lent/tbasic_lent_check.nim +++ b/tests/lent/tbasic_lent_check.nim @@ -28,7 +28,7 @@ template main2 = # bug #15958 doAssert byLent(a) == [11,12] doAssert sameAddress(byLent(a), a) doAssert byLent(b) == @[21,23] - # pending bug #16073 + # bug #16073 doAssert sameAddress(byLent(b), b) doAssert byLent(ss) == {1, 2, 3, 5} doAssert sameAddress(byLent(ss), ss) diff --git a/tests/macros/ttemplatesymbols.nim b/tests/macros/ttemplatesymbols.nim index 280b34ff1d..3182de79df 100644 --- a/tests/macros/ttemplatesymbols.nim +++ b/tests/macros/ttemplatesymbols.nim @@ -148,8 +148,6 @@ proc overloadedProc[T](x: T) = echo x """ - # XXX: There seems to be a repr rendering problem above. - # Notice that `echo [x]` inspectSymbol overloadedProc[float], """ proc overloadedProc(x: T) = diff --git a/tests/metatype/tcompositetypeclasses.nim b/tests/metatype/tcompositetypeclasses.nim index d125b119b8..43b6a57e4c 100644 --- a/tests/metatype/tcompositetypeclasses.nim +++ b/tests/metatype/tcompositetypeclasses.nim @@ -30,7 +30,7 @@ accept bar(vbar) accept baz(vbar) accept baz(vbaz) -#reject baz(vnotbaz) # XXX this really shouldn't compile +reject baz(vnotbaz) reject bar(vfoo) # https://github.com/Araq/Nim/issues/517 diff --git a/tests/misc/tcsharpusingstatement.nim b/tests/misc/tcsharpusingstatement.nim index dd4cf589d3..1ce553895d 100644 --- a/tests/misc/tcsharpusingstatement.nim +++ b/tests/misc/tcsharpusingstatement.nim @@ -49,25 +49,13 @@ macro autoClose(args: varargs[untyped]): untyped = var finallyBlock = newNimNode(nnkStmtList) finallyBlock.add(closingCalls) - # XXX: Use a template here once getAst is working properly - var targetAst = parseStmt"""block: - var - x = foo() - y = bar() - - try: - body() - - finally: - close x - close y - """ - - targetAst[0][1][0] = varSection - targetAst[0][1][1][0] = body - targetAst[0][1][1][1][0] = finallyBlock - - result = targetAst + result = quote do: + block: + `varSection` + try: + `body` + finally: + `finallyBlock` type TResource* = object diff --git a/tests/misc/tspellsuggest.nim b/tests/misc/tspellsuggest.nim index 345458bb19..ea0a98cd36 100644 --- a/tests/misc/tspellsuggest.nim +++ b/tests/misc/tspellsuggest.nim @@ -1,6 +1,5 @@ discard """ - # pending bug #16521 (bug 12) use `matrix` - cmd: "nim c --spellsuggest:15 --hints:off $file" + matrix: "--spellsuggest:15 --hints:off" action: "reject" nimout: ''' tspellsuggest.nim(45, 13) Error: undeclared identifier: 'fooBar' @@ -27,6 +26,7 @@ candidates (edit distance, scope distance); see '--spellSuggest': + # line 30 import ./mspellsuggest diff --git a/tests/misc/tspellsuggest2.nim b/tests/misc/tspellsuggest2.nim index d20fb00dc5..4bf05799ee 100644 --- a/tests/misc/tspellsuggest2.nim +++ b/tests/misc/tspellsuggest2.nim @@ -1,6 +1,5 @@ discard """ - # pending bug #16521 (bug 12) use `matrix` - cmd: "nim c --spellsuggest:12 --hints:off $file" + matrix: "--spellsuggest:12 --hints:off" action: "reject" nimout: ''' tspellsuggest2.nim(45, 13) Error: undeclared identifier: 'fooBar' @@ -27,6 +26,7 @@ candidates (edit distance, scope distance); see '--spellSuggest': + # line 30 import ./mspellsuggest diff --git a/tests/misc/tspellsuggest3.nim b/tests/misc/tspellsuggest3.nim index 9b0b846027..bd4d5256f7 100644 --- a/tests/misc/tspellsuggest3.nim +++ b/tests/misc/tspellsuggest3.nim @@ -1,6 +1,5 @@ discard """ - # pending bug #16521 (bug 12) use `matrix` - cmd: "nim c --spellsuggest:4 --hints:off $file" + matrix: "--spellsuggest:4 --hints:off" action: "reject" nimout: ''' tspellsuggest3.nim(21, 1) Error: undeclared identifier: 'fooBar' @@ -12,6 +11,7 @@ candidates (edit distance, scope distance); see '--spellSuggest': ''' """ + import ./mspellsuggest import ./mspellsuggest import ./mspellsuggest diff --git a/tests/nimdoc/trunnableexamples.nim b/tests/nimdoc/trunnableexamples.nim index 1886ceeb3b..57e725b2e7 100644 --- a/tests/nimdoc/trunnableexamples.nim +++ b/tests/nimdoc/trunnableexamples.nim @@ -1,5 +1,5 @@ discard """ -cmd: "nim doc --doccmd:--hints:off --hints:off $file" +cmd: '''nim doc --doccmd:"-d:testFooExternal --hints:off" --hints:off $file''' action: "compile" nimoutFull: true nimout: ''' @@ -19,12 +19,6 @@ foo6 joinable: false """ -#[ -pending bug #18077, use instead: -cmd: "nim doc --doccmd:'-d:testFooExternal --hints:off' --hints:off $file" -and merge trunnableexamples2 back here -]# -{.define(testFooExternal).} proc fun*() = runnableExamples: @@ -212,3 +206,8 @@ snippet: doAssert defined(testFooExternal) ]## + +when true: # runnableExamples with rdoccmd + runnableExamples "-d:testFoo -d:testBar": + doAssert defined(testFoo) and defined(testBar) + doAssert defined(testFooExternal) diff --git a/tests/nimdoc/trunnableexamples2.nim b/tests/nimdoc/trunnableexamples2.nim deleted file mode 100644 index 5a437744e9..0000000000 --- a/tests/nimdoc/trunnableexamples2.nim +++ /dev/null @@ -1,11 +0,0 @@ -discard """ -cmd: "nim doc --doccmd:-d:testFooExternal --hints:off $file" -action: "compile" -joinable: false -""" - -# pending bug #18077, merge back inside trunnableexamples.nim -when true: # runnableExamples with rdoccmd - runnableExamples "-d:testFoo -d:testBar": - doAssert defined(testFoo) and defined(testBar) - doAssert defined(testFooExternal) diff --git a/tests/overload/tstatic_with_converter.nim b/tests/overload/tstatic_with_converter.nim index e830e8a223..2bc1dfaab6 100644 --- a/tests/overload/tstatic_with_converter.nim +++ b/tests/overload/tstatic_with_converter.nim @@ -1,7 +1,6 @@ discard """ output: ''' 9.0 - ''' """ @@ -39,12 +38,11 @@ proc `^`(x: vfloat, exp: static[float]): vfloat = when exp == 0.5: sqrt(x) else: - pow(x, exp) + pow(x, exp) proc `$`(x: vfloat): string = let y = cast[ptr float](addr x) - # xxx not sure if intentional in this issue, but this returns "" - echo y[] + result = $y[] let x = set1(9.0) echo x^0.5 diff --git a/tests/parallel/tblocking_channel.nim b/tests/parallel/tblocking_channel.nim index eb5fcb7159..f3ccd166ab 100644 --- a/tests/parallel/tblocking_channel.nim +++ b/tests/parallel/tblocking_channel.nim @@ -1,8 +1,8 @@ discard """ output: "" -disabled: "freebsd" +disabled: "freebsd" # see #15725 """ -# disabled pending bug #15725 + import threadpool, os var chan: Channel[int] diff --git a/tests/stdlib/tdecls.nim b/tests/stdlib/tdecls.nim index c17fd33431..42dc646f28 100644 --- a/tests/stdlib/tdecls.nim +++ b/tests/stdlib/tdecls.nim @@ -14,18 +14,18 @@ template fun() = var b {.byaddr.}: int = s[0] doAssert a.addr == b.addr - when false: - # template specific redeclaration issue - # see https://github.com/nim-lang/Nim/issues/8275 - doAssert not compiles(block: - # redeclaration not allowed - var foo = 0 - var foo {.byaddr.} = s[0]) + {.push warningAsError[ImplicitTemplateRedefinition]: on.} + # in the future ImplicitTemplateRedefinition will be an error anyway + doAssert not compiles(block: + # redeclaration not allowed + var foo = 0 + var foo {.byaddr.} = s[0]) - doAssert not compiles(block: - # ditto - var foo {.byaddr.} = s[0] - var foo {.byaddr.} = s[0]) + doAssert not compiles(block: + # ditto + var foo {.byaddr.} = s[0] + var foo {.byaddr.} = s[0]) + {.pop.} block: var b {.byaddr.} = s[1] # redeclaration ok in sub scope diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index 1184503f59..da4f6252d5 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -94,9 +94,7 @@ else: # main driver const sourcePath = currentSourcePath() let dir = getCurrentDir() / "tests" / "osproc" - template deferScoped(cleanup, body) = - # pending https://github.com/nim-lang/RFCs/issues/236#issuecomment-646855314 - # xxx move to std/sugar or (preferably) some low level module + template deferring(cleanup, body) = try: body finally: cleanup @@ -250,14 +248,14 @@ else: # main driver var x = newStringOfCap(120) block: # startProcess stdout poStdErrToStdOut (replaces old test `tstdout` + `ta_out`) var p = startProcess(output, dir, options={poStdErrToStdOut}) - deferScoped: p.close() + deferring: p.close() do: var sout: seq[string] while p.outputStream.readLine(x): sout.add x doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stderr", "to stderr", "to stdout", "to stdout", "end ta_out"] block: # startProcess stderr (replaces old test `tstderr` + `ta_out`) var p = startProcess(output, dir, options={}) - deferScoped: p.close() + deferring: p.close() do: var serr, sout: seq[string] while p.errorStream.readLine(x): serr.add x diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim index 4104ad1a44..8784b33ee4 100644 --- a/tests/stdlib/trandom.nim +++ b/tests/stdlib/trandom.nim @@ -192,9 +192,7 @@ block: # bug #17467 # This used to fail for each i in 0..<26844, i.e. the 1st produced value # was predictable and < 1e-4, skewing distributions. -const withUint = false # pending exporting `proc rand[T: uint | uint64](r: var Rand; max: T): T =` - -block: # bug #16360 +block: # bug #16360, Natural overload var r = initRand() template test(a) = let a2 = a @@ -206,23 +204,38 @@ block: # bug #16360 let a3 = rand(a2) doAssert a3 <= a2 doAssert a3.type is a2.type - when withUint: - test cast[uint](int.high) - test cast[uint](int.high) + 1 - whenJsNoBigInt64: discard - do: - test uint64.high - test uint64.high - 1 - test uint.high - 2 - test uint.high - 1 - test uint.high test int.high test int.high - 1 test int.high - 2 test 0 - when withUint: - test 0'u - test 0'u64 + +block: # same as above but use slice overload + var r = initRand() + template test[T](a: T) = + let a2: T = a + block: + let a3 = r.rand(T(0) .. a2) + doAssert a3 <= a2 + doAssert a3.type is a2.type + block: + let a3 = rand(T(0) .. a2) + doAssert a3 <= a2 + doAssert a3.type is a2.type + test cast[uint](int.high) + test cast[uint](int.high) + 1 + whenJsNoBigInt64: discard + do: + test uint64.high + test uint64.high - 1 + test uint.high - 2 + test uint.high - 1 + test uint.high + test int.high + test int.high - 1 + test int.high - 2 + test 0 + test 0'u + test 0'u64 block: # bug #16296 var r = initRand() diff --git a/tests/stdlib/tssl.nim b/tests/stdlib/tssl.nim index 0e3f9cd82c..1628b9326a 100644 --- a/tests/stdlib/tssl.nim +++ b/tests/stdlib/tssl.nim @@ -1,11 +1,11 @@ discard """ matrix: "--mm:refc; --mm:orc" joinable: false - disabled: "freebsd" - disabled: "openbsd" - disabled: "netbsd" + disabled: "freebsd" # see #15713 + disabled: "openbsd" # see #15713 + disabled: "netbsd" # see #15713 """ -# disabled: pending bug #15713 + import std/[net, nativesockets, assertions, typedthreads] when defined(posix): import os, posix diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim index 913db7c863..39337cca77 100644 --- a/tests/system/tdollars.nim +++ b/tests/system/tdollars.nim @@ -45,8 +45,7 @@ block: # `$`(SomeInteger) check $int8.low == "-128" check $int8(-128) == "-128" - when not defined js: # pending https://github.com/nim-lang/Nim/issues/14127 - check $cast[int8](-128) == "-128" + check $cast[int8](-128) == "-128" var a = 12345'u16 check $a == "12345" diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index c29dd50108..11fdcbd8ce 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -291,7 +291,7 @@ block: # bug #10815 const a = P() doAssert $a == "" -when defined osx: # xxx bug https://github.com/nim-lang/Nim/issues/10815#issuecomment-476380734 +when defined osx: # xxx bug #13481 block: type CharSet {.union.} = object cs: set[char] diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index bab2de1e47..60d4bc673e 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -1,6 +1,6 @@ ## Part of 'koch' responsible for the documentation generation. -import std/[os, strutils, osproc, sets, pathnorm, sequtils] +import std/[os, strutils, osproc, sets, pathnorm, sequtils, pegs] import officialpackages export exec @@ -8,9 +8,6 @@ export exec when defined(nimPreviewSlimSystem): import std/assertions -# XXX: Remove this feature check once the csources supports it. -when defined(nimHasCastPragmaBlocks): - import std/pegs from std/private/globs import nativeToUnixPath, walkDirRecFilter, PathEntry import "../compiler/nimpaths" @@ -373,9 +370,7 @@ proc buildDocs*(args: string, localOnly = false, localOutDir = "") = if not localOnly: buildDocsDir(args, webUploadOutput / NimVersion) - # XXX: Remove this feature check once the csources supports it. - when defined(nimHasCastPragmaBlocks): - let gaFilter = peg"@( y'--doc.googleAnalytics:' @(\s / $) )" - args = args.replace(gaFilter) + let gaFilter = peg"@( y'--doc.googleAnalytics:' @(\s / $) )" + args = args.replace(gaFilter) buildDocsDir(args, localOutDir) From 71dc929ad7d6ecf26c35028c9ae5fe1406837c7c Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 11 May 2023 16:29:11 +0800 Subject: [PATCH 079/489] bring #21802 back; fixes #21753 [backport] (#21815) * bring #21802 back; fixes #21753 [backport] * adds tests and multiple fixes * add test cases * refactor and remove startId * fixes custom hooks and adds tests * handle tyUncheckedArray better --- compiler/ccgexprs.nim | 4 +- compiler/ccgtypes.nim | 8 +-- compiler/injectdestructors.nim | 4 +- compiler/liftdestructors.nim | 12 ++-- compiler/semmagic.nim | 4 ++ compiler/types.nim | 45 ++++++++---- tests/types/tcyclic.nim | 123 +++++++++++++++++++++++++++++++++ 7 files changed, 174 insertions(+), 26 deletions(-) create mode 100644 tests/types/tcyclic.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 66f92f12ec..38ecb11aab 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1414,7 +1414,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) if a.storage == OnHeap and usesWriteBarrier(p.config): - if canFormAcycle(a.t): + if canFormAcycle(p.module.g.graph, a.t): linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [a.rdLoc]) else: linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", [a.rdLoc]) @@ -1451,7 +1451,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = var call: TLoc initLoc(call, locExpr, dest.lode, OnHeap) if dest.storage == OnHeap and usesWriteBarrier(p.config): - if canFormAcycle(dest.t): + if canFormAcycle(p.module.g.graph, dest.t): linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [dest.rdLoc]) else: linefmt(p, cpsStmts, "if ($1) { #nimGCunrefNoCycle($1); $1 = NIM_NIL; }$n", [dest.rdLoc]) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 2d1f632a26..2669dec247 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1036,7 +1036,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; # compute type flags for GC optimization var flags = 0 if not containsGarbageCollectedRef(typ): flags = flags or 1 - if not canFormAcycle(typ): flags = flags or 2 + if not canFormAcycle(m.g.graph, typ): flags = flags or 2 #else echo("can contain a cycle: " & typeToString(typ)) if flags != 0: m.s[cfsTypeInit3].addf("$1.flags = $2;$n", [nameHcr, rope(flags)]) @@ -1318,7 +1318,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp; result: result.add theProc.loc.r when false: - if not canFormAcycle(t) and op == attachedTrace: + if not canFormAcycle(m.g.graph, t) and op == attachedTrace: echo "ayclic but has this =trace ", t, " ", theProc.ast else: when false: @@ -1364,7 +1364,7 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name]) var flags = 0 - if not canFormAcycle(t): flags = flags or 1 + if not canFormAcycle(m.g.graph, t): flags = flags or 1 var typeEntry = newRopeAppender() addf(typeEntry, "$1.destructor = (void*)", [name]) @@ -1405,7 +1405,7 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name]) var flags = 0 - if not canFormAcycle(t): flags = flags or 1 + if not canFormAcycle(m.g.graph, t): flags = flags or 1 var typeEntry = newRopeAppender() addf(typeEntry, "N_LIB_PRIVATE TNimTypeV2 $1 = {", [name]) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index ab0fa02d91..9745fee814 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -305,13 +305,13 @@ proc isCriticalLink(dest: PNode): bool {.inline.} = proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) = if c.graph.config.selectedGC == gcOrc: let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct}) - if cyclicType(t): + if cyclicType(c.graph, t): result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest)) proc genMarkCyclic(c: var Con; result, dest: PNode) = if c.graph.config.selectedGC == gcOrc: let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct}) - if cyclicType(t): + if cyclicType(c.graph, t): if t.kind == tyRef: result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest) else: diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 34ab3cc8e1..85403586f4 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -545,7 +545,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = forallElements(c, t, body, x, y) body.add genBuiltin(c, mDestroy, "destroy", x) of attachedTrace: - if canFormAcycle(t.elemType): + if canFormAcycle(c.g, t.elemType): # follow all elements: forallElements(c, t, body, x, y) of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) @@ -583,7 +583,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = doAssert t.destructor != nil body.add destructorCall(c, t.destructor, x) of attachedTrace: - if t.kind != tyString and canFormAcycle(t.elemType): + if t.kind != tyString and canFormAcycle(c.g, t.elemType): let op = getAttachedOp(c.g, t, c.kind) if op == nil: return # protect from recursion @@ -610,9 +610,9 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDup: assert false, "cannot happen" -proc cyclicType*(t: PType): bool = +proc cyclicType*(g: ModuleGraph, t: PType): bool = case t.kind - of tyRef: result = types.canFormAcycle(t.lastSon) + of tyRef: result = types.canFormAcycle(g, t.lastSon) of tyProc: result = t.callConv == ccClosure else: result = false @@ -640,7 +640,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let elemType = t.lastSon createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen) - let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType) + let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType) let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and (not isPureObject(elemType)) and @@ -990,7 +990,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp result.typ.addParam src if kind == attachedAsgn and g.config.selectedGC == gcOrc and - cyclicType(typ.skipTypes(abstractInst)): + cyclicType(g, typ.skipTypes(abstractInst)): let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"), idgen, result, info) cycleParam.typ = getSysType(g, info, tyBool) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 6af7527701..71efcadb1d 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -215,6 +215,10 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym) var arg = operand.skipTypes({tyGenericInst}) assert arg.kind == tyRange result = getTypeDescNode(c, arg.base, operand.owner, traitCall.info) + of "isCyclic": + var operand = operand.skipTypes({tyGenericInst}) + let isCyclic = canFormAcycle(c.graph, operand) + result = newIntNodeT(toInt128(ord(isCyclic)), traitCall, c.idgen, c.graph) else: localError(c.config, traitCall.info, "unknown trait: " & s) result = newNodeI(nkEmpty, traitCall.info) diff --git a/compiler/types.nim b/compiler/types.nim index d2517127a9..97cc439c02 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -370,41 +370,62 @@ proc containsHiddenPointer*(typ: PType): bool = # that need to be copied deeply) result = searchTypeFor(typ, isHiddenPointer) -proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool -proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = +proc canFormAcycleAux(g: ModuleGraph; marker: var IntSet, typ: PType, orig: PType, withRef: bool, hasTrace: bool): bool +proc canFormAcycleNode(g: ModuleGraph; marker: var IntSet, n: PNode, orig: PType, withRef: bool, hasTrace: bool): bool = result = false if n != nil: - result = canFormAcycleAux(marker, n.typ, startId) + result = canFormAcycleAux(g, marker, n.typ, orig, withRef, hasTrace) if not result: case n.kind of nkNone..nkNilLit: discard else: for i in 0.. Date: Thu, 11 May 2023 05:49:19 -0300 Subject: [PATCH 080/489] Improve nimsuggest (#21825) Small improvement for nimsuggest --- nimsuggest/nimsuggest.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim index 7608052a6c..c1d31cacdc 100644 --- a/nimsuggest/nimsuggest.nim +++ b/nimsuggest/nimsuggest.nim @@ -732,7 +732,7 @@ func deduplicateSymInfoPair[SymInfoPair](xs: seq[SymInfoPair]): seq[SymInfoPair] # sym may not match. This can happen when xs contains the same definition but # with different signature because suggestSym might be called multiple times # for the same symbol (e. g. including/excluding the pragma) - result = @[] + result = newSeqOfCap[SymInfoPair](xs.len) for itm in xs.reversed: var found = false for res in result: From 3b9999b93c35ff3e61b0a9848fdeb23083c89eb3 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 11 May 2023 19:38:27 +0800 Subject: [PATCH 081/489] adds documentation for `=wasMoved` and `=dup` hooks and small fixes (#21827) * adds documentation for `=wasMoved` and `=dup` hooks and small fixes * Update doc/destructors.md * Update doc/destructors.md --------- Co-authored-by: Andreas Rumpf --- compiler/injectdestructors.nim | 4 +++- compiler/liftdestructors.nim | 2 +- compiler/semstmts.nim | 2 +- doc/destructors.md | 37 +++++++++++++++++++++++++++++++++- doc/manual.md | 2 +- lib/system.nim | 2 +- tests/arc/tdup.nim | 2 +- 7 files changed, 44 insertions(+), 7 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 9745fee814..7183aac4e0 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -431,7 +431,9 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = let src = p(n, c, s, normal) result.add newTreeI(nkFastAsgn, src.info, tmp, - genOp(c, op, src) + newTreeIT(nkCall, src.info, src.typ, + newSymNode(op), + src) ) elif typ.kind == tyRef: let src = p(n, c, s, normal) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 85403586f4..43e5baf086 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -8,7 +8,7 @@ # ## This module implements lifting for type-bound operations -## (``=sink``, ``=copy``, ``=destroy``, ``=deepCopy``). +## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`). import modulegraphs, lineinfos, idents, ast, renderer, semdata, sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 126d1aa654..f81423915b 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1819,7 +1819,7 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) = of {attachedDestructor, attachedWasMoved}: t.len == 2 and t[0] == nil and t[1].kind == tyVar of attachedDup: - t.len == 2 and t[0] != nil and t[1].kind == tyVar + t.len == 2 and t[0] != nil of attachedTrace: t.len == 3 and t[0] == nil and t[1].kind == tyVar and t[2].kind == tyPointer else: diff --git a/doc/destructors.md b/doc/destructors.md index a37eade330..d924c7c4ce 100644 --- a/doc/destructors.md +++ b/doc/destructors.md @@ -101,7 +101,7 @@ well as other standard collections is performed via so-called "Lifetime-tracking hooks", which are particular [type bound operators]( manual.html#procedures-type-bound-operators). -There are 4 different hooks for each (generic or concrete) object type `T` (`T` can also be a +There are 6 different hooks for each (generic or concrete) object type `T` (`T` can also be a `distinct` type) that are called implicitly by the compiler. (Note: The word "hook" here does not imply any kind of dynamic binding @@ -262,6 +262,41 @@ The general pattern in using `=destroy` with `=trace` looks like: **Note**: The `=trace` hooks (which are only used by `--mm:orc`) are currently more experimental and less refined than the other hooks. +`=WasMoved` hook +---------------- + +A `wasMoved` hook resets the memory of an object to its initial (binary zero) value to signify it was "moved" and to signify its destructor should do nothing and ideally be optimized away. + +The prototype of this hook for a type `T` needs to be: + + ```nim + proc `=wasMoved`(x: var T) + ``` + +`=dup` hook +----------- + +A `=dup` hook duplicates the memory of an object. `=dup(x)` can be regarded as an optimization replacing the `wasMoved(dest); =copy(dest, x)` operation. + +The prototype of this hook for a type `T` needs to be: + + ```nim + proc `=dup`(x: T): T + ``` + +The general pattern in implementing `=dup` looks like: + + ```nim + type + Ref[T] = object + data: ptr T + rc: ptr int + + proc `=dup`[T](x: Ref[T]): Ref[T] = + result = x + if x.rc != nil: + inc x.rc[] + ``` Move semantics ============== diff --git a/doc/manual.md b/doc/manual.md index 7fe9923f41..f3fe62c498 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -4155,7 +4155,7 @@ the operator is in scope (including if it is private). ``` Type bound operators are: -`=destroy`, `=copy`, `=sink`, `=trace`, `=deepcopy`, `=wasMoved`. +`=destroy`, `=copy`, `=sink`, `=trace`, `=deepcopy`, `=wasMoved`, `=dup`. These operations can be *overridden* instead of *overloaded*. This means that the implementation is automatically lifted to structured types. For instance, diff --git a/lib/system.nim b/lib/system.nim index e8664d7a47..e7b6ed7c3c 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -350,7 +350,7 @@ proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} = when defined(nimHasDup): proc `=dup`*[T](x: ref T): ref T {.inline, magic: "Dup".} = - ## Generic `dup` implementation that can be overridden. + ## Generic `dup`:idx: implementation that can be overridden. discard proc `=sink`*[T](x: var T; y: T) {.inline, nodestroy, magic: "Asgn".} = diff --git a/tests/arc/tdup.nim b/tests/arc/tdup.nim index 3f64061fbe..b77f5c6ebe 100644 --- a/tests/arc/tdup.nim +++ b/tests/arc/tdup.nim @@ -40,7 +40,7 @@ proc inc(x: sink Ref) = proc inc(x: sink RefCustom) = inc x.id[] -proc `=dup`(x: var RefCustom): RefCustom = +proc `=dup`(x: RefCustom): RefCustom = result.id = x.id proc foo = From 802d57c2374e9048181569ec2fc19501ea790ad3 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Fri, 12 May 2023 00:14:44 +1200 Subject: [PATCH 082/489] Add nnkHiddenCallConv to nnkCallKinds (#21781) (#21829) --- lib/core/macros.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 28f52f0a93..2196a42bef 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -145,8 +145,9 @@ type const nnkLiterals* = {nnkCharLit..nnkNilLit} + # see matching set CallNodes below nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, - nnkCallStrLit} + nnkCallStrLit, nnkHiddenCallConv} nnkPragmaCallKinds = {nnkExprColonExpr, nnkCall, nnkCallStrLit} {.push warnings: off.} @@ -1208,6 +1209,7 @@ const RoutineNodes* = {nnkProcDef, nnkFuncDef, nnkMethodDef, nnkDo, nnkLambda, nnkIteratorDef, nnkTemplateDef, nnkConverterDef, nnkMacroDef} AtomicNodes* = {nnkNone..nnkNilLit} + # see matching set nnkCallKinds above CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, nnkCallStrLit, nnkHiddenCallConv} From f7ed293fbd84bf0350fbfee78e634b5f401f5b0a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 11 May 2023 22:04:25 +0800 Subject: [PATCH 083/489] switch to the official URL of loop-fusion in the impoerant packages (#21830) ref https://github.com/mratsim/loop-fusion/pull/9 --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 7e030e92cd..d5a3ba97b5 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -84,7 +84,7 @@ pkg "iterutils" pkg "jstin" pkg "karax", "nim c -r tests/tester.nim" pkg "kdtree", "nimble test -d:nimLegacyRandomInitRand", "https://github.com/jblindsay/kdtree" -pkg "loopfusion", url = "https://github.com/nim-lang/loop-fusion" +pkg "loopfusion" pkg "lockfreequeues" pkg "macroutils" pkg "manu" From c00448358121bbf6b5e1fcfe39bb6eb3359d6462 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Thu, 11 May 2023 16:50:18 +0200 Subject: [PATCH 084/489] Bootstrap: Allow to override number of CPUs (#21823) * Allow to override number of cpu * NCPU -> NIMCORES --- ci/funs.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ci/funs.sh b/ci/funs.sh index 8e7f8faf7a..0263661983 100644 --- a/ci/funs.sh +++ b/ci/funs.sh @@ -58,7 +58,11 @@ _nimNumCpu(){ # FreeBSD | macOS: $(sysctl -n hw.ncpu) # OpenBSD: $(sysctl -n hw.ncpuonline) # windows: $NUMBER_OF_PROCESSORS ? - echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1) + if env | grep -q '^NIMCORES='; then + echo $NIMCORES + else + echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1) + fi } _nimBuildCsourcesIfNeeded(){ From ebbad9e9604d778c32838c981c8748f3675d2659 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 12 May 2023 02:49:47 +0800 Subject: [PATCH 085/489] cursor fields cannot form reference cycles (#21832) * cursor fields cannot form a reference cycle * fixes typo * fixes position --- compiler/types.nim | 21 ++++++++++++--------- tests/types/tcyclic.nim | 20 ++++++++++++++++---- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/compiler/types.nim b/compiler/types.nim index 97cc439c02..96dbd26b2d 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -374,15 +374,18 @@ proc canFormAcycleAux(g: ModuleGraph; marker: var IntSet, typ: PType, orig: PTyp proc canFormAcycleNode(g: ModuleGraph; marker: var IntSet, n: PNode, orig: PType, withRef: bool, hasTrace: bool): bool = result = false if n != nil: - result = canFormAcycleAux(g, marker, n.typ, orig, withRef, hasTrace) - if not result: - case n.kind - of nkNone..nkNilLit: - discard - else: - for i in 0.. Date: Thu, 11 May 2023 21:50:01 +0300 Subject: [PATCH 086/489] just set CallNodes = nnkCallKinds, follows up #21829 (#21833) These sets are now equal --- lib/core/macros.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 2196a42bef..3286d7861f 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1210,8 +1210,7 @@ const nnkIteratorDef, nnkTemplateDef, nnkConverterDef, nnkMacroDef} AtomicNodes* = {nnkNone..nnkNilLit} # see matching set nnkCallKinds above - CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, - nnkCallStrLit, nnkHiddenCallConv} + CallNodes* = nnkCallKinds proc expectKind*(n: NimNode; k: set[NimNodeKind]) = ## Checks that `n` is of kind `k`. If this is not the case, From ea39c600abcb8853791404145c3038ea9488d0f4 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Fri, 12 May 2023 18:02:09 +1200 Subject: [PATCH 087/489] Add `minmax` to comparisons (#21820) * Add `minmax` to sequtils This adds a `minmax` proc to complement `min` and `max`; it computes both results in a single pass for efficiency. * Update lib/pure/collections/sequtils.nim * Add minmax note to changelog. --------- Co-authored-by: Andreas Rumpf --- changelogs/changelog_2_0_0.md | 1 + lib/pure/collections/sequtils.nim | 9 +++++++++ tests/collections/tseq.nim | 8 ++++++++ 3 files changed, 18 insertions(+) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index e89cb6b624..d2c12a3557 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -305,6 +305,7 @@ - Added `openArray[char]` overloads for `std/unicode` allowing more code reuse. - Added `safe` parameter to `base64.encodeMime`. - Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes. +- Added `minmax` to `sequtils`, as a more efficient `(min(_), max(_))` over sequences. [//]: # "Deprecations:" - Deprecated `selfExe` for Nimscript. diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index bcdd0879d6..19bc3e65c6 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -248,6 +248,15 @@ func maxIndex*[T](s: openArray[T]): int {.since: (1, 1).} = for i in 1..high(s): if s[i] > s[result]: result = i +func minmax*[T](x: openArray[T]): (T, T) = + ## The minimum and maximum values of `x`. `T` needs to have a `<` operator. + var l = x[0] + var h = x[0] + for i in 1..high(x): + if x[i] < l: l = x[i] + if h < x[i]: h = x[i] + result = (l, h) + template zipImpl(s1, s2, retType: untyped): untyped = proc zip*[S, T](s1: openArray[S], s2: openArray[T]): retType = diff --git a/tests/collections/tseq.nim b/tests/collections/tseq.nim index 39f066f4c6..5fca784e7f 100644 --- a/tests/collections/tseq.nim +++ b/tests/collections/tseq.nim @@ -12,6 +12,7 @@ FilterIt: [1, 3, 7] Concat: [1, 3, 5, 7, 2, 4, 6] Deduplicate: [1, 2, 3, 4, 5, 7] @[()] +Minmax: (1, 7) 2345623456 ''' """ @@ -156,6 +157,13 @@ block tsequtils: let someObjSeq = aSeq.mapIt(it.field) echo someObjSeq + block minmax: + doAssert minmax(@[0]) == (0, 0) + doAssert minmax(@[0, 1]) == (0, 1) + doAssert minmax(@[1, 0]) == (0, 1) + doAssert minmax(@[8,2,1,7,3,9,4,0,5]) == (0, 9) + echo "Minmax: ", $(minmax(concat(seq1, seq2))) + when not defined(nimseqsv2): block tshallowseq: From c6e2dc191995bada24f26acc99bf4653d0d665bd Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 12 May 2023 16:03:41 +0800 Subject: [PATCH 088/489] fixes nightlies regressions; disable `build-id=none` on macos (#21839) * fixes nightlies regressions; disable `build-id=none` on macos * fixes typos --- config/nim.cfg | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/nim.cfg b/config/nim.cfg index 656885e0c3..6af5b0fd7a 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -366,6 +366,8 @@ tcc.options.always = "-w" # Linker: Skip "Build-ID metadata strings" in binaries when build for release. @if release or danger: - gcc.options.linker %= "${gcc.options.linker} -Wl,--build-id=none" - gcc.cpp.options.linker %= "${gcc.cpp.options.linker} -Wl,--build-id=none" + @if not macosx: + gcc.options.linker %= "${gcc.options.linker} -Wl,--build-id=none" + gcc.cpp.options.linker %= "${gcc.cpp.options.linker} -Wl,--build-id=none" + @end @end From 161f50643a8615d6d123d4e947e85666c2176eab Mon Sep 17 00:00:00 2001 From: metagn Date: Fri, 12 May 2023 11:05:38 +0300 Subject: [PATCH 089/489] make deprecated statement a no-op (#21836) --- changelogs/changelog_2_0_0.md | 17 +++++++++ compiler/ast.nim | 3 +- compiler/condsyms.nim | 1 - compiler/lookups.nim | 61 +++++++++++++------------------- compiler/magicsys.nim | 1 - compiler/pragmas.nim | 15 ++------ compiler/semgnrc.nim | 4 +-- tests/deprecated/tdeprecated.nim | 2 +- 8 files changed, 48 insertions(+), 56 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index d2c12a3557..2de86fb691 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -231,6 +231,23 @@ unlisted exceptions) and explicitly raising destructors are implementation defined behavior. +- The very old, undocumented deprecated pragma statement syntax for + deprecated aliases is now a no-op. The regular deprecated pragma syntax is + generally sufficient instead. + + ```nim + # now does nothing: + {.deprecated: [OldName: NewName].} + + # instead use: + type OldName* {.deprecated: "use NewName instead".} = NewName + const oldName* {.deprecated: "use newName instead".} = newName + ``` + + `defined(nimalias)` can be used to check for versions when this syntax was + available; however since code that used this syntax is usually very old, + these deprecated aliases are likely not used anymore and it may make sense + to simply remove these statements. ## Standard library additions and changes diff --git a/compiler/ast.nim b/compiler/ast.nim index 815cb00dc4..41e5387427 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -620,13 +620,12 @@ type # file (it is loaded on demand, which may # mean: never) skPackage, # symbol is a package (used for canonicalization) - skAlias # an alias (needs to be resolved immediately) TSymKinds* = set[TSymKind] const routineKinds* = {skProc, skFunc, skMethod, skIterator, skConverter, skMacro, skTemplate} - ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub, skAlias} + routineKinds + ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub} + routineKinds tfUnion* = tfNoSideEffect tfGcSafe* = tfThread diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 3d14408a3c..ea635e52e1 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -45,7 +45,6 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimNewTypedesc") # deadcode defineSymbol("nimrequiresnimframe") # deadcode defineSymbol("nimparsebiggestfloatmagic") # deadcode - defineSymbol("nimalias") # deadcode defineSymbol("nimlocks") # deadcode defineSymbol("nimnode") # deadcode defineSymbol("nimvarargstyped") # deadcode diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 188bb1a6b5..9f376a6027 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -15,7 +15,7 @@ when defined(nimPreviewSlimSystem): import intsets, ast, astalgo, idents, semdata, types, msgs, options, - renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs, sets, wordrecg + renderer, lineinfos, modulegraphs, astmsgs, sets, wordrecg proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) @@ -94,17 +94,6 @@ iterator localScopesFrom*(c: PContext; scope: PScope): PScope = if s == c.topLevelScope: break yield s -proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym = - if s == nil or s.kind != skAlias: - result = s - else: - result = s.owner - if conf.cmd == cmdNimfix: - prettybase.replaceDeprecated(conf, n.info, s, result) - else: - message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " & - s.name.s & " is deprecated") - proc isShadowScope*(s: PScope): bool {.inline.} = s.parent != nil and s.parent.depthLevel == s.depthLevel @@ -568,13 +557,13 @@ proc lookUp*(c: PContext, n: PNode): PSym = var amb = false case n.kind of nkIdent: - result = searchInScopes(c, n.ident, amb).skipAlias(n, c.config) + result = searchInScopes(c, n.ident, amb) if result == nil: result = errorUndeclaredIdentifierHint(c, n, n.ident) of nkSym: result = n.sym of nkAccQuoted: var ident = considerQuotedIdent(c, n) - result = searchInScopes(c, ident, amb).skipAlias(n, c.config) + result = searchInScopes(c, ident, amb) if result == nil: result = errorUndeclaredIdentifierHint(c, n, ident) else: internalError(c.config, n.info, "lookUp") @@ -596,9 +585,9 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = var amb = false var ident = considerQuotedIdent(c, n) if checkModule in flags: - result = searchInScopes(c, ident, amb).skipAlias(n, c.config) + result = searchInScopes(c, ident, amb) else: - let candidates = searchInScopesFilterBy(c, ident, allExceptModule) #.skipAlias(n, c.config) + let candidates = searchInScopesFilterBy(c, ident, allExceptModule) if candidates.len > 0: result = candidates[0] amb = candidates.len > 1 @@ -630,13 +619,13 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = ident = considerQuotedIdent(c, n[1]) if ident != nil: if m == c.module: - result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config) + result = strTableGet(c.topLevelScope.symbols, ident) else: if c.importModuleLookup.getOrDefault(m.name.id).len > 1: var amb: bool result = errorUseQualifier(c, n.info, m, amb) else: - result = someSym(c.graph, m, ident).skipAlias(n, c.config) + result = someSym(c.graph, m, ident) if result == nil and checkUndeclared in flags: result = errorUndeclaredIdentifierHint(c, n[1], ident) elif n[1].kind == nkSym: @@ -660,7 +649,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = var scope = c.currentScope o.mode = oimNoQualifier while true: - result = initIdentIter(o.it, scope.symbols, ident).skipAlias(n, c.config) + result = initIdentIter(o.it, scope.symbols, ident) if result != nil: o.currentScope = scope break @@ -668,7 +657,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = scope = scope.parent if scope == nil: for i in 0..c.imports.high: - result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph) if result != nil: o.currentScope = nil o.importIdx = i @@ -691,10 +680,10 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = if o.m == c.module: # a module may access its private members: result = initIdentIter(o.it, c.topLevelScope.symbols, - ident).skipAlias(n, c.config) + ident) o.mode = oimSelfModule else: - result = initModuleIter(o.mit, c.graph, o.m, ident).skipAlias(n, c.config) + result = initModuleIter(o.mit, c.graph, o.m, ident) else: noidentError(c.config, n[1], n) result = errorSym(c, n[1]) @@ -727,7 +716,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym var idx = o.importIdx+1 o.importIdx = c.imports.len # assume the other imported modules lack this symbol too while idx < c.imports.len: - result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph) if result != nil: # oh, we were wrong, some other module had the symbol, so remember that: o.importIdx = idx @@ -737,7 +726,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym = assert o.currentScope == nil while o.importIdx < c.imports.len: - result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph) #while result != nil and result.id in o.marked: # result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx]) if result != nil: @@ -752,29 +741,29 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = of oimNoQualifier: if o.currentScope != nil: assert o.importIdx < 0 - result = nextIdentIter(o.it, o.currentScope.symbols).skipAlias(n, c.config) + result = nextIdentIter(o.it, o.currentScope.symbols) while result == nil: o.currentScope = o.currentScope.parent if o.currentScope != nil: - result = initIdentIter(o.it, o.currentScope.symbols, o.it.name).skipAlias(n, c.config) + result = initIdentIter(o.it, o.currentScope.symbols, o.it.name) # BUGFIX: o.it.name <-> n.ident else: o.importIdx = 0 if c.imports.len > 0: - result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config) + result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph) if result == nil: result = nextOverloadIterImports(o, c, n) break elif o.importIdx < c.imports.len: - result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config) + result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph) if result == nil: result = nextOverloadIterImports(o, c, n) else: result = nil of oimSelfModule: - result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n, c.config) + result = nextIdentIter(o.it, c.topLevelScope.symbols) of oimOtherModule: - result = nextModuleIter(o.mit, c.graph).skipAlias(n, c.config) + result = nextModuleIter(o.mit, c.graph) of oimSymChoice: if o.symChoiceIndex < n.len: result = n[o.symChoiceIndex].sym @@ -785,12 +774,12 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = o.mode = oimSymChoiceLocalLookup o.currentScope = c.currentScope result = firstIdentExcluding(o.it, o.currentScope.symbols, - n[0].sym.name, o.marked).skipAlias(n, c.config) + n[0].sym.name, o.marked) while result == nil: o.currentScope = o.currentScope.parent if o.currentScope != nil: result = firstIdentExcluding(o.it, o.currentScope.symbols, - n[0].sym.name, o.marked).skipAlias(n, c.config) + n[0].sym.name, o.marked) else: o.importIdx = 0 result = symChoiceExtension(o, c, n) @@ -799,12 +788,12 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = incl o.marked, result.id of oimSymChoiceLocalLookup: if o.currentScope != nil: - result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked).skipAlias(n, c.config) + result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked) while result == nil: o.currentScope = o.currentScope.parent if o.currentScope != nil: result = firstIdentExcluding(o.it, o.currentScope.symbols, - n[0].sym.name, o.marked).skipAlias(n, c.config) + n[0].sym.name, o.marked) else: o.importIdx = 0 result = symChoiceExtension(o, c, n) @@ -813,10 +802,10 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = incl o.marked, result.id elif o.importIdx < c.imports.len: - result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config) + result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph) #assert result.id notin o.marked #while result != nil and result.id in o.marked: - # result = nextIdentIter(o.it, c.imports[o.importIdx]).skipAlias(n, c.config) + # result = nextIdentIter(o.it, c.imports[o.importIdx]) if result == nil: inc o.importIdx result = symChoiceExtension(o, c, n) diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 8261b14c7e..becde13e6d 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -28,7 +28,6 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym = localError(g.config, info, "system module needs: " & name) result = newSym(skError, getIdent(g.cache, name), g.idgen, g.systemModule, g.systemModule.info, {}) result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule) - if result.kind == skAlias: result = result.owner proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym = let id = getIdent(g.cache, name) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 31414063a5..1857ef3ce0 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -736,19 +736,8 @@ proc deprecatedStmt(c: PContext; outerPragma: PNode) = return if pragma.kind != nkBracket: localError(c.config, pragma.info, "list of key:value pairs expected"); return - for n in pragma: - if n.kind in nkPragmaCallKinds and n.len == 2: - let dest = qualifiedLookUp(c, n[1], {checkUndeclared}) - if dest == nil or dest.kind in routineKinds: - localError(c.config, n.info, warnUser, "the .deprecated pragma is unreliable for routines") - let src = considerQuotedIdent(c, n[0]) - let alias = newSym(skAlias, src, c.idgen, dest, n[0].info, c.config.options) - incl(alias.flags, sfExported) - if sfCompilerProc in dest.flags: markCompilerProc(c, alias) - addInterfaceDecl(c, alias) - n[1] = newSymNode(dest) - else: - localError(c.config, n.info, "key:value pair expected") + message(c.config, pragma.info, warnDeprecated, + "deprecated statement is now a no-op, use regular deprecated pragma") proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym = if it.kind notin nkPragmaCallKinds or it.len != 2: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 543bd1132d..01146bb7c1 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -115,7 +115,7 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, result = n let ident = considerQuotedIdent(c, n) var amb = false - var s = searchInScopes(c, ident, amb).skipAlias(n, c.config) + var s = searchInScopes(c, ident, amb) if s == nil: s = strTableGet(c.pureEnumFields, ident) #if s != nil and contains(c.ambiguousSymbols, s.id): @@ -152,7 +152,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, result = n let n = n[1] let ident = considerQuotedIdent(c, n) - var candidates = searchInScopesFilterBy(c, ident, routineKinds) # .skipAlias(n, c.config) + var candidates = searchInScopesFilterBy(c, ident, routineKinds) if candidates.len > 0: let s = candidates[0] # XXX take into account the other candidates! isMacro = s.kind in {skTemplate, skMacro} diff --git a/tests/deprecated/tdeprecated.nim b/tests/deprecated/tdeprecated.nim index ba8d579adf..51c0dc14b6 100644 --- a/tests/deprecated/tdeprecated.nim +++ b/tests/deprecated/tdeprecated.nim @@ -35,7 +35,7 @@ block: # issue #8063 Foo = enum fooX - {.deprecated: [fooA: fooX].} + const fooA {.deprecated: "use fooX instead".} = fooX let foo: Foo = fooA echo foo From 9c40dd2406e6e83799aa4e3a22e23922318aabd6 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 12 May 2023 19:38:10 +0800 Subject: [PATCH 090/489] fixes #21840; nested local template lookup regression (#21841) * fixes #21840; nested local template lookup regression * use original types * fixes js vm tests --- compiler/sem.nim | 14 ++--- tests/objects/tobject_default_value.nim | 74 +++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index bac029fb98..3b20579d57 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -578,14 +578,14 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s result.add newTree(nkExprColonExpr, recNode, asgnExpr) return - let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), recType.owner) - rawAddSon(asgnType, recType) + let asgnType = newType(tyTypeDesc, nextTypeId(c.idgen), recNode.typ.owner) + rawAddSon(asgnType, recNode.typ) let asgnExpr = newTree(nkCall, newSymNode(getSysMagic(c.graph, recNode.info, "zeroDefault", mZeroDefault)), newNodeIT(nkType, recNode.info, asgnType) ) asgnExpr.flags.incl nfSkipFieldChecking - asgnExpr.typ = recType + asgnExpr.typ = recNode.typ result.add newTree(nkExprColonExpr, recNode, asgnExpr) else: doAssert false @@ -615,9 +615,9 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = if field.ast != nil: #Try to use default value result.add newTree(nkExprColonExpr, recNode, field.ast) elif recType.kind in {tyObject, tyArray, tyTuple}: - let asgnExpr = defaultNodeField(c, recNode, recType) + let asgnExpr = defaultNodeField(c, recNode, recNode.typ) if asgnExpr != nil: - asgnExpr.typ = recType + asgnExpr.typ = recNode.typ asgnExpr.flags.incl nfSkipFieldChecking result.add newTree(nkExprColonExpr, recNode, asgnExpr) else: @@ -628,8 +628,8 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode = if aTypSkip.kind == tyObject: let child = defaultFieldsForTheUninitialized(c, aTypSkip.n) if child.len > 0: - var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTypSkip)) - asgnExpr.typ = aTypSkip + var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTyp)) + asgnExpr.typ = aTyp asgnExpr.sons.add child result = semExpr(c, asgnExpr) elif aTypSkip.kind == tyArray: diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim index 97e3a207d7..b571965ea1 100644 --- a/tests/objects/tobject_default_value.nim +++ b/tests/objects/tobject_default_value.nim @@ -614,6 +614,80 @@ template main {.dirty.} = type SearchOptions = object evaluation = evaluate + block: + type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate: bool + else: + case oResultPrivate: bool + of false: + eResultPrivate: E + of true: + discard + else: + when E is void: + case oResultPrivate: bool + of false: + discard + of true: + vResultPrivate: T + else: + case oResultPrivate: bool + of false: + eResultPrivate: E + of true: + vResultPrivate: T + + + template `?`[T, E](self: Result[T, E]): auto = + let v = (self) + if not v.oResultPrivate: + when compiles(`assignResult?`(default(typeof(result)))): + when typeof(result) is typeof(v): + `assignResult?`(v) + elif E is void: + `assignResult?`(err(typeof(result))) + else: + `assignResult?`(err(typeof(result), v.eResultPrivate)) + return + else: + return + when typeof(result) is typeof(v): + v + elif E is void: + err(typeof(result)) + else: + err(typeof(result), v.eResultPrivate) + + when not(T is void): + v.vResultPrivate + + type R = Result[int, string] + + proc testAssignResult() = + var assigned: bool + template `assignResult?`(v: Result) = + assigned = true + result = v + + proc failed(): Result[int, string] = + discard + + proc calling(): Result[int, string] = + let _ = ? failed() + doAssert false + + let r = calling() + doAssert assigned + + when nimvm: + when not defined(js): + testAssignResult() + else: + testAssignResult() + static: main() main() From 871e4af6ef384ef27c9357dab24ab727a2006eae Mon Sep 17 00:00:00 2001 From: Ecorous Date: Fri, 12 May 2023 13:44:29 +0100 Subject: [PATCH 091/489] add getDataDir to std/appdirs.nim (#21754) * add getDataDir to std/appdirs.nim * reuse `osappdirs.getDataDir` * Update lib/std/appdirs.nim --------- Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- lib/std/appdirs.nim | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/std/appdirs.nim b/lib/std/appdirs.nim index c945ba8ec1..963451efe2 100644 --- a/lib/std/appdirs.nim +++ b/lib/std/appdirs.nim @@ -17,6 +17,23 @@ proc getHomeDir*(): Path {.inline, tags: [ReadEnvEffect, ReadIOEffect].} = ## * `getTempDir proc`_ result = Path(osappdirs.getHomeDir()) +proc getDataDir*(): Path {.inline, tags: [ReadEnvEffect, ReadIOEffect].} = + ## Returns the data directory of the current user for applications. + ## + ## On non-Windows OSs, this proc conforms to the XDG Base Directory + ## spec. Thus, this proc returns the value of the `XDG_DATA_HOME` environment + ## variable if it is set, otherwise it returns the default configuration + ## directory ("~/.local/share" or "~/Library/Application Support" on macOS). + ## + ## See also: + ## * `getHomeDir proc`_ + ## * `getConfigDir proc`_ + ## * `getTempDir proc`_ + ## * `expandTilde proc`_ + ## * `getCurrentDir proc`_ + ## * `setCurrentDir proc`_ + result = Path(osappdirs.getDataDir()) + proc getConfigDir*(): Path {.inline, tags: [ReadEnvEffect, ReadIOEffect].} = ## Returns the config directory of the current user for applications. ## From ddce5559981ac5dedd3a5dfb210eb25296e69307 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 12 May 2023 21:24:14 +0800 Subject: [PATCH 092/489] improve `wasMoved` hooks; allow reset to use the overridden `wasMoved` hook (#21831) * improve `wasMoved` hooks * Because `wasMoved` is lifted --- compiler/injectdestructors.nim | 2 +- compiler/liftdestructors.nim | 37 +++++++++++++++++++++------------- compiler/optimizer.nim | 2 +- compiler/semmagic.nim | 9 +++++++++ lib/system.nim | 13 ++++++++---- 5 files changed, 43 insertions(+), 20 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 7183aac4e0..56ca8f605c 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -381,7 +381,7 @@ proc genWasMoved(c: var Con, n: PNode): PNode = result = genOp(c, op, n) else: result = newNodeI(nkCall, n.info) - result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved))) + result.add(newSymNode(createMagic(c.graph, c.idgen, "`=wasMoved`", mWasMoved))) result.add copyTree(n) #mWasMoved does not take the address #if n.kind != nkSym: # message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")") diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 43e5baf086..e8db145690 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -89,7 +89,7 @@ proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = call.typ = t body.add newAsgnStmt(x, call) elif c.kind == attachedWasMoved: - body.add genBuiltin(c, mWasMoved, "wasMoved", x) + body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) proc genAddr(c: var TLiftCtx; x: PNode): PNode = if x.kind == nkHiddenDeref: @@ -143,7 +143,7 @@ proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode = if sfNeverRaises notin op.flags: c.canRaise = true if c.addMemReset: - result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "wasMoved", x)) + result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "`=wasMoved`", x)) else: result = destroy @@ -262,7 +262,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) = #body.add newAsgnStmt(blob, x) var wasMovedCall = newNodeI(nkCall, c.info) - wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "wasMoved", mWasMoved))) + wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "`=wasMoved`", mWasMoved))) wasMovedCall.add x # mWasMoved does not take the address body.add wasMovedCall @@ -548,7 +548,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if canFormAcycle(c.g, t.elemType): # follow all elements: forallElements(c, t, body, x, y) - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) of attachedDup: assert false, "cannot happen" @@ -588,7 +588,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if op == nil: return # protect from recursion body.add newHookCall(c, op, x, y) - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) of attachedDup: assert false, "cannot happen" @@ -606,7 +606,7 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genBuiltin(c, mDestroy, "destroy", x) of attachedTrace: discard "strings are atomic and have no inner elements that are to trace" - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) of attachedDup: assert false, "cannot happen" @@ -707,7 +707,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # If the ref is polymorphic we have to account for this body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y) #echo "can follow ", elemType, " static ", isFinal(elemType) - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) of attachedDup: assert false, "cannot happen" @@ -758,7 +758,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y) - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) of attachedDup: assert false, "cannot happen" @@ -785,7 +785,7 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.sons.insert(des, 0) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) of attachedDup: assert false, "cannot happen" @@ -813,7 +813,7 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, x, actions) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) of attachedDup: assert false, "cannot happen" @@ -850,7 +850,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.sons.insert(des, 0) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) of attachedDup: assert false, "cannot happen" @@ -868,7 +868,7 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, xx, actions) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard - of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x) + of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) of attachedDup: assert false, "cannot happen" @@ -934,8 +934,14 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = defaultOp(c, t, body, x, y) of tyObject: if not considerUserDefinedOp(c, t, body, x, y): - if c.kind in {attachedAsgn, attachedSink} and t.sym != nil and sfImportc in t.sym.flags: - body.add newAsgnStmt(x, y) + if t.sym != nil and sfImportc in t.sym.flags: + case c.kind + of {attachedAsgn, attachedSink}: + body.add newAsgnStmt(x, y) + of attachedWasMoved: + body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) + else: + fillBodyObjT(c, t, body, x, y) else: fillBodyObjT(c, t, body, x, y) of tyDistinct: @@ -1004,6 +1010,9 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp result.ast = n incl result.flags, sfFromGeneric incl result.flags, sfGeneratedOp + if kind == attachedWasMoved: + incl result.flags, sfNoSideEffect + incl result.typ.flags, tfNoSideEffect proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) = let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x) diff --git a/compiler/optimizer.nim b/compiler/optimizer.nim index 0b26e8d34f..a5cfa54209 100644 --- a/compiler/optimizer.nim +++ b/compiler/optimizer.nim @@ -113,7 +113,7 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) = if n[0].kind == nkSym: let s = n[0].sym let name = s.name.s.normalize - if s.magic == mWasMoved or name == "=wasmoved": + if name == "=wasmoved": b.wasMovedLocs.add n special = true elif name == "=destroy": diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 71efcadb1d..b47737beee 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -613,6 +613,15 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, let op = getAttachedOp(c.graph, t, attachedTrace) if op != nil: result[0] = newSymNode(op) + of mWasMoved: + result = n + let t = n[1].typ.skipTypes(abstractVar) + let op = getAttachedOp(c.graph, t, attachedWasMoved) + if op != nil: + result[0] = newSymNode(op) + let addrExp = newNodeIT(nkHiddenAddr, result[1].info, makePtrType(c, t)) + addrExp.add result[1] + result[1] = addrExp of mUnown: result = semUnown(c, n) of mExists, mForall: diff --git a/lib/system.nim b/lib/system.nim index e7b6ed7c3c..f8523b0947 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -137,15 +137,20 @@ proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {. ## **Note**: The `finalizer` refers to the type `T`, not to the object! ## This means that for each object of type `T` the finalizer will be called! -proc wasMoved*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} = +proc `=wasMoved`[T](obj: var T) {.magic: "WasMoved", noSideEffect.} = + ## Generic `wasMoved`:idx: implementation that can be overridden. + +proc wasMoved*[T](obj: var T) {.inline, noSideEffect.} = ## Resets an object `obj` to its initial (binary zero) value to signify ## it was "moved" and to signify its destructor should do nothing and ## ideally be optimized away. - discard + {.cast(raises: []), cast(tags: []).}: + `=wasMoved`(obj) proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} = result = x - wasMoved(x) + {.cast(raises: []), cast(tags: []).}: + `=wasMoved`(x) type range*[T]{.magic: "Range".} ## Generic type to construct range types. @@ -912,7 +917,7 @@ proc reset*[T](obj: var T) {.noSideEffect.} = when defined(gcDestructors): {.cast(noSideEffect), cast(raises: []), cast(tags: []).}: `=destroy`(obj) - wasMoved(obj) + `=wasMoved`(obj) else: obj = default(typeof(obj)) From 0ece98620f8d9d7b874262c75fa148970626d44d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 14 May 2023 13:59:41 +0800 Subject: [PATCH 093/489] closes #7590; add a test case (#21846) --- tests/vm/tvmmisc.nim | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 11fdcbd8ce..f41a918f95 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -668,3 +668,23 @@ block: # bug #10108 discard y2 reject: const c5 = deliver_x() + +block: # bug #7590 + proc doInit[T]():auto= + var a: T + return a + + proc fun2[T](tup1:T)= + const tup0=doInit[T]() + + # var tup=tup0 #ok + const tup=tup0 #causes bug + + doAssert tup is tuple + doAssert tup[0] is tuple + for ai in tup.fields: + doAssert ai is tuple, "BUG2" + + # const c=(foo:(bar1: 0.0)) + const c=(foo:(bar1:"foo1")) + fun2(c) From f4a9b258c34a83efb74d9dea6853880e47f45b06 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 14 May 2023 16:58:28 +0200 Subject: [PATCH 094/489] isolation spec update; WIP (#21843) * isolation spec update; WIP * wip * docs update, WIP * progress * Update doc/manual.md --- compiler/ast.nim | 5 +- compiler/condsyms.nim | 2 +- compiler/isolation_check.nim | 76 ++++++++++++++++++- compiler/pragmas.nim | 9 ++- compiler/wordrecg.nim | 1 + doc/manual.md | 10 +-- doc/manual_experimental.md | 123 +++++++++++++++++++++++++++++++ lib/std/isolation.nim | 6 +- tests/isolate/tisolated_lock.nim | 67 +++++++++++++++++ 9 files changed, 284 insertions(+), 15 deletions(-) create mode 100644 tests/isolate/tisolated_lock.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 41e5387427..3ed9bf2b2a 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -515,7 +515,7 @@ type nfSkipFieldChecking # node skips field visable checking TNodeFlags* = set[TNodeFlag] - TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46) + TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47) tfVarargs, # procedure has C styled varargs # tyArray type represeting a varargs list tfNoSideEffect, # procedure type does not allow side effects @@ -585,6 +585,7 @@ type tfIsConstructor tfEffectSystemWorkaround tfIsOutParam + tfSendable TTypeFlags* = set[TTypeFlag] @@ -634,7 +635,7 @@ const skError* = skUnknown var - eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam} + eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam, tfSendable} ## type flags that are essential for type equality. ## This is now a variable because for emulation of version:1.0 we ## might exclude {tfGcSafe, tfNoSideEffect}. diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index ea635e52e1..9d9ba1605e 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -154,4 +154,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasWarnBareExcept") defineSymbol("nimHasDup") defineSymbol("nimHasChecksums") - + defineSymbol("nimHasSendable") diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index 2674605dcf..273bfb7f9f 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -72,6 +72,69 @@ proc isValueOnlyType(t: PType): bool = proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr, tyVar, tyLent} result = not types.searchTypeFor(t, wrap) +type + SearchResult = enum + NotFound, Abort, Found + +proc containsDangerousRefAux(t: PType; marker: var IntSet): SearchResult + +proc containsDangerousRefAux(n: PNode; marker: var IntSet): SearchResult = + result = NotFound + case n.kind + of nkRecList: + for i in 0.. Date: Mon, 15 May 2023 21:16:49 +0200 Subject: [PATCH 095/489] fix #21848 (#21852) --- compiler/ccgexprs.nim | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 38ecb11aab..4ad63de8f2 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -3377,18 +3377,19 @@ proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool; result: var Rope) proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool; result: var Rope) = let base = t.skipTypes(abstractInst)[0] - var data = rope"{" - for i in 0.. 0: data.addf(",$n", []) - genBracedInit(p, n[i], isConst, base, data) - data.add("}") + var data = rope"" + if n.len > 0: + data.add(", {") + for i in 0.. 0: data.addf(",$n", []) + genBracedInit(p, n[i], isConst, base, data) + data.add("}") let payload = getTempName(p.module) - appcg(p.module, cfsStrData, "static $5 struct {$n" & " NI cap; $1 data[$2];$n" & - "} $3 = {$2 | NIM_STRLIT_FLAG, $4};$n", [ + "} $3 = {$2 | NIM_STRLIT_FLAG$4};$n", [ getTypeDesc(p.module, base), n.len, payload, data, if isConst: "const" else: ""]) result.add "{$1, ($2*)&$3}" % [rope(n.len), getSeqPayloadType(p.module, t), payload] From ce1ba915732dfff88cd9e7d975060a2a2250cd72 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 16 May 2023 03:17:06 +0800 Subject: [PATCH 096/489] close #19990; adds a test case (#21853) --- tests/arc/tarc_orc.nim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/arc/tarc_orc.nim b/tests/arc/tarc_orc.nim index 981567350e..2fbb2e7921 100644 --- a/tests/arc/tarc_orc.nim +++ b/tests/arc/tarc_orc.nim @@ -45,3 +45,17 @@ proc main() = # todo bug with templates doAssert b() == @[] static: main() main() + + +type Obj = tuple + value: int + arr: seq[int] + +proc bug(): seq[Obj] = + result.add (value: 0, arr: @[]) + result[^1].value = 1 + result[^1].arr.add 1 + +# bug #19990 +let s = bug() +doAssert s[0] == (value: 1, arr: @[1]) From eecf12c4b5fa8a011b1fc1991b554a31ca9a4a27 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 17 May 2023 06:20:40 +0800 Subject: [PATCH 097/489] fixes #21708; skip colons for tuples in VM (#21850) * fixes #21708; skip colon for tuples in VM * skip nimnodes * fixes types --- compiler/vm.nim | 8 +++++++- tests/vm/tvmmisc.nim | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index ba3677cf1b..4a505c9209 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -20,7 +20,7 @@ import when defined(nimPreviewSlimSystem): import std/formatfloat - +import astalgo import ast except getstr from semfold import leValueConv, ordinalValToString from evaltempl import evalTemplate @@ -844,6 +844,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of nkObjConstr: let n = src[rc + 1].skipColon regs[ra].node = n + of nkTupleConstr: + let n = if src.typ != nil and tfTriggersCompileTime in src.typ.flags: + src[rc] + else: + src[rc].skipColon + regs[ra].node = n else: let n = src[rc] regs[ra].node = n diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index f41a918f95..9e32c92493 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -688,3 +688,13 @@ block: # bug #7590 # const c=(foo:(bar1: 0.0)) const c=(foo:(bar1:"foo1")) fun2(c) + +block: # bug #21708 + type + Tup = tuple[name: string] + + const X: array[2, Tup] = [(name: "foo",), (name: "bar",)] + + static: + let s = X[0] + doAssert s[0] == "foo" From f22e5067c5e0f375cb2263ec779d6e6ede108155 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 17 May 2023 06:21:34 +0800 Subject: [PATCH 098/489] fixes #21847; let `parseFloat` behave like `strtod` (#21854) --- lib/system/strmantle.nim | 4 +++- tests/float/tfloat4.nim | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index ab158d6b7c..60c63501cc 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -178,7 +178,9 @@ proc nimParseBiggestFloat(s: openArray[char], number: var BiggestFloat, # if exponent greater than can be represented: +/- zero or infinity if absExponent > 999: - if expNegative: + if integer == 0: + number = 0.0 + elif expNegative: number = 0.0*sign else: number = Inf*sign diff --git a/tests/float/tfloat4.nim b/tests/float/tfloat4.nim index f6216c374e..2bb61eb58e 100644 --- a/tests/float/tfloat4.nim +++ b/tests/float/tfloat4.nim @@ -56,8 +56,14 @@ doAssert 0.9999999999999999 == ".9999999999999999".parseFloat # bug #18400 var s = [-13.888888'f32] -assert $s[0] == "-13.888888" +doAssert $s[0] == "-13.888888" var x = 1.23456789012345'f32 -assert $x == "1.2345679" +doAssert $x == "1.2345679" + +# bug #21847 +doAssert parseFloat"0e+42" == 0.0 +doAssert parseFloat"0e+42949672969" == 0.0 +doAssert parseFloat"0e+42949672970" == 0.0 +doAssert parseFloat"0e+42949623223346323563272970" == 0.0 echo("passed all tests.") From 1314ea75169b877f458e8b4eb1455d5f6428227b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 17 May 2023 06:02:11 +0200 Subject: [PATCH 099/489] tasks that support return values (#21859) tasks.nim: Code cleanups and support expressions that produce a value --- lib/std/tasks.nim | 60 ++++++++++++++++++++++++----------------- tests/stdlib/ttasks.nim | 18 +++++++++++++ 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim index 055ddf144d..dadb2bc97a 100644 --- a/lib/std/tasks.nim +++ b/lib/std/tasks.nim @@ -11,7 +11,6 @@ ## A `Task` should be only owned by a single Thread, it cannot be shared by threads. import std/[macros, isolation, typetraits] -import system/ansi_c when defined(nimPreviewSlimSystem): import std/assertions @@ -62,7 +61,7 @@ when compileOption("threads"): type Task* = object ## `Task` contains the callback and its arguments. - callback: proc (args: pointer) {.nimcall, gcsafe.} + callback: proc (args, res: pointer) {.nimcall, gcsafe.} args: pointer destroy: proc (args: pointer) {.nimcall, gcsafe.} @@ -74,12 +73,12 @@ proc `=destroy`*(t: var Task) {.inline, gcsafe.} = if t.args != nil: if t.destroy != nil: t.destroy(t.args) - c_free(t.args) + deallocShared(t.args) -proc invoke*(task: Task) {.inline, gcsafe.} = +proc invoke*(task: Task; res: pointer = nil) {.inline, gcsafe.} = ## Invokes the `task`. assert task.callback != nil - task.callback(task.args) + task.callback(task.args, res) template checkIsolate(scratchAssignList: seq[NimNode], procParam, scratchDotExpr: NimNode) = # block: @@ -110,8 +109,8 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC let b = toTask hello(13) assert b is Task - if getTypeInst(e).typeKind != ntyVoid: - error("'toTask' cannot accept a call with a return value", e) + let retType = getTypeInst(e) + let returnsVoid = retType.typeKind == ntyVoid when compileOption("threads"): if not isGcSafe(e[0]): @@ -188,27 +187,18 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC let scratchObjPtrType = quote do: - cast[ptr `scratchObjType`](c_calloc(csize_t 1, csize_t sizeof(`scratchObjType`))) + cast[ptr `scratchObjType`](allocShared0(sizeof(`scratchObjType`))) - let scratchLetSection = newLetStmt( - scratchIdent, - scratchObjPtrType - ) - - let scratchCheck = quote do: - if `scratchIdent`.isNil: - raise newException(OutOfMemDefect, "Could not allocate memory") + let scratchLetSection = newLetStmt(scratchIdent, scratchObjPtrType) var stmtList = newStmtList() stmtList.add(scratchObj) stmtList.add(scratchLetSection) - stmtList.add(scratchCheck) stmtList.add(nnkBlockStmt.newTree(newEmptyNode(), newStmtList(scratchAssignList))) var functionStmtList = newStmtList() let funcCall = newCall(e[0], callNode) functionStmtList.add tempAssignList - functionStmtList.add funcCall let funcName = genSym(nskProc, e[0].strVal) let destroyName = genSym(nskProc, "destroyScratch") @@ -216,12 +206,24 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC let tempNode = quote("@") do: `=destroy`(@objTemp2[]) + var funcDecl: NimNode + if returnsVoid: + funcDecl = quote do: + proc `funcName`(args, res: pointer) {.gcsafe, nimcall.} = + let `objTemp` = cast[ptr `scratchObjType`](args) + `functionStmtList` + `funcCall` + else: + funcDecl = quote do: + proc `funcName`(args, res: pointer) {.gcsafe, nimcall.} = + let `objTemp` = cast[ptr `scratchObjType`](args) + `functionStmtList` + cast[ptr `retType`](res)[] = `funcCall` + result = quote do: `stmtList` - proc `funcName`(args: pointer) {.gcsafe, nimcall.} = - let `objTemp` = cast[ptr `scratchObjType`](args) - `functionStmtList` + `funcDecl` proc `destroyName`(args: pointer) {.gcsafe, nimcall.} = let `objTemp2` = cast[ptr `scratchObjType`](args) @@ -232,11 +234,19 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC let funcCall = newCall(e[0]) let funcName = genSym(nskProc, e[0].strVal) - result = quote do: - proc `funcName`(args: pointer) {.gcsafe, nimcall.} = - `funcCall` + if returnsVoid: + result = quote do: + proc `funcName`(args, res: pointer) {.gcsafe, nimcall.} = + `funcCall` + + Task(callback: `funcName`, args: nil) + else: + result = quote do: + proc `funcName`(args, res: pointer) {.gcsafe, nimcall.} = + cast[ptr `retType`](res)[] = `funcCall` + + Task(callback: `funcName`, args: nil) - Task(callback: `funcName`, args: nil) when defined(nimTasksDebug): echo result.repr diff --git a/tests/stdlib/ttasks.nim b/tests/stdlib/ttasks.nim index 4889d49d94..347c3347a0 100644 --- a/tests/stdlib/ttasks.nim +++ b/tests/stdlib/ttasks.nim @@ -505,3 +505,21 @@ block: b.invoke() doAssert called == 36 + + block: + proc returnsSomething(a, b: int): int = a + b + + proc noArgsButReturnsSomething(): string = "abcdef" + + proc testReturnValues() = + let t = toTask returnsSomething(2233, 11) + var res: int + t.invoke(addr res) + doAssert res == 2233+11 + + let tb = toTask noArgsButReturnsSomething() + var resB: string + tb.invoke(addr resB) + doAssert resB == "abcdef" + + testReturnValues() From 02a10ec379d427f27f471d489247aa586078354b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Wed, 17 May 2023 10:44:42 +0100 Subject: [PATCH 100/489] Cpp Vfunctions draft (#21790) * introduces virtual pragma, modifies proc def, prevents proc decl * marks virtual procs as infix * forward declare vfuncs inside the typedef * adds naked callConv to virtual * virtual proc error if not defined in the same top level scope as the type * first param is now this. extracts genvirtualheaderproc * WIP syntax * supports obj. Removes the need for the prefix * parameter count starts as this. Cleanup * clean up * sem tests * adds integration tests * uses constraint to store the virtual content * introduces genVirtualProcParams --------- Co-authored-by: Andreas Rumpf --- compiler/ast.nim | 5 +- compiler/ccgtypes.nim | 155 ++++++++++++++++++++++++++++++++++++-- compiler/cgen.nim | 7 +- compiler/modulegraphs.nim | 1 + compiler/pragmas.nim | 17 ++++- compiler/sempass2.nim | 1 - compiler/semstmts.nim | 19 +++++ tests/cpp/tvirtual.nim | 68 +++++++++++++++++ 8 files changed, 260 insertions(+), 13 deletions(-) create mode 100644 tests/cpp/tvirtual.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 3ed9bf2b2a..7e92cd140b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -231,7 +231,7 @@ type TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # 49 flags! + TSymFlag* = enum # 50 flags! sfUsed, # read access of sym (for warnings) or simply used sfExported, # symbol is exported from module sfFromGeneric, # symbol is instantiation of a generic; this is needed @@ -312,6 +312,7 @@ type # # This is disallowed but can cause the typechecking to go into # an infinite loop, this flag is used as a sentinel to stop it. + sfVirtual # proc is a C++ virtual function TSymFlags* = set[TSymFlag] @@ -929,7 +930,7 @@ type cname*: string # resolved C declaration name in importc decl, e.g.: # proc fun() {.importc: "$1aux".} => cname = funaux constraint*: PNode # additional constraints like 'lit|result'; also - # misused for the codegenDecl pragma in the hope + # misused for the codegenDecl and virtual pragmas in the hope # it won't cause problems # for skModule the string literal to output for # deprecated modules. diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 2669dec247..7bd4dac81b 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -12,6 +12,7 @@ # ------------------------- Name Mangling -------------------------------- import sighashes, modulegraphs +import strscans import ../dist/checksums/src/checksums/md5 proc isKeyword(w: PIdent): bool = @@ -424,9 +425,105 @@ proc paramStorageLoc(param: PSym): TStorageLoc = else: result = OnUnknown +macro unrollChars(x: static openArray[char], name, body: untyped) = + result = newStmtList() + for a in x: + result.add(newBlockStmt(newStmtList( + newConstStmt(name, newLit(a)), + copy body + ))) + +proc multiFormat*(frmt: var string, chars : static openArray[char], args: openArray[seq[string]]) = + var res : string + unrollChars(chars, c): + res = "" + let arg = args[find(chars, c)] + var i = 0 + var num = 0 + while i < frmt.len: + if frmt[i] == c: + inc(i) + case frmt[i] + of c: + res.add(c) + inc(i) + of '0'..'9': + var j = 0 + while true: + j = j * 10 + ord(frmt[i]) - ord('0') + inc(i) + if i >= frmt.len or frmt[i] notin {'0'..'9'}: break + num = j + if j > high(arg) + 1: + doAssert false, "invalid format string: " & frmt + else: + res.add(arg[j-1]) + else: + doAssert false, "invalid format string: " & frmt + var start = i + while i < frmt.len: + if frmt[i] != c: inc(i) + else: break + if i - 1 >= start: + res.add(substr(frmt, start, i - 1)) + frmt = res + +proc genVirtualProcParams(m: BModule; t: PType, rettype, params: var string, + check: var IntSet, declareEnvironment=true; + weakDep=false;) = + if t[0] == nil or isInvalidReturnType(m.config, t): + rettype = "void" + else: + if rettype == "": + rettype = getTypeDescAux(m, t[0], check, skResult) + else: + rettype = runtimeFormat(rettype.replace("'0", "$1"), [getTypeDescAux(m, t[0], check, skResult)]) + var this = t.n[1].sym + fillParamName(m, this) + fillLoc(this.loc, locParam, t.n[1], + this.paramStorageLoc) + if this.typ.kind == tyPtr: + this.loc.r = "this" + else: + this.loc.r = "(*this)" + + var types = @[getTypeDescWeak(m, this.typ, check, skParam)] + var names = @[this.loc.r] + + for i in 2.. -1 + isOverride = afterParams.find("override") > -1 + discard scanf(afterParams, "->$s$* ", retType) + params = "(" & params & ")" + +proc genVirtualProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl : bool = false) = + assert sfVirtual in prc.flags + # using static is needed for inline procs + var check = initIntSet() + fillBackendName(m, prc) + fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown) + var typ = prc.typ.n[1].sym.typ + var memberOp = "#." + if typ.kind == tyPtr: + typ = typ[0] + memberOp = "#->" + var typDesc = getTypeDescWeak(m, typ, check, skParam) + let asPtrStr = rope(if asPtr: "_PTR" else: "") + var name, params, rettype: string + var isFnConst, isOverride: bool + parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, isFnConst, isOverride) + genVirtualProcParams(m, prc.typ, rettype, params, check, true, false) + var fnConst, override: string + if isFnConst: + fnConst = " const" + if isFwdDecl: + rettype = "virtual " & rettype + if isOverride: + override = " override" + else: + prc.loc.r = "$1 $2 (@)" % [memberOp, name] + name = "$1::$2" % [typDesc, name] + + result.add "N_LIB_PRIVATE " + result.addf("$1$2($3, $4)$5$6$7", + [rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name, + params, fnConst, override]) + proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false) = # using static is needed for inline procs var check = initIntSet() fillBackendName(m, prc) fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown) var rettype, params: Rope - genProcParams(m, prc.typ, rettype, params, check) + genProcParams(m, prc.typ, rettype, params, check, true, false) # handle the 2 options for hotcodereloading codegen - function pointer # (instead of forward declaration) or header for function body with "_actual" postfix let asPtrStr = rope(if asPtr: "_PTR" else: "") var name = prc.loc.r - if isReloadable(m, prc) and not asPtr: - name.add("_actual") # careful here! don't access ``prc.ast`` as that could reload large parts of # the object graph! if prc.constraint.isNil: @@ -1003,6 +1147,7 @@ proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false) let asPtrStr = if asPtr: (rope("(*") & name & ")") else: name result.add runtimeFormat(prc.cgDeclFrmt, [rettype, asPtrStr, params]) + # ------------------ type info generation ------------------------------------- proc genTypeInfoV1(m: BModule; t: PType; info: TLineInfo): Rope diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 17b0350b6c..107af373b0 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1128,7 +1128,10 @@ proc isNoReturn(m: BModule; s: PSym): bool {.inline.} = proc genProcAux*(m: BModule, prc: PSym) = var p = newProc(prc, m) var header = newRopeAppender() - genProcHeader(m, prc, header) + if m.config.backend == backendCpp and sfVirtual in prc.flags: + genVirtualProcHeader(m, prc, header) + else: + genProcHeader(m, prc, header) var returnStmt: Rope = "" assert(prc.ast != nil) @@ -1234,7 +1237,7 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} = proc genProcPrototype(m: BModule, sym: PSym) = useHeader(m, sym) - if lfNoDecl in sym.loc.flags: return + if lfNoDecl in sym.loc.flags or sfVirtual in sym.flags: return if lfDynamicLib in sym.loc.flags: if sym.itemId.module != m.module.position and not containsOrIncl(m.declaredThings, sym.id): diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 5cb6a1c34a..de97ced995 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -79,6 +79,7 @@ type procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId. attachedOps*: array[TTypeAttachedOp, Table[ItemId, LazySym]] # Type ID, destructors, etc. methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods + virtualProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached virtual procs enumToStringProcs*: Table[ItemId, LazySym] emittedTypeInfo*: Table[string, FileIndex] diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 6fe09921d2..be8e83d25d 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -34,7 +34,7 @@ const wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl, wGensym, wInject, wRaises, wEffectsOf, wTags, wForbids, wLocks, wDelegator, wGcSafe, wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy, - wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect} + wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect, wVirtual} converterPragmas* = procPragmas methodPragmas* = procPragmas+{wBase}-{wImportCpp} templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty, @@ -211,9 +211,9 @@ proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) = let m = s.getModule() incl(m.flags, sfCompileToObjc) -proc newEmptyStrNode(c: PContext; n: PNode): PNode {.noinline.} = +proc newEmptyStrNode(c: PContext; n: PNode, strVal: string = ""): PNode {.noinline.} = result = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString)) - result.strVal = "" + result.strVal = strVal proc getStrLitNode(c: PContext, n: PNode): PNode = if n.kind notin nkPragmaCallKinds or n.len != 2: @@ -245,6 +245,14 @@ proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string = if n.kind in nkPragmaCallKinds: result = expectStrLit(c, n) else: result = defaultStr +proc processVirtual(c: PContext, n: PNode, s: PSym) = + s.constraint = newEmptyStrNode(c, n, getOptionalStr(c, n, "$1")) + s.constraint.strVal = s.constraint.strVal % s.name.s + s.flags.incl {sfVirtual, sfInfixCall, sfExportc, sfMangleCpp} + + s.typ.callConv = ccNoConvention + incl c.config.globalOptions, optMixedMode + proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) = sym.constraint = getStrLitNode(c, n) @@ -1263,6 +1271,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, sym.flags.incl sfNeverRaises of wSystemRaisesDefect: sym.flags.incl sfSystemRaisesDefect + of wVirtual: + processVirtual(c, it, sym) + else: invalidPragma(c, it) elif comesFromPush and whichKeyword(ident) != wInvalid: discard "ignore the .push pragma; it doesn't apply" diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 7024c99fe7..fc9755aa2c 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -833,7 +833,6 @@ proc trackCall(tracked: PEffects; n: PNode) = # and it's not a recursive call: if not (a.kind == nkSym and a.sym == tracked.owner): markSideEffect(tracked, a, n.info) - # p's effects are ours too: var a = n[0] #if canRaise(a): diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f81423915b..579af973ef 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2188,6 +2188,25 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if sfBorrow in s.flags and c.config.cmd notin cmdDocLike: result[bodyPos] = c.graph.emptyNode + + if sfVirtual in s.flags: + if c.config.backend == backendCpp: + for son in s.typ.sons: + if son!=nil and son.isMetaType: + localError(c.config, n.info, "virtual unsupported for generic routine") + + var typ = s.typ.sons[1] + if typ.kind == tyPtr: + typ = typ[0] + if typ.kind != tyObject: + localError(c.config, n.info, "virtual must be a non ref object type") + if typ.owner.id == s.owner.id and c.module.id == s.owner.id: + c.graph.virtualProcsPerType.mgetOrPut(typ.itemId, @[]).add s + else: + localError(c.config, n.info, + "virtual procs must be defined in the same scope as the type they are virtual for and it must be a top level scope") + else: + localError(c.config, n.info, "virtual procs are only supported in C++") if n[bodyPos].kind != nkEmpty and sfError notin s.flags: # for DLL generation we allow sfImportc to have a body, for use in VM diff --git a/tests/cpp/tvirtual.nim b/tests/cpp/tvirtual.nim new file mode 100644 index 0000000000..d7dd6a7c43 --- /dev/null +++ b/tests/cpp/tvirtual.nim @@ -0,0 +1,68 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" + output: ''' +hello foo +hello boo +hello boo +Const Message: hello world +NimPrinter: hello world +NimPrinterConstRef: hello world +''' +""" + +{.emit:"""/*TYPESECTION*/ +#include + class CppPrinter { + public: + + virtual void printConst(char* message) const { + std::cout << "Const Message: " << message << std::endl; + } + virtual void printConstRef(char* message, const int& flag) const { + std::cout << "Const Ref Message: " << message << std::endl; + } +}; +""".} + +proc newCpp*[T](): ptr T {.importcpp:"new '*0()".} +type + Foo = object of RootObj + FooPtr = ptr Foo + Boo = object of Foo + BooPtr = ptr Boo + CppPrinter {.importcpp, inheritable.} = object + NimPrinter {.exportc.} = object of CppPrinter + +proc salute(self:FooPtr) {.virtual.} = + echo "hello foo" + +proc salute(self:BooPtr) {.virtual.} = + echo "hello boo" + +let foo = newCpp[Foo]() +let boo = newCpp[Boo]() +let booAsFoo = cast[FooPtr](newCpp[Boo]()) + +#polymorphism works +foo.salute() +boo.salute() +booAsFoo.salute() +let message = "hello world".cstring + +proc printConst(self:CppPrinter, message:cstring) {.importcpp.} +CppPrinter().printConst(message) + +#notice override is optional. +#Will make the cpp compiler to fail if not virtual function with the same signature if found in the base type +proc printConst(self:NimPrinter, message:cstring) {.virtual:"$1('2 #2) const override".} = + echo "NimPrinter: " & $message + +proc printConstRef(self:NimPrinter, message:cstring, flag:int32) {.virtual:"$1('2 #2, const '3& #3 ) const override".} = + echo "NimPrinterConstRef: " & $message + +NimPrinter().printConst(message) +var val : int32 = 10 +NimPrinter().printConstRef(message, val) + + From 21ff10b882ccf0b5eeec44a73dfec16b0cb32f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Fri, 19 May 2023 20:23:29 +0100 Subject: [PATCH 101/489] documents virtual (#21860) * documents virtual * Apply suggestions from code review --------- Co-authored-by: Andreas Rumpf --- doc/manual_experimental.md | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 93d9938797..6e11e03eac 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -2130,3 +2130,79 @@ can be used in an `isolate` context: The `.sendable` pragma itself is an experimenal, unchecked, unsafe annotation. It is currently only used by `Isolated[T]`. + +Virtual pragma +---------------- + +`virtual` is designed to extend or create virtual functions when targeting the cpp backend. When a proc is marked with virtual, it forward declares the proc header within the type's body. + +Here's an example of how to use the virtual pragma: + +```nim + +proc newCpp*[T](): ptr T {.importcpp: "new '*0()".} +type + Foo = object of RootObj + FooPtr = ptr Foo + Boo = object of Foo + BooPtr = ptr Boo + +proc salute(self: FooPtr) {.virtual.} = + echo "hello foo" + +proc salute(self: BooPtr) {.virtual.} = + echo "hello boo" + +let foo = newCpp[Foo]() +let boo = newCpp[Boo]() +let booAsFoo = cast[FooPtr](newCpp[Boo]()) + +foo.salute() # prints hello foo +boo.salute() # prints hello boo +booAsFoo.salute() # prints hello boo + +``` +In this example, the `salute` function is virtual in both Foo and Boo types. This allows for polymorphism. + +The virtual pragma also supports a special syntax to express Cpp constraints. Here's how it works: + +`$1` refers to the function name +`'idx` refers to the type of the argument at the position idx. Where idx = 1 is the `this` argument. +`#idx` refers to the argument name. + +The return type can be referred to as `-> '0`, but this is optional and often not needed. + + ```nim + {.emit:"""/*TYPESECTION*/ +#include + class CppPrinter { + public: + + virtual void printConst(char* message) const { + std::cout << "Const Message: " << message << std::endl; + } + virtual void printConstRef(char* message, const int& flag) const { + std::cout << "Const Ref Message: " << message << std::endl; + } +}; +""".} + +type + CppPrinter {.importcpp, inheritable.} = object + NimPrinter {.exportc.} = object of CppPrinter + +proc printConst(self: CppPrinter; message:cstring) {.importcpp.} +CppPrinter().printConst(message) + +# override is optional. +proc printConst(self: NimPrinter; message: cstring) {.virtual: "$1('2 #2) const override".} = + echo "NimPrinter: " & $message + +proc printConstRef(self: NimPrinter; message: cstring; flag:int32) {.virtual: "$1('2 #2, const '3& #3 ) const override".} = + echo "NimPrinterConstRef: " & $message + +NimPrinter().printConst(message) +var val: int32 = 10 +NimPrinter().printConstRef(message, val) + +``` \ No newline at end of file From 4186529ff7ae9afcdf56ceed41da43e806e537e1 Mon Sep 17 00:00:00 2001 From: noah edward hall Date: Fri, 19 May 2023 14:23:44 -0500 Subject: [PATCH 102/489] Update threadpool.nim with correct link to typedthreads module (#21865) --- lib/pure/concurrency/threadpool.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 0eb20dc9a7..136850b4f0 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -13,7 +13,7 @@ ## ## See also ## ======== -## * `threads module `_ for basic thread support +## * `threads module `_ for basic thread support ## * `locks module `_ for locks and condition variables ## * `asyncdispatch module `_ for asynchronous IO From 476e0320048f82c2743ca96614fde87b69ef2559 Mon Sep 17 00:00:00 2001 From: heterodoxic <122719743+heterodoxic@users.noreply.github.com> Date: Fri, 19 May 2023 21:24:37 +0200 Subject: [PATCH 103/489] potential fix for C++ codegen with ARC/ORC and goto exceptions fixes #21579, fixes #21862 (#21868) potential fix for C++ codegen with ARC/ORC and goto exceptions --- compiler/ccgstmts.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 6ce632a2ae..315af8777c 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -329,7 +329,8 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = else: let imm = isAssignedImmediately(p.config, value) if imm and p.module.compileToCpp and p.splitDecls == 0 and - not containsHiddenPointer(v.typ): + not containsHiddenPointer(v.typ) and + nimErrorFlagAccessed notin p.flags: # C++ really doesn't like things like 'Foo f; f = x' as that invokes a # parameterless constructor followed by an assignment operator. So we # generate better code here: 'Foo f = x;' From a852b2e9cf80e806a85c92149d9f68f592e32185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Fri, 19 May 2023 20:31:57 +0100 Subject: [PATCH 104/489] refactor gettypedesc so it accepts its own kind instead of symkind (#21867) --- compiler/ccgexprs.nim | 20 ++++---- compiler/ccgstmts.nim | 2 +- compiler/ccgtypes.nim | 115 ++++++++++++++++++++++++------------------ compiler/cgen.nim | 44 ++++++++-------- 4 files changed, 100 insertions(+), 81 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 4ad63de8f2..d27535546e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -755,7 +755,7 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} = proc genDeref(p: BProc, e: PNode, d: var TLoc) = assert e[0].kind notin {nkBlockExpr, nkBlockStmt}, "it should have been transformed in transf" - let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0])) + let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0]) == skParam) if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags: # XXX the amount of hacks for C's arrays is incredible, maybe we should # simply wrap them in a struct? --> Losing auto vectorization then? @@ -823,7 +823,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e[0], a) putIntoDest(p, d, e, "&" & a.r, a.storage) #Message(e.info, warnUser, "HERE NEW &") - elif mapType(p.config, e[0].typ, mapTypeChooser(e[0])) == ctArray or isCppRef(p, e.typ): + elif mapType(p.config, e[0].typ, mapTypeChooser(e[0]) == skParam) == ctArray or isCppRef(p, e.typ): expr(p, e[0], d) else: var a: TLoc @@ -2510,10 +2510,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mNewSeqOfCap: genNewSeqOfCap(p, e, d) of mSizeOf: let t = e[1].typ.skipTypes({tyTypeDesc}) - putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, skVar)]) + putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, dkRefParam)]) of mAlignOf: let t = e[1].typ.skipTypes({tyTypeDesc}) - putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, skVar)]) + putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, dkRefParam)]) of mOffsetOf: var dotExpr: PNode if e[1].kind == nkDotExpr: @@ -2523,7 +2523,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: internalError(p.config, e.info, "unknown ast") let t = dotExpr[0].typ.skipTypes({tyTypeDesc}) - let tname = getTypeDesc(p.module, t, skVar) + let tname = getTypeDesc(p.module, t, dkRefParam) let member = if t.kind == tyTuple: "Field" & rope(dotExpr[1].sym.position) @@ -2843,7 +2843,7 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = # expression not found in the cache: inc(p.module.labels) p.module.s[cfsData].addf("static NIM_CONST $1 $2 = ", - [getTypeDesc(p.module, t, skConst), tmp]) + [getTypeDesc(p.module, t, dkConst), tmp]) genBracedInit(p, n, isConst = true, t, p.module.s[cfsData]) p.module.s[cfsData].addf(";$n", []) @@ -2870,13 +2870,13 @@ proc genConstHeader(m, q: BModule; p: BProc, sym: PSym) = if not genConstSetup(p, sym): return assert(sym.loc.r != "", $sym.name.s & $sym.itemId) if m.hcrOn: - m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r]); + m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, dkRefParam), sym.loc.r]); m.initProc.procSec(cpsLocals).addf( "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, - getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(q, sym)]) + getTypeDesc(m, sym.loc.t, dkRefParam), getModuleDllPath(q, sym)]) else: let headerDecl = "extern NIM_CONST $1 $2;$n" % - [getTypeDesc(m, sym.loc.t, skVar), sym.loc.r] + [getTypeDesc(m, sym.loc.t, dkRefParam), sym.loc.r] m.s[cfsData].add(headerDecl) if sfExportc in sym.flags and p.module.g.generatedHeader != nil: p.module.g.generatedHeader.s[cfsData].add(headerDecl) @@ -2892,7 +2892,7 @@ proc genConstDefinition(q: BModule; p: BProc; sym: PSym) = q.s[cfsData].add data if q.hcrOn: # generate the global pointer with the real name - q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(q, sym.loc.t, skVar), sym.loc.r]) + q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(q, sym.loc.t, dkRefParam), sym.loc.r]) # register it (but ignore the boolean result of hcrRegisterGlobal) q.initProc.procSec(cpsLocals).addf( "\thcrRegisterGlobal($1, \"$2\", sizeof($3), NULL, (void**)&$2);$n", diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 315af8777c..4328377fde 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1623,7 +1623,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = let le = e[0] let ri = e[1] var a: TLoc - discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar) + discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkRefParam) initLoc(a, locNone, le, OnUnknown) a.flags.incl(lfEnforceDeref) a.flags.incl(lfPrepareForMutation) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 7bd4dac81b..8c268a1adb 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -15,6 +15,24 @@ import sighashes, modulegraphs import strscans import ../dist/checksums/src/checksums/md5 +type + TypeDescKind = enum + dkParam #skParam + dkRefParam #skVar and byref (soon) + dkField #skField + dkResult #skResult + dkConst #skConst + dkOther #skType, skTemp, skLet and skForVar so far + +proc descKindFromSymKind(kind: TSymKind): TypeDescKind = + case kind + of skParam: dkParam + of skVar: dkRefParam + of skField: dkField + of skResult: dkResult + of skConst: dkConst + else: dkOther + proc isKeyword(w: PIdent): bool = # Nim and C++ share some keywords # it's more efficient to test the whole Nim keywords range @@ -140,7 +158,7 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = of 8: result = ctInt64 else: result = ctArray -proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = +proc mapType(conf: ConfigRef; typ: PType; isParam: bool): TCTypeKind = ## Maps a Nim type to a C type case typ.kind of tyNone, tyTyped: result = ctVoid @@ -149,16 +167,16 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = of tyNil: result = ctPtr of tySet: result = mapSetType(conf, typ) of tyOpenArray, tyVarargs: - if kind == skParam: result = ctArray + if isParam: result = ctArray else: result = ctStruct of tyArray, tyUncheckedArray: result = ctArray of tyObject, tyTuple: result = ctStruct of tyUserTypeClasses: doAssert typ.isResolvedUserTypeClass - return mapType(conf, typ.lastSon, kind) + return mapType(conf, typ.lastSon, isParam) of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal, tyTypeDesc, tyAlias, tySink, tyInferred, tyOwned: - result = mapType(conf, lastSon(typ), kind) + result = mapType(conf, lastSon(typ), isParam) of tyEnum: if firstOrd(conf, typ) < 0: result = ctInt32 @@ -169,7 +187,7 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = of 4: result = ctInt32 of 8: result = ctInt64 else: result = ctInt32 - of tyRange: result = mapType(conf, typ[0], kind) + of tyRange: result = mapType(conf, typ[0], isParam) of tyPtr, tyVar, tyLent, tyRef: var base = skipTypes(typ.lastSon, typedescInst) case base.kind @@ -186,14 +204,15 @@ proc mapType(conf: ConfigRef; typ: PType; kind: TSymKind): TCTypeKind = of tyInt..tyUInt64: result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) of tyStatic: - if typ.n != nil: result = mapType(conf, lastSon typ, kind) + if typ.n != nil: result = mapType(conf, lastSon typ, isParam) else: doAssert(false, "mapType: " & $typ.kind) else: doAssert(false, "mapType: " & $typ.kind) + proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind = #if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr #else: - result = mapType(conf, typ, skResult) + result = mapType(conf, typ, false) proc isImportedType(t: PType): bool = result = t.sym != nil and sfImportc in t.sym.flags @@ -206,7 +225,7 @@ proc isImportedCppType(t: PType): bool = proc isOrHasImportedCppType(typ: PType): bool = searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType) -proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TSymKind): Rope +proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDescKind): Rope proc isObjLackingTypeField(typ: PType): bool {.inline.} = result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and @@ -226,7 +245,7 @@ proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool = getSize(conf, rettype) > conf.target.floatSize*3): result = true else: - case mapType(conf, rettype, skResult) + case mapType(conf, rettype, false) of ctArray: result = not (skipTypes(rettype, typedescInst).kind in {tyVar, tyLent, tyRef, tyPtr}) @@ -358,7 +377,7 @@ proc getTypeForward(m: BModule; typ: PType; sig: SigHash): Rope = doAssert m.forwTypeCache[sig] == result else: internalError(m.config, "getTypeForward(" & $typ.kind & ')') -proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): Rope = +proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TypeDescKind): Rope = ## like getTypeDescAux but creates only a *weak* dependency. In other words ## we know we only need a pointer to it so we only generate a struct forward ## declaration: @@ -400,14 +419,14 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TSymKind): R proc getSeqPayloadType(m: BModule; t: PType): Rope = var check = initIntSet() - result = getTypeDescWeak(m, t, check, skParam) & "_Content" + result = getTypeDescWeak(m, t, check, dkParam) & "_Content" #result = getTypeForward(m, t, hashType(t)) & "_Content" proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) = let sig = hashType(t, m.config) let result = cacheGetType(m.typeCache, sig) if result == "": - discard getTypeDescAux(m, t, check, skVar) + discard getTypeDescAux(m, t, check, dkRefParam) else: # little hack for now to prevent multiple definitions of the same # Seq_Content: @@ -416,7 +435,7 @@ $3ifndef $2_Content_PP $3define $2_Content_PP struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE];}; $3endif$N - """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, skVar), result, rope"#"]) + """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, dkRefParam), result, rope"#"]) proc paramStorageLoc(param: PSym): TStorageLoc = if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin { @@ -475,9 +494,9 @@ proc genVirtualProcParams(m: BModule; t: PType, rettype, params: var string, rettype = "void" else: if rettype == "": - rettype = getTypeDescAux(m, t[0], check, skResult) + rettype = getTypeDescAux(m, t[0], check, dkResult) else: - rettype = runtimeFormat(rettype.replace("'0", "$1"), [getTypeDescAux(m, t[0], check, skResult)]) + rettype = runtimeFormat(rettype.replace("'0", "$1"), [getTypeDescAux(m, t[0], check, dkResult)]) var this = t.n[1].sym fillParamName(m, this) fillLoc(this.loc, locParam, t.n[1], @@ -487,7 +506,7 @@ proc genVirtualProcParams(m: BModule; t: PType, rettype, params: var string, else: this.loc.r = "(*this)" - var types = @[getTypeDescWeak(m, this.typ, check, skParam)] + var types = @[getTypeDescWeak(m, this.typ, check, dkParam)] var names = @[this.loc.r] for i in 2..= 0: let objDisplay = genDisplay(m, t, objDepth) let objDisplayStore = getTempName(m) - m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), skVar), objDisplayStore, rope(objDepth+1), objDisplay]) + m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), dkRefParam), objDisplayStore, rope(objDepth+1), objDisplay]) addf(typeEntry, "$1.display = $2;$n", [name, rope(objDisplayStore)]) m.s[cfsTypeInit3].add typeEntry @@ -1569,7 +1588,7 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn if objDepth >= 0: let objDisplay = genDisplay(m, t, objDepth) let objDisplayStore = getTempName(m) - m.s[cfsVars].addf("static NIM_CONST $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), skVar), objDisplayStore, rope(objDepth+1), objDisplay]) + m.s[cfsVars].addf("static NIM_CONST $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), dkRefParam), objDisplayStore, rope(objDepth+1), objDisplay]) addf(typeEntry, ", .display = $1", [rope(objDisplayStore)]) if isDefined(m.config, "nimTypeNames"): var typeName: Rope @@ -1777,6 +1796,6 @@ proc genTypeSection(m: BModule, n: PNode) = for p in 0.. 0: decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)] @@ -820,7 +820,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) = initLoc(dest, locTemp, lib.path, OnStack) dest.r = getTempName(m) appcg(m, m.s[cfsDynLibInit],"$1 $2;$n", - [getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)]) + [getTypeDesc(m, lib.path.typ, dkRefParam), rdLoc(dest)]) expr(p, lib.path, dest) m.s[cfsVars].add(p.s(cpsLocals)) @@ -860,7 +860,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) = params.add(rdLoc(a)) params.add(", ") let load = "\t$1 = ($2) ($3$4));$n" % - [tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)] + [tmp, getTypeDesc(m, sym.typ, dkRefParam), params, makeCString($extname)] var last = lastSon(n) if last.kind == nkHiddenStdConv: last = last[1] internalAssert(m.config, last.kind == nkStrLit) @@ -874,8 +874,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) = else: appcg(m, m.s[cfsDynLibInit], "\t$1 = ($2) #nimGetProcAddr($3, $4);$n", - [tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)]) - m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)]) + [tmp, getTypeDesc(m, sym.typ, dkRefParam), lib.name, makeCString($extname)]) + m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, dkRefParam)]) proc varInDynamicLib(m: BModule, sym: PSym) = var lib = sym.annex @@ -887,9 +887,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) = inc(m.labels, 2) appcg(m, m.s[cfsDynLibInit], "$1 = ($2*) #nimGetProcAddr($3, $4);$n", - [tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)]) + [tmp, getTypeDesc(m, sym.typ, dkRefParam), lib.name, makeCString($extname)]) m.s[cfsVars].addf("$2* $1;$n", - [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)]) + [sym.loc.r, getTypeDesc(m, sym.loc.t, dkRefParam)]) proc symInDynamicLibPartial(m: BModule, sym: PSym) = sym.loc.r = mangleDynLibProc(sym) @@ -1375,7 +1375,7 @@ proc genVarPrototype(m: BModule, n: PNode) = if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0: m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)] m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ") - m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, skVar)) + m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, dkRefParam)) if m.hcrOn: m.s[cfsVars].add("*") if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*") if sfRegister in sym.flags: m.s[cfsVars].add(" register") @@ -1384,7 +1384,7 @@ proc genVarPrototype(m: BModule, n: PNode) = m.s[cfsVars].addf(" $1;$n", [sym.loc.r]) if m.hcrOn: m.initProc.procSec(cpsLocals).addf( "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, - getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(m, sym)]) + getTypeDesc(m, sym.loc.t, dkRefParam), getModuleDllPath(m, sym)]) proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} = result.addf("#define NIM_INTBITS $1\L", [ @@ -1779,10 +1779,10 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R prc.typ.sym = nil if not containsOrIncl(m.declaredThings, prc.id): - m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, skVar)]) + m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, dkRefParam)]) result = "\t$1 = ($2) $3($4, $5);$n" % - [tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] + [tmp, getTypeDesc(m, prc.typ, dkRefParam), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] proc genInitCode(m: BModule) = ## this function is called in cgenWriteModules after all modules are closed, From 641e34bcb2acf8e289c5be67f5fb1164cb6be80a Mon Sep 17 00:00:00 2001 From: metagn Date: Sat, 20 May 2023 22:09:16 +0300 Subject: [PATCH 105/489] fix #14254 (#21837) * fix #14254 * use temporary PR branch for neo * fix url --- compiler/semexprs.nim | 4 +++- compiler/semgnrc.nim | 8 ++++++-- testament/important_packages.nim | 3 ++- tests/generics/mdotlookup.nim | 4 ++++ tests/generics/timports.nim | 2 ++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 4dd7840f14..b79abadff4 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1522,7 +1522,9 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode = flags.incl efCannotBeDotCall proc dotTransformation(c: PContext, n: PNode): PNode = - if isSymChoice(n[1]): + if isSymChoice(n[1]) or + # generics usually leave field names as symchoices, but not types + (n[1].kind == nkSym and n[1].sym.kind == skType): result = newNodeI(nkDotCall, n.info) result.add n[1] result.add copyTree(n[0]) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 01146bb7c1..7dec8a30df 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -152,12 +152,16 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, result = n let n = n[1] let ident = considerQuotedIdent(c, n) - var candidates = searchInScopesFilterBy(c, ident, routineKinds) + var candidates = searchInScopesFilterBy(c, ident, routineKinds+{skType}) + # skType here because could be type conversion if candidates.len > 0: let s = candidates[0] # XXX take into account the other candidates! isMacro = s.kind in {skTemplate, skMacro} if withinBind in flags or s.id in ctx.toBind: - result = newDot(result, symChoice(c, n, s, scClosed)) + if s.kind == skType: # don't put types in sym choice + result = newDot(result, semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true)) + else: + result = newDot(result, symChoice(c, n, s, scClosed)) elif s.isMixedIn: result = newDot(result, symChoice(c, n, s, scForceOpen)) else: diff --git a/testament/important_packages.nim b/testament/important_packages.nim index d5a3ba97b5..4c93189f1c 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -93,7 +93,8 @@ pkg "measuremancer", "nimble testDeps; nimble -y test" pkg "memo" pkg "msgpack4nim", "nim c -r tests/test_spec.nim" pkg "nake", "nim c nakefile.nim" -pkg "neo", "nim c -d:blas=openblas --mm:refc tests/all.nim" +pkg "neo", "nim c -d:blas=openblas --mm:refc tests/all.nim", "https://github.com/metagn/neo" +# remove custom url when https://github.com/andreaferretti/neo/pull/53 is merged pkg "nesm", "nimble tests", "https://github.com/nim-lang/NESM", useHead = true pkg "netty" pkg "nico", allowFailure = true diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim index b69a56dafd..215f75003e 100644 --- a/tests/generics/mdotlookup.nim +++ b/tests/generics/mdotlookup.nim @@ -19,3 +19,7 @@ import strutils proc doStrip*[T](a: T): string = result = ($a).strip() + +type Foo = int32 +proc baz2*[T](y: int): auto = + result = y.Foo diff --git a/tests/generics/timports.nim b/tests/generics/timports.nim index b619c48cf6..df830c1f0e 100644 --- a/tests/generics/timports.nim +++ b/tests/generics/timports.nim @@ -38,6 +38,8 @@ block tdotlookup: # bug #1444 fn(4) doAssert doStrip(123) == "123" + # bug #14254 + doAssert baz2[float](1'i8) == 1 block tmodule_same_as_proc: # bug #1965 From fcf2dcf099c4be7e2e7422d21728c220fbb034bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Sat, 20 May 2023 22:52:21 +0100 Subject: [PATCH 106/489] Moves virtual under its own section manual_experimental.md (#21870) --- doc/manual_experimental.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 6e11e03eac..25c9c1b552 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -2132,7 +2132,7 @@ The `.sendable` pragma itself is an experimenal, unchecked, unsafe annotation. I currently only used by `Isolated[T]`. Virtual pragma ----------------- +============== `virtual` is designed to extend or create virtual functions when targeting the cpp backend. When a proc is marked with virtual, it forward declares the proc header within the type's body. @@ -2205,4 +2205,4 @@ NimPrinter().printConst(message) var val: int32 = 10 NimPrinter().printConstRef(message, val) -``` \ No newline at end of file +``` From 016aa1d98cfa0ef535d2c56e82f194ac33b3bf4e Mon Sep 17 00:00:00 2001 From: metagn Date: Sun, 21 May 2023 01:13:30 +0300 Subject: [PATCH 107/489] remove legacy define for zero_functional tests (#21871) test remove legacy define for zero_functional tests --- testament/important_packages.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 4c93189f1c..e2d1024b12 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -171,5 +171,5 @@ pkg "winim", "nim c winim.nim" pkg "with" pkg "ws", allowFailure = true pkg "yaml", "nim c -r test/tserialization.nim" -pkg "zero_functional", "nim c -r -d:nimNoLentIterators test.nim" +pkg "zero_functional", "nim c -r test.nim" pkg "zippy" From 44f059c75ee6db2278c671e3da18eb9af390b937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Sat, 20 May 2023 23:19:09 +0100 Subject: [PATCH 108/489] implements allow byref to work in params #21873 (#21875) --- compiler/ccgcalls.nim | 3 ++- compiler/ccgexprs.nim | 14 ++++++------ compiler/ccgstmts.nim | 2 +- compiler/ccgtypes.nim | 51 +++++++++++++++++++++++++----------------- compiler/ccgutils.nim | 3 ++- compiler/cgen.nim | 30 ++++++++++++------------- compiler/pragmas.nim | 6 +++-- tests/cpp/tvirtual.nim | 19 +++++++++++----- 8 files changed, 76 insertions(+), 52 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index b55c89c1dc..dcada5d7c2 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -292,7 +292,8 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: var n = if n.kind != nkHiddenAddr: n else: n[0] openArrayLoc(p, param.typ, n, result) - elif ccgIntroducedPtr(p.config, param, call[0].typ[0]): + elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and + (optByRef notin param.options or not p.module.compileToCpp): initLocExpr(p, n, a) if n.kind in {nkCharLit..nkNilLit}: addAddrLoc(p.config, literalsNeedsTmp(p, a), result) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index d27535546e..fe776e8d30 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2510,10 +2510,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mNewSeqOfCap: genNewSeqOfCap(p, e, d) of mSizeOf: let t = e[1].typ.skipTypes({tyTypeDesc}) - putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, dkRefParam)]) + putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, dkVar)]) of mAlignOf: let t = e[1].typ.skipTypes({tyTypeDesc}) - putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, dkRefParam)]) + putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, dkVar)]) of mOffsetOf: var dotExpr: PNode if e[1].kind == nkDotExpr: @@ -2523,7 +2523,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: internalError(p.config, e.info, "unknown ast") let t = dotExpr[0].typ.skipTypes({tyTypeDesc}) - let tname = getTypeDesc(p.module, t, dkRefParam) + let tname = getTypeDesc(p.module, t, dkVar) let member = if t.kind == tyTuple: "Field" & rope(dotExpr[1].sym.position) @@ -2870,13 +2870,13 @@ proc genConstHeader(m, q: BModule; p: BProc, sym: PSym) = if not genConstSetup(p, sym): return assert(sym.loc.r != "", $sym.name.s & $sym.itemId) if m.hcrOn: - m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, dkRefParam), sym.loc.r]); + m.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(m, sym.loc.t, dkVar), sym.loc.r]); m.initProc.procSec(cpsLocals).addf( "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, - getTypeDesc(m, sym.loc.t, dkRefParam), getModuleDllPath(q, sym)]) + getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(q, sym)]) else: let headerDecl = "extern NIM_CONST $1 $2;$n" % - [getTypeDesc(m, sym.loc.t, dkRefParam), sym.loc.r] + [getTypeDesc(m, sym.loc.t, dkVar), sym.loc.r] m.s[cfsData].add(headerDecl) if sfExportc in sym.flags and p.module.g.generatedHeader != nil: p.module.g.generatedHeader.s[cfsData].add(headerDecl) @@ -2892,7 +2892,7 @@ proc genConstDefinition(q: BModule; p: BProc; sym: PSym) = q.s[cfsData].add data if q.hcrOn: # generate the global pointer with the real name - q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(q, sym.loc.t, dkRefParam), sym.loc.r]) + q.s[cfsVars].addf("static $1* $2;$n", [getTypeDesc(q, sym.loc.t, dkVar), sym.loc.r]) # register it (but ignore the boolean result of hcrRegisterGlobal) q.initProc.procSec(cpsLocals).addf( "\thcrRegisterGlobal($1, \"$2\", sizeof($3), NULL, (void**)&$2);$n", diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 4328377fde..b57864b466 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1623,7 +1623,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = let le = e[0] let ri = e[1] var a: TLoc - discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkRefParam) + discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar) initLoc(a, locNone, le, OnUnknown) a.flags.incl(lfEnforceDeref) a.flags.incl(lfPrepareForMutation) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 8c268a1adb..33b0d92d3b 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -18,7 +18,8 @@ import ../dist/checksums/src/checksums/md5 type TypeDescKind = enum dkParam #skParam - dkRefParam #skVar and byref (soon) + dkRefParam #param passed by ref when {.byref.} is used. Cpp only. C goes straight to dkParam and is handled as a regular pointer + dkVar #skVar dkField #skField dkResult #skResult dkConst #skConst @@ -27,7 +28,7 @@ type proc descKindFromSymKind(kind: TSymKind): TypeDescKind = case kind of skParam: dkParam - of skVar: dkRefParam + of skVar: dkVar of skField: dkField of skResult: dkResult of skConst: dkConst @@ -426,7 +427,7 @@ proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) = let sig = hashType(t, m.config) let result = cacheGetType(m.typeCache, sig) if result == "": - discard getTypeDescAux(m, t, check, dkRefParam) + discard getTypeDescAux(m, t, check, dkVar) else: # little hack for now to prevent multiple definitions of the same # Seq_Content: @@ -435,7 +436,7 @@ $3ifndef $2_Content_PP $3define $2_Content_PP struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE];}; $3endif$N - """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, dkRefParam), result, rope"#"]) + """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, dkVar), result, rope"#"]) proc paramStorageLoc(param: PSym): TStorageLoc = if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin { @@ -512,18 +513,21 @@ proc genVirtualProcParams(m: BModule; t: PType, rettype, params: var string, for i in 2..= 0: let objDisplay = genDisplay(m, t, objDepth) let objDisplayStore = getTempName(m) - m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), dkRefParam), objDisplayStore, rope(objDepth+1), objDisplay]) + m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), dkVar), objDisplayStore, rope(objDepth+1), objDisplay]) addf(typeEntry, "$1.display = $2;$n", [name, rope(objDisplayStore)]) m.s[cfsTypeInit3].add typeEntry @@ -1588,7 +1599,7 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn if objDepth >= 0: let objDisplay = genDisplay(m, t, objDepth) let objDisplayStore = getTempName(m) - m.s[cfsVars].addf("static NIM_CONST $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), dkRefParam), objDisplayStore, rope(objDepth+1), objDisplay]) + m.s[cfsVars].addf("static NIM_CONST $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), dkVar), objDisplayStore, rope(objDepth+1), objDisplay]) addf(typeEntry, ", .display = $1", [rope(objDisplayStore)]) if isDefined(m.config, "nimTypeNames"): var typeName: Rope diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index d86ebe4610..d9aa58c675 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -121,7 +121,8 @@ proc mapSetType(conf: ConfigRef; typ: PType): TCTypeKind = proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool = var pt = skipTypes(s.typ, typedescInst) assert skResult != s.kind - + + if optByRef in s.options: return true if tfByRef in pt.flags: return true elif tfByCopy in pt.flags: return false case pt.kind diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 42356730ed..0e6e02c7a4 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -547,9 +547,9 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = inc(p.labels) result.r = "T" & rope(p.labels) & "_" if p.module.compileToCpp and isOrHasImportedCppType(t): - linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, dkRefParam), result.r]) + linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, dkVar), result.r]) else: - linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkRefParam), result.r]) + linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r]) result.k = locTemp result.lode = lodeTyp t result.storage = OnStack @@ -567,7 +567,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) = inc(p.labels) result.r = "T" & rope(p.labels) & "_" - linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkRefParam), result.r, value]) + linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value]) result.k = locTemp result.lode = lodeTyp t result.storage = OnStack @@ -593,7 +593,7 @@ proc localVarDecl(p: BProc; n: PNode): Rope = genCLineDir(result, p, n.info, p.config) - result.add getTypeDesc(p.module, s.typ, dkRefParam) + result.add getTypeDesc(p.module, s.typ, dkVar) if s.constraint.isNil: if sfRegister in s.flags: result.add(" register") #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: @@ -648,7 +648,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = internalError(p.config, n.info, ".threadvar variables cannot have a value") else: var decl: Rope = "" - var td = getTypeDesc(p.module, s.loc.t, dkRefParam) + var td = getTypeDesc(p.module, s.loc.t, dkVar) if s.constraint.isNil: if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)] @@ -820,7 +820,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) = initLoc(dest, locTemp, lib.path, OnStack) dest.r = getTempName(m) appcg(m, m.s[cfsDynLibInit],"$1 $2;$n", - [getTypeDesc(m, lib.path.typ, dkRefParam), rdLoc(dest)]) + [getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)]) expr(p, lib.path, dest) m.s[cfsVars].add(p.s(cpsLocals)) @@ -860,7 +860,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) = params.add(rdLoc(a)) params.add(", ") let load = "\t$1 = ($2) ($3$4));$n" % - [tmp, getTypeDesc(m, sym.typ, dkRefParam), params, makeCString($extname)] + [tmp, getTypeDesc(m, sym.typ, dkVar), params, makeCString($extname)] var last = lastSon(n) if last.kind == nkHiddenStdConv: last = last[1] internalAssert(m.config, last.kind == nkStrLit) @@ -874,8 +874,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) = else: appcg(m, m.s[cfsDynLibInit], "\t$1 = ($2) #nimGetProcAddr($3, $4);$n", - [tmp, getTypeDesc(m, sym.typ, dkRefParam), lib.name, makeCString($extname)]) - m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, dkRefParam)]) + [tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)]) + m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)]) proc varInDynamicLib(m: BModule, sym: PSym) = var lib = sym.annex @@ -887,9 +887,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) = inc(m.labels, 2) appcg(m, m.s[cfsDynLibInit], "$1 = ($2*) #nimGetProcAddr($3, $4);$n", - [tmp, getTypeDesc(m, sym.typ, dkRefParam), lib.name, makeCString($extname)]) + [tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)]) m.s[cfsVars].addf("$2* $1;$n", - [sym.loc.r, getTypeDesc(m, sym.loc.t, dkRefParam)]) + [sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)]) proc symInDynamicLibPartial(m: BModule, sym: PSym) = sym.loc.r = mangleDynLibProc(sym) @@ -1375,7 +1375,7 @@ proc genVarPrototype(m: BModule, n: PNode) = if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0: m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)] m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ") - m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, dkRefParam)) + m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, dkVar)) if m.hcrOn: m.s[cfsVars].add("*") if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*") if sfRegister in sym.flags: m.s[cfsVars].add(" register") @@ -1384,7 +1384,7 @@ proc genVarPrototype(m: BModule, n: PNode) = m.s[cfsVars].addf(" $1;$n", [sym.loc.r]) if m.hcrOn: m.initProc.procSec(cpsLocals).addf( "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, - getTypeDesc(m, sym.loc.t, dkRefParam), getModuleDllPath(m, sym)]) + getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(m, sym)]) proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} = result.addf("#define NIM_INTBITS $1\L", [ @@ -1779,10 +1779,10 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R prc.typ.sym = nil if not containsOrIncl(m.declaredThings, prc.id): - m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, dkRefParam)]) + m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, dkVar)]) result = "\t$1 = ($2) $3($4, $5);$n" % - [tmp, getTypeDesc(m, prc.typ, dkRefParam), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] + [tmp, getTypeDesc(m, prc.typ, dkVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)] proc genInitCode(m: BModule) = ## this function is called in cgenWriteModules after all modules are closed, diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index be8e83d25d..bc375b1bc9 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -84,7 +84,7 @@ const wGensym, wInject, wIntDefine, wStrDefine, wBoolDefine, wDefine, wCompilerProc, wCore} - paramPragmas* = {wNoalias, wInject, wGensym} + paramPragmas* = {wNoalias, wInject, wGensym, wByRef} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect, wThread, wRaises, wEffectsOf, wLocks, wTags, wForbids, wGcSafe, @@ -1196,7 +1196,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, invalidPragma(c, it) of wByRef: noVal(c, it) - if sym == nil or sym.typ == nil: + if sym != nil and sym.kind == skParam: + sym.options.incl optByRef + elif sym == nil or sym.typ == nil: processOption(c, it, c.config.options) else: incl(sym.typ.flags, tfByRef) diff --git a/tests/cpp/tvirtual.nim b/tests/cpp/tvirtual.nim index d7dd6a7c43..0488ce07de 100644 --- a/tests/cpp/tvirtual.nim +++ b/tests/cpp/tvirtual.nim @@ -8,6 +8,7 @@ hello boo Const Message: hello world NimPrinter: hello world NimPrinterConstRef: hello world +NimPrinterConstRefByRef: hello world ''' """ @@ -22,6 +23,10 @@ NimPrinterConstRef: hello world virtual void printConstRef(char* message, const int& flag) const { std::cout << "Const Ref Message: " << message << std::endl; } + virtual void printConstRef2(char* message, const int& flag) const { + std::cout << "Const Ref2 Message: " << message << std::endl; + } + }; """.} @@ -34,10 +39,10 @@ type CppPrinter {.importcpp, inheritable.} = object NimPrinter {.exportc.} = object of CppPrinter -proc salute(self:FooPtr) {.virtual.} = +proc salute(self: FooPtr) {.virtual.} = echo "hello foo" -proc salute(self:BooPtr) {.virtual.} = +proc salute(self: BooPtr) {.virtual.} = echo "hello boo" let foo = newCpp[Foo]() @@ -50,19 +55,23 @@ boo.salute() booAsFoo.salute() let message = "hello world".cstring -proc printConst(self:CppPrinter, message:cstring) {.importcpp.} +proc printConst(self: CppPrinter, message: cstring) {.importcpp.} CppPrinter().printConst(message) #notice override is optional. #Will make the cpp compiler to fail if not virtual function with the same signature if found in the base type -proc printConst(self:NimPrinter, message:cstring) {.virtual:"$1('2 #2) const override".} = +proc printConst(self: NimPrinter, message: cstring) {.virtual:"$1('2 #2) const override".} = echo "NimPrinter: " & $message -proc printConstRef(self:NimPrinter, message:cstring, flag:int32) {.virtual:"$1('2 #2, const '3& #3 ) const override".} = +proc printConstRef(self: NimPrinter, message: cstring, flag: int32) {.virtual:"$1('2 #2, const '3& #3 ) const override".} = echo "NimPrinterConstRef: " & $message +proc printConstRef2(self: NimPrinter, message: cstring, flag {.byref.}: int32) {.virtual:"$1('2 #2, const '3 #3 ) const override".} = + echo "NimPrinterConstRefByRef: " & $message + NimPrinter().printConst(message) var val : int32 = 10 NimPrinter().printConstRef(message, val) +NimPrinter().printConstRef2(message, val) From 5606702e6d9aa583141c975f45534d0f55d9acc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Sun, 21 May 2023 03:44:43 +0100 Subject: [PATCH 109/489] implements: "Allow bycopy to work in params #21874" (#21877) * implements: "Allow bycopy to work in params #21874" * Update compiler/pragmas.nim --------- Co-authored-by: Andreas Rumpf --- compiler/ast.nim | 3 ++- compiler/ccgutils.nim | 4 +++- compiler/pragmas.nim | 6 ++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 7e92cd140b..da9b3898e9 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -231,7 +231,7 @@ type TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # 50 flags! + TSymFlag* = enum # 51 flags! sfUsed, # read access of sym (for warnings) or simply used sfExported, # symbol is exported from module sfFromGeneric, # symbol is instantiation of a generic; this is needed @@ -313,6 +313,7 @@ type # This is disallowed but can cause the typechecking to go into # an infinite loop, this flag is used as a sentinel to stop it. sfVirtual # proc is a C++ virtual function + sfByCopy # param is marked as pass bycopy TSymFlags* = set[TSymFlag] diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index d9aa58c675..ea4f3fe18b 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -122,8 +122,10 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool = var pt = skipTypes(s.typ, typedescInst) assert skResult != s.kind + #note precedence: params override types if optByRef in s.options: return true - if tfByRef in pt.flags: return true + elif sfByCopy in s.flags: return false + elif tfByRef in pt.flags: return true elif tfByCopy in pt.flags: return false case pt.kind of tyObject: diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index bc375b1bc9..11305db2a3 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -84,7 +84,7 @@ const wGensym, wInject, wIntDefine, wStrDefine, wBoolDefine, wDefine, wCompilerProc, wCore} - paramPragmas* = {wNoalias, wInject, wGensym, wByRef} + paramPragmas* = {wNoalias, wInject, wGensym, wByRef, wByCopy} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect, wThread, wRaises, wEffectsOf, wLocks, wTags, wForbids, wGcSafe, @@ -1204,7 +1204,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, incl(sym.typ.flags, tfByRef) of wByCopy: noVal(c, it) - if sym.kind != skType or sym.typ == nil: invalidPragma(c, it) + if sym.kind == skParam: + incl(sym.flags, sfByCopy) + elif sym.kind != skType or sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfByCopy) of wPartial: noVal(c, it) From 28a116a47701462a5f22e0fa496a91daff2c1816 Mon Sep 17 00:00:00 2001 From: Jason Beetham Date: Sun, 21 May 2023 12:10:32 -0600 Subject: [PATCH 110/489] Fixed generic parameters failing to be used in inheritance (#21866) --- compiler/semtypes.nim | 35 ++++++++++++++------- tests/types/tinheritgenericparameter.nim | 39 ++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 tests/types/tinheritgenericparameter.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index f4b284f7e1..fc59b6f916 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -854,12 +854,18 @@ proc skipGenericInvocation(t: PType): PType {.inline.} = while result.kind in {tyGenericInst, tyGenericBody, tyRef, tyPtr, tyAlias, tySink, tyOwned}: result = lastSon(result) -proc addInheritedFields(c: PContext, check: var IntSet, pos: var int, - obj: PType) = - assert obj.kind == tyObject - if (obj.len > 0) and (obj[0] != nil): - addInheritedFields(c, check, pos, obj[0].skipGenericInvocation) - addInheritedFieldsAux(c, check, pos, obj.n) +proc tryAddInheritedFields(c: PContext, check: var IntSet, pos: var int, + obj: PType, n: PNode, isPartial = false): bool = + if (not isPartial) and (obj.kind notin {tyObject, tyGenericParam} or tfFinal in obj.flags): + localError(c.config, n.info, "Cannot inherit from: '" & $obj & "'") + result = false + elif obj.kind == tyObject: + result = true + if (obj.len > 0) and (obj[0] != nil): + result = result and tryAddInheritedFields(c, check, pos, obj[0].skipGenericInvocation, n) + addInheritedFieldsAux(c, check, pos, obj.n) + else: + result = true proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType = if n.len == 0: @@ -886,7 +892,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType if concreteBase.sym != nil and concreteBase.sym.magic == mException and sfSystemModule notin c.module.flags: message(c.config, n.info, warnInheritFromException, "") - addInheritedFields(c, check, pos, concreteBase) + if not tryAddInheritedFields(c, check, pos, concreteBase, n): + return newType(tyError, nextTypeId c.idgen, result.owner) + else: if concreteBase.kind != tyError: localError(c.config, n[1].info, "inheritance only works with non-final objects; " & @@ -904,7 +912,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType; flags: TTypeFlags): PType result.n = newNodeI(nkRecList, n.info) else: # partial object so add things to the check - addInheritedFields(c, check, pos, result) + if not tryAddInheritedFields(c, check, pos, result, n, isPartial = true): + return newType(tyError, nextTypeId c.idgen, result.owner) + semRecordNodeAux(c, n[2], check, pos, result.n, result) if n[0].kind != nkEmpty: # dummy symbol for `pragma`: @@ -1435,19 +1445,21 @@ proc semGenericParamInInvocation(c: PContext, n: PNode): PType = result = semTypeNode(c, n, nil) n.typ = makeTypeDesc(c, result) -proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) = +proc trySemObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType): bool = var check = initIntSet() pos = 0 let realBase = t[0] base = skipTypesOrNil(realBase, skipPtrs) + result = true if base.isNil: localError(c.config, n.info, errIllegalRecursionInTypeX % "object") else: let concreteBase = skipGenericInvocation(base) if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: - addInheritedFields(c, check, pos, concreteBase) + if not tryAddInheritedFields(c, check, pos, concreteBase, n): + return false else: if concreteBase.kind != tyError: localError(c.config, n.info, errInheritanceOnlyWithNonFinalObjects) @@ -1527,7 +1539,8 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = return errorType(c) if tx != result and tx.kind == tyObject: if tx[0] != nil: - semObjectTypeForInheritedGenericInst(c, n, tx) + if not trySemObjectTypeForInheritedGenericInst(c, n, tx): + return newOrPrevType(tyError, prev, c) var position = 0 recomputeFieldPositions(tx, tx.n, position) diff --git a/tests/types/tinheritgenericparameter.nim b/tests/types/tinheritgenericparameter.nim new file mode 100644 index 0000000000..c88c50b7b2 --- /dev/null +++ b/tests/types/tinheritgenericparameter.nim @@ -0,0 +1,39 @@ +discard """ + cmd: "nim check --hints:off --warnings:off $file" + action: "reject" + nimout:''' +tinheritgenericparameter.nim(36, 15) Error: Cannot inherit from: 'MyObject' +tinheritgenericparameter.nim(36, 15) Error: Cannot inherit from: 'MyObject' +tinheritgenericparameter.nim(36, 23) Error: object constructor needs an object type [proxy] +tinheritgenericparameter.nim(36, 23) Error: expression '' has no type (or is ambiguous) +tinheritgenericparameter.nim(37, 15) Error: Cannot inherit from: 'int' +tinheritgenericparameter.nim(37, 15) Error: Cannot inherit from: 'int' +tinheritgenericparameter.nim(37, 23) Error: object constructor needs an object type [proxy] +tinheritgenericparameter.nim(37, 23) Error: expression '' has no type (or is ambiguous) +''' +""" + +type + MyObject = object + HorzLayout[Base, T] = ref object of Base + data: seq[T] + VertLayout[T, Base] = ref object of Base + data: seq[T] + UiElement = ref object of RootObj + a: int + MyType[T] = ref object of RootObj + data: seq[T] + OtherElement[T] = ref object of T + Child[T] = ref object of HorzLayout[UiElement, T] + Child2[T] = ref object of VertLayout[T, UiElement] + Child3[T] = ref object of HorzLayout[MyObject, T] + Child4[T] = ref object of HorzLayout[int, T] +static: + var a = Child[int](a: 300, data: @[100, 200, 300]) + assert a.a == 300 + assert a.data == @[100, 200, 300] +discard Child2[string]() +discard Child3[string]() +discard Child4[string]() +discard OtherElement[MyType[int]]() + From 9c2d2773ec3184aa73e811af38d6f5c5f0bb79d4 Mon Sep 17 00:00:00 2001 From: Carlo Capocasa Date: Sun, 21 May 2023 20:12:05 +0200 Subject: [PATCH 111/489] Weekday parse/format (replacement) (#21857) * parsing capability for iso week year * remove outdated test --- lib/pure/times.nim | 140 ++++++++++++++++++++++++++-------- tests/stdlib/ttimes.nim | 24 ++++++ tests/system/tuse_version.nim | 49 ------------ 3 files changed, 134 insertions(+), 79 deletions(-) delete mode 100644 tests/system/tuse_version.nim diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 3d644d3611..ae101bc343 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -62,6 +62,8 @@ | `Monday -> Mon` `dddd` Full string for the day of the week. | `Saturday -> Saturday` | `Monday -> Monday` + `GG` The last two digits of the Iso Week-Year | `30/12/2012 -> 13` + `GGGG` The Iso week-calendar year padded to four digits | `30/12/2012 -> 2013` `h` The hours in one digit if possible. Ranging from 1-12. | `5pm -> 5` | `2am -> 2` `hh` The hours in two digits always. If the hour is one digit, 0 is prepended. | `5pm -> 05` @@ -104,6 +106,10 @@ | `24 AD -> 24` | `24 BC -> -23` | `12345 AD -> 12345` + `V` The Iso Week-Number as one or two digits | `3/2/2012 -> 5` + | `1/4/2012 -> 13` + `VV` The Iso Week-Number as two digits always. 0 is prepended if one digit. | `3/2/2012 -> 05` + | `1/4/2012 -> 13` `z` Displays the timezone offset from UTC. | `UTC+7 -> +7` | `UTC-5 -> -5` `zz` Same as above but with leading 0. | `UTC+7 -> +07` @@ -1507,6 +1513,33 @@ proc getClockStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect]. result = intToStr(dt.hour, 2) & ':' & intToStr(dt.minute, 2) & ':' & intToStr(dt.second, 2) +# +# Iso week +# + +proc initDateTime*(weekday: WeekDay, isoweek: IsoWeekRange, isoyear: IsoYear, + hour: HourRange, minute: MinuteRange, second: SecondRange, + nanosecond: NanosecondRange, + zone: Timezone = local()): DateTime {.since: (1, 5).} = + ## Create a new `DateTime <#DateTime>`_ from a weekday and an ISO 8601 week number and year + ## in the specified timezone. + ## + ## .. warning:: The ISO week-based year can correspond to the following or previous year from 29 December to January 3. + runnableExamples: + assert initDateTime(21, mApr, 2018, 00, 00, 00) == initDateTime(dSat, 16, 2018.IsoYear, 00, 00, 00) + assert initDateTime(30, mDec, 2019, 00, 00, 00) == initDateTime(dMon, 01, 2020.IsoYear, 00, 00, 00) + assert initDateTime(13, mSep, 2020, 00, 00, 00) == initDateTime(dSun, 37, 2020.IsoYear, 00, 00, 00) + assert initDateTime(2, mJan, 2021, 00, 00, 00) == initDateTime(dSat, 53, 2020.IsoYear, 00, 00, 00) + + # source https://webspace.science.uu.nl/~gent0113/calendar/isocalendar.htm + let d = isoweek * 7 + weekday.int - initDateTime(4, mJan, isoyear.int, 00, 00, 00).weekday.int - 4 + initDateTime(1, mJan, isoyear.int, hour, minute, second, nanosecond, zone) + initDuration(days=d) + +proc initDateTime*(weekday: WeekDay, isoweek: IsoWeekRange, isoyear: IsoYear, + hour: HourRange, minute: MinuteRange, second: SecondRange, + zone: Timezone = local()): DateTime {.since: (1, 5).} = + initDateTime(weekday, isoweek, isoyear, hour, minute, second, 0, zone) + # # TimeFormat # @@ -1537,6 +1570,9 @@ type year: Option[int] month: Option[int] monthday: Option[int] + isoyear: Option[int] + yearweek: Option[int] + weekday: Option[WeekDay] utcOffset: Option[int] # '0' as default for these work fine @@ -1551,6 +1587,7 @@ type FormatPattern {.pure.} = enum d, dd, ddd, dddd + GG, GGGG h, hh, H, HH m, mm, M, MM, MMM, MMMM s, ss @@ -1560,6 +1597,7 @@ type YYYY uuuu UUUU + V, VV z, zz, zzz, zzzz ZZZ, ZZZZ g @@ -1688,6 +1726,8 @@ proc stringToPattern(str: string): FormatPattern = of "dd": result = dd of "ddd": result = ddd of "dddd": result = dddd + of "GG": result = GG + of "GGGG": result = GGGG of "h": result = h of "hh": result = hh of "H": result = H @@ -1710,6 +1750,8 @@ proc stringToPattern(str: string): FormatPattern = of "YYYY": result = YYYY of "uuuu": result = uuuu of "UUUU": result = UUUU + of "V": result = V + of "VV": result = VV of "z": result = z of "zz": result = zz of "zzz": result = zzz @@ -1759,6 +1801,10 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string, result.add loc.ddd[dt.weekday] of dddd: result.add loc.dddd[dt.weekday] + of GG: + result.add (dt.getIsoWeekAndYear.isoyear.int mod 100).intToStr(2) + of GGGG: + result.add $dt.getIsoWeekAndYear.isoyear of h: result.add( if dt.hour == 0: "12" @@ -1822,6 +1868,10 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string, result.add '+' & $year of UUUU: result.add $dt.year + of V: + result.add $dt.getIsoWeekAndYear.isoweek + of VV: + result.add dt.getIsoWeekAndYear.isoweek.intToStr(2) of z, zz, zzz, zzzz, ZZZ, ZZZZ: if dt.timezone != nil and dt.timezone.name == "Etc/UTC": result.add 'Z' @@ -1876,18 +1926,30 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int, result = monthday in MonthdayRange of ddd: result = false - for v in loc.ddd: + for d, v in loc.ddd: if input.substr(i, i+v.len-1).cmpIgnoreCase(v) == 0: + parsed.weekday = some(d.WeekDay) result = true i.inc v.len break of dddd: result = false - for v in loc.dddd: + for d, v in loc.dddd: if input.substr(i, i+v.len-1).cmpIgnoreCase(v) == 0: + parsed.weekday = some(d.WeekDay) result = true i.inc v.len break + of GG: + # Assumes current century + var isoyear = takeInt(2..2) + var thisCen = now().year div 100 + parsed.isoyear = some(thisCen*100 + isoyear) + result = isoyear > 0 + of GGGG: + let isoyear = takeInt(1..high(int)) + parsed.isoyear = some(isoyear) + result = isoyear > 0 of h, H: parsed.hour = takeInt(1..2) result = parsed.hour in HourRange @@ -1978,6 +2040,14 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int, parsed.year = some(year) of UUUU: parsed.year = some(takeInt(1..high(int), allowSign = true)) + of V: + let yearweek = takeInt(1..2) + parsed.yearweek = some(yearweek) + result = yearweek in IsoWeekRange + of VV: + let yearweek = takeInt(2..2) + parsed.yearweek = some(yearweek) + result = yearweek in IsoWeekRange of z, zz, zzz, zzzz, ZZZ, ZZZZ: case input[i] of '+', '-': @@ -2079,6 +2149,38 @@ proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat, result = (dateTime(year, month, monthday, hour, minute, second, nanosecond, utc()).toTime + initDuration(seconds = p.utcOffset.get())).inZone(zone) +proc toDateTimeByWeek(p: ParsedTime, zone: Timezone, f: TimeFormat, + input: string): DateTime = + var isoyear = p.isoyear.get(0) + var yearweek = p.yearweek.get(1) + var weekday = p.weekday.get(dMon) + + if p.amPm != apUnknown: + raiseParseException(f, input, "Parsing iso weekyear dates does not support am/pm") + + if p.year.isSome: + raiseParseException(f, input, "Use iso-year GG or GGGG as year with iso week number") + + if p.month.isSome: + raiseParseException(f, input, "Use either iso week number V or VV or month") + + if p.monthday.isSome: + raiseParseException(f, input, "Use weekday ddd or dddd as day with with iso week number") + + if p.isoyear.isNone: + raiseParseException(f, input, "Need iso-year with week number") + + let hour = p.hour + let minute = p.minute + let second = p.second + let nanosecond = p.nanosecond + + if p.utcOffset.isNone: + result = initDateTime(weekday, yearweek.IsoWeekRange, isoyear.IsoYear, hour, minute, second, nanosecond, zone) + else: + result = (initDateTime(weekday, yearweek.IsoWeekRange, isoyear.IsoYear, hour, minute, second, nanosecond, zone).toTime + + initDuration(seconds = p.utcOffset.get())).inZone(zone) + proc format*(dt: DateTime, f: TimeFormat, loc: DateTimeLocale = DefaultLocale): string {.raises: [].} = ## Format `dt` using the format specified by `f`. @@ -2184,7 +2286,12 @@ proc parse*(input: string, f: TimeFormat, zone: Timezone = local(), raiseParseException(f, input, "Parsing ended but there was still patterns remaining") - result = toDateTime(parsed, zone, f, input) + if parsed.yearweek.isSome: + result = toDateTimeByWeek(parsed, zone, f, input) + elif parsed.isoyear.isSome: + raiseParseException(f, input, "Iso year GG or GGGG require iso week V or VV") + else: + result = toDateTime(parsed, zone, f, input) proc parse*(input, f: string, tz: Timezone = local(), loc: DateTimeLocale = DefaultLocale): DateTime {.parseFormatRaises.} = @@ -2645,33 +2752,6 @@ proc `+=`*(t: var Time, b: TimeInterval) = proc `-=`*(t: var Time, b: TimeInterval) = t = t - b -# -# Day of year -# - -proc initDateTime*(weekday: WeekDay, isoweek: IsoWeekRange, isoyear: IsoYear, - hour: HourRange, minute: MinuteRange, second: SecondRange, - nanosecond: NanosecondRange, - zone: Timezone = local()): DateTime {.since: (1, 5).} = - ## Create a new `DateTime <#DateTime>`_ from a weekday and an ISO 8601 week number and year - ## in the specified timezone. - ## - ## .. warning:: The ISO week-based year can correspond to the following or previous year from 29 December to January 3. - runnableExamples: - assert initDateTime(21, mApr, 2018, 00, 00, 00) == initDateTime(dSat, 16, 2018.IsoYear, 00, 00, 00) - assert initDateTime(30, mDec, 2019, 00, 00, 00) == initDateTime(dMon, 01, 2020.IsoYear, 00, 00, 00) - assert initDateTime(13, mSep, 2020, 00, 00, 00) == initDateTime(dSun, 37, 2020.IsoYear, 00, 00, 00) - assert initDateTime(2, mJan, 2021, 00, 00, 00) == initDateTime(dSat, 53, 2020.IsoYear, 00, 00, 00) - - # source https://webspace.science.uu.nl/~gent0113/calendar/isocalendar.htm - let d = isoweek * 7 + weekday.int - initDateTime(4, mJan, isoyear.int, 00, 00, 00).weekday.int - 4 - initDateTime(1, mJan, isoyear.int, hour, minute, second, nanosecond, zone) + initTimeInterval(days=d) - -proc initDateTime*(weekday: WeekDay, isoweek: IsoWeekRange, isoyear: IsoYear, - hour: HourRange, minute: MinuteRange, second: SecondRange, - zone: Timezone = local()): DateTime {.since: (1, 5).} = - initDateTime(weekday, isoweek, isoyear, hour, minute, second, 0, zone) - # # Other # diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index 91db310339..5794fa739e 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -742,3 +742,27 @@ block: # ttimes doAssert getWeeksInIsoYear(2014.IsoYear) == 52 doAssert getWeeksInIsoYear(2015.IsoYear) == 53 doAssert getWeeksInIsoYear(2016.IsoYear) == 52 + + block: # parse and generate iso years + # short calendar week with text + parseTest("KW 23 2023", "'KW' VV GGGG", + "2023-06-05T00:00:00Z", 155) + parseTest("KW 5 2023", "'KW' V GGGG", + "2023-01-30T00:00:00Z", 29) + parseTest("KW 05 23 Saturday", "'KW' V GG dddd", + "2023-02-04T00:00:00Z", 34) + parseTest("KW 53 20 Fri", "'KW' VV GG ddd", + "2021-01-01T00:00:00Z", 0) + + parseTestExcp("KW 23", "'KW' VV") # no year + parseTestExcp("KW 23", "'KW' V") # no year + parseTestExcp("KW 23", "'KW' GG") # no week + parseTestExcp("KW 2023", "'KW' GGGG") # no week + + var dt = initDateTime(5, mJan, 2023, 0, 0, 0, utc()) + check dt.format("V") == "1" + check dt.format("VV") == "01" + check dt.format("GG") == "23" + check dt.format("GGGG") == "2023" + check dt.format("dddd 'KW'V GGGG") == "Thursday KW1 2023" + diff --git a/tests/system/tuse_version.nim b/tests/system/tuse_version.nim deleted file mode 100644 index 6f12becafa..0000000000 --- a/tests/system/tuse_version.nim +++ /dev/null @@ -1,49 +0,0 @@ -discard """ - matrix: "-d:NimMajor=1 -d:NimMinor=0 -d:NimPatch=100" -""" - -{.warning[UnusedImport]: off.} - -import std/[ - # Core: - bitops, typetraits, lenientops, macros, volatile, - - # Algorithms: - algorithm, sequtils, - - # Collections: - critbits, deques, heapqueue, intsets, lists, options, sets, - sharedlist, tables, - - # Strings: - editdistance, wordwrap, parseutils, ropes, - pegs, strformat, strmisc, strscans, strtabs, - strutils, unicode, unidecode, - - # Generic operator system services: - os, streams, - - # Math libraries: - complex, math, mersenne, random, rationals, stats, sums, - - # Internet protocols: - httpcore, mimetypes, uri, - - # Parsers: - htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, - - # XML processing: - xmltree, xmlparser, - - # Generators: - htmlgen, - - # Hashing: - base64, hashes, - - # Miscellaneous: - colors, sugar, varints, -] - - -doAssert NimVersion == "1.0.100" From b14043c39e40e941a79ef3794e2998b04387f5d2 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 22 May 2023 12:53:50 +0800 Subject: [PATCH 112/489] revert #21808 (#21881) --- changelogs/changelog_2_0_0.md | 1 - config/nim.cfg | 7 ------- 2 files changed, 8 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 2de86fb691..dcdaa797dd 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -472,7 +472,6 @@ static libraries. - When compiling for Release the flag `-fno-math-errno` is used for GCC. -- When compiling for Release the flag `--build-id=none` is used for GCC Linker. - Removed deprecated `LineTooLong` hint. diff --git a/config/nim.cfg b/config/nim.cfg index 6af5b0fd7a..a9dba347a0 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -364,10 +364,3 @@ tcc.options.always = "-w" clang.cpp.options.linker %= "${clang.cpp.options.linker} -s" @end -# Linker: Skip "Build-ID metadata strings" in binaries when build for release. -@if release or danger: - @if not macosx: - gcc.options.linker %= "${gcc.options.linker} -Wl,--build-id=none" - gcc.cpp.options.linker %= "${gcc.cpp.options.linker} -Wl,--build-id=none" - @end -@end From ee3650b29e82eb0b48d70cb30ed1dd23a7472cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Mon, 22 May 2023 16:39:54 +0100 Subject: [PATCH 113/489] documents changes on byref and bycopy (#21882) --- doc/manual.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/doc/manual.md b/doc/manual.md index 8075da18fc..2f9506a879 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -8444,8 +8444,7 @@ is available and a literal dollar sign must be written as ``$$``. Bycopy pragma ------------- -The `bycopy` pragma can be applied to an object or tuple type and -instructs the compiler to pass the type by value to procs: +The `bycopy` pragma can be applied to an object or tuple type or a proc param. It instructs the compiler to pass the type by value to procs: ```nim type @@ -8453,14 +8452,19 @@ instructs the compiler to pass the type by value to procs: x, y, z: float ``` -The Nim compiler automatically determines whether a parameter is passed by value or by reference based on the parameter type's size. If a parameter must be passed by value or by reference, (such as when interfacing with a C library) use the bycopy or byref pragmas. +The Nim compiler automatically determines whether a parameter is passed by value or +by reference based on the parameter type's size. If a parameter must be passed by value +or by reference, (such as when interfacing with a C library) use the bycopy or byref pragmas. +Notice params marked as `byref` takes precedence over types marked as `bycopy`. Byref pragma ------------ -The `byref` pragma can be applied to an object or tuple type and instructs -the compiler to pass the type by reference (hidden pointer) to procs. - +The `byref` pragma can be applied to an object or tuple type or a proc param. +When applied to a type it instructs the compiler to pass the type by reference +(hidden pointer) to procs. When applied to a param it will take precedence, even +if the the type was marked as `bycopy`. When using the Cpp backend, params marked +as byref will translate to cpp references `&`. Varargs pragma -------------- From d696ef5ad7cefdde044bce0277fac172de0f56ea Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 22 May 2023 20:35:27 +0200 Subject: [PATCH 114/489] =?UTF-8?q?Atlas=20tool:=20search=20github=20too,?= =?UTF-8?q?=20no=20need=20to=20register=20your=20project=20at=20pa?= =?UTF-8?q?=E2=80=A6=20(#21884)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Atlas tool: search github too, no need to register your project at packages.json * added missing file --- tools/atlas/atlas.nim | 4 ++- tools/atlas/atlas.nim.cfg | 1 + tools/atlas/packagesjson.nim | 56 ++++++++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 tools/atlas/atlas.nim.cfg diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index dfa60856ef..fe070c9691 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -248,7 +248,9 @@ proc toUrl(c: var AtlasContext; p: string): string = fillPackageLookupTable(c) result = c.p.getOrDefault(unicode.toLower p) if result.len == 0: - inc c.errors + result = getUrlFromGithub(p) + if result.len == 0: + inc c.errors proc toName(p: string): PackageName = if p.isUrl: diff --git a/tools/atlas/atlas.nim.cfg b/tools/atlas/atlas.nim.cfg new file mode 100644 index 0000000000..fcace05799 --- /dev/null +++ b/tools/atlas/atlas.nim.cfg @@ -0,0 +1 @@ +--define:ssl diff --git a/tools/atlas/packagesjson.nim b/tools/atlas/packagesjson.nim index 0b85997699..5ceef706f2 100644 --- a/tools/atlas/packagesjson.nim +++ b/tools/atlas/packagesjson.nim @@ -1,5 +1,5 @@ -import std / [json, os, sets, strutils] +import std / [json, os, sets, strutils, httpclient, uri] type Package* = ref object @@ -65,11 +65,57 @@ proc `$`*(pkg: Package): string = if pkg.web.len > 0: result &= " website: " & pkg.web & "\n" +proc toTags(j: JsonNode): seq[string] = + result = @[] + if j.kind == JArray: + for elem in items j: + result.add elem.getStr("") + +proc singleGithubSearch(term: string): JsonNode = + # For example: + # https://api.github.com/search/repositories?q=weave+language:nim + var client = newHttpClient() + try: + let x = client.getContent("https://api.github.com/search/repositories?q=" & encodeUrl(term) & "+language:nim") + result = parseJson(x) + except: + discard "it's a failed search, ignore" + finally: + client.close() + +proc githubSearch(seen: var HashSet[string]; terms: seq[string]) = + for term in terms: + let results = singleGithubSearch(term) + for j in items(results.getOrDefault("items")): + let p = Package( + name: j.getOrDefault("name").getStr, + url: j.getOrDefault("html_url").getStr, + downloadMethod: "git", + tags: toTags(j.getOrDefault("topics")), + description: ", not listed in packages.json", + web: j.getOrDefault("html_url").getStr + ) + if not seen.containsOrIncl(p.url): + echo p + +proc getUrlFromGithub*(term: string): string = + let results = singleGithubSearch(term) + var matches = 0 + result = "" + for j in items(results.getOrDefault("items")): + if cmpIgnoreCase(j.getOrDefault("name").getStr, term) == 0: + if matches == 0: + result = j.getOrDefault("html_url").getStr + inc matches + if matches != 1: + # ambiguous, not ok! + result = "" + proc search*(pkgList: seq[Package]; terms: seq[string]) = - var found = false + var seen = initHashSet[string]() template onFound = echo pkg - found = true + seen.incl pkg.url break forPackage for pkg in pkgList: @@ -86,8 +132,8 @@ proc search*(pkgList: seq[Package]; terms: seq[string]) = onFound() else: echo(pkg) - - if not found and terms.len > 0: + githubSearch seen, terms + if seen.len == 0 and terms.len > 0: echo("No package found.") type PkgCandidates* = array[3, seq[Package]] From 76a98fee650228306a6b1af72e64bb83a9473ef0 Mon Sep 17 00:00:00 2001 From: Bung Date: Tue, 23 May 2023 15:39:44 +0800 Subject: [PATCH 115/489] fix #21251 Compiler SIGSEGV when using SharedTable (#21876) fix #21251 --- compiler/semexprs.nim | 2 ++ lib/pure/collections/deques.nim | 5 ++--- lib/pure/collections/tableimpl.nim | 8 +++++--- lib/pure/collections/tables.nim | 2 -- tests/stdlib/t21251.nim | 6 ++++++ 5 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 tests/stdlib/t21251.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b79abadff4..f90ef48701 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2984,6 +2984,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType else: {checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields} s = qualifiedLookUp(c, n, checks) + if s == nil: + return if c.matchedConcept == nil: semCaptureSym(s, c.p.owner) case s.kind of skProc, skFunc, skMethod, skConverter, skIterator: diff --git a/lib/pure/collections/deques.nim b/lib/pure/collections/deques.nim index 60e0fd351e..ed58028c8e 100644 --- a/lib/pure/collections/deques.nim +++ b/lib/pure/collections/deques.nim @@ -70,9 +70,8 @@ template initImpl(result: typed, initialSize: int) = newSeq(result.data, correctSize) template checkIfInitialized(deq: typed) = - when compiles(defaultInitialSize): - if deq.mask == 0: - initImpl(deq, defaultInitialSize) + if deq.mask == 0: + initImpl(deq, defaultInitialSize) proc initDeque*[T](initialSize: int = defaultInitialSize): Deque[T] = ## Creates a new empty deque. diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index 81079a3d17..fa06b99234 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -11,6 +11,9 @@ include hashcommon +const + defaultInitialSize* = 32 + template rawGetDeepImpl() {.dirty.} = # Search algo for unconditional add genHashImpl(key, hc) var h: Hash = hc and maxHash(t) @@ -31,9 +34,8 @@ proc rawInsert[X, A, B](t: var X, data: var KeyValuePairSeq[A, B], rawInsertImpl() template checkIfInitialized() = - when compiles(defaultInitialSize): - if t.dataLen == 0: - initImpl(t, defaultInitialSize) + if t.dataLen == 0: + initImpl(t, defaultInitialSize) template addImpl(enlarge) {.dirty.} = checkIfInitialized() diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 4737fa4782..9ecc6b8e6c 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -220,8 +220,6 @@ type ## For creating a new empty TableRef, use `newTable proc ## <#newTable>`_. -const - defaultInitialSize* = 32 # ------------------------------ helpers --------------------------------- diff --git a/tests/stdlib/t21251.nim b/tests/stdlib/t21251.nim new file mode 100644 index 0000000000..4402e9b7e1 --- /dev/null +++ b/tests/stdlib/t21251.nim @@ -0,0 +1,6 @@ +import std / [tables, sets, sharedtables] + +var shared: SharedTable[int, int] +shared.init + +shared[1] = 1 From d372ad3ee6563cff2c086e774f1e00b091b79373 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Tue, 23 May 2023 04:59:21 -0300 Subject: [PATCH 116/489] Fix jsgen (#21880) * . * Fix jsgen FrameInfo * Fix jsgen FrameInfo * . * Move to PProc --- changelogs/changelog_2_0_0.md | 1 + compiler/jsgen.nim | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index dcdaa797dd..b15818ae69 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -473,6 +473,7 @@ - When compiling for Release the flag `-fno-math-errno` is used for GCC. - Removed deprecated `LineTooLong` hint. +- Line numbers and filenames of source files work correctly inside templates for JavaScript targets. ## Docgen diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 45b0baec0c..ecfc221086 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -110,6 +110,7 @@ type extraIndent: int up: PProc # up the call chain; required for closure support declaredGlobals: IntSet + previousFileName: string # For frameInfo inside templates. template config*(p: PProc): ConfigRef = p.module.config @@ -803,6 +804,10 @@ proc genLineDir(p: PProc, n: PNode) = lineF(p, "$1", [lineDir(p.config, n.info, line)]) if hasFrameInfo(p): lineF(p, "F.line = $1;$n", [rope(line)]) + let currentFileName = toFilename(p.config, n.info) + if p.previousFileName != currentFileName: + lineF(p, "F.filename = $1;$n", [makeJSString(currentFileName)]) + p.previousFileName = currentFileName proc genWhileStmt(p: PProc, n: PNode) = var cond: TCompRes From 125207019338d50acd810133350e9be84a1da35b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 23 May 2023 13:47:51 +0200 Subject: [PATCH 117/489] minor atlas improvements (#21888) * minor atlas improvements * atlas: support a _deps workspace subdirectory --- tools/atlas/atlas.md | 16 +++++++--- tools/atlas/atlas.nim | 71 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/tools/atlas/atlas.md b/tools/atlas/atlas.md index 61ca28ff00..cbdb54b9a7 100644 --- a/tools/atlas/atlas.md +++ b/tools/atlas/atlas.md @@ -44,13 +44,15 @@ Thanks to this setup, it's easy to develop multiple projects at the same time. A project plus its dependencies are stored in a workspace: $workspace / main project - $workspace / dependency A - $workspace / dependency B + $workspace / _deps / dependency A + $workspace / _deps / dependency B +The deps directory can be set via `--deps:DIR` explicitly. It defaults to `_deps`. +If you want it to be the same as the workspace use `--deps:.`. -No attempts are being made at keeping directory hygiene inside the -workspace, you're supposed to create appropriate `$workspace` directories -at your own leisure. +You can move a dependency out of the `_deps` subdirectory into the workspace. +This can be convenient should you decide to work on a dependency too. You need to +patch the `nim.cfg` then. ## Commands @@ -85,3 +87,7 @@ Use the .nimble file to setup the project's dependencies. Update every package in the workspace that has a remote URL that matches `filter` if a filter is given. The package is only updated if there are no uncommitted changes. + +### Others + +Run `atlas --help` for more features. diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index fe070c9691..4662edf9d9 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -29,12 +29,17 @@ Command: the given Nimble file update [filter] update every package in the workspace that has a remote URL that matches `filter` if a filter is given + build|test|doc|tasks currently delegates to `nimble build|test|doc` + task currently delegates to `nimble ` Options: --keepCommits do not perform any `git checkouts` --cfgHere also create/maintain a nim.cfg in the current working directory --workspace=DIR use DIR as workspace + --deps=DIR store dependencies in DIR instead of the workspace + (if DIR is a relative path, it is interpreted to + be relative to the workspace) --version show the version --help show this help """ @@ -63,7 +68,7 @@ type url, commit: string rel: DepRelation # "requires x < 1.0" is silly, but Nimble allows it so we have too. AtlasContext = object - projectDir, workspace: string + projectDir, workspace, depsDir: string hasPackageList: bool keepCommits: bool cfgHere: bool @@ -91,6 +96,20 @@ type include testdata +proc silentExec(cmd: string; args: openArray[string]): (string, int) = + var cmdLine = cmd + for i in 0.. ", result @@ -265,7 +280,10 @@ proc isShortCommitHash(commit: string): bool {.inline.} = commit.len >= 4 and commit.len < 40 proc checkoutCommit(c: var AtlasContext; w: Dependency) = - let dir = c.workspace / w.name.string + var dir = c.workspace / w.name.string + if not dirExists(dir): + dir = c.depsDir / w.name.string + withDir c, dir: if w.commit.len == 0 or cmpIgnoreCase(w.commit, "head") == 0: gitPull(c, w.name) @@ -372,8 +390,8 @@ proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]): seq[string] = let destDir = toDestDir(w.name) let oldErrors = c.errors - if not dirExists(c.workspace / destDir): - withDir c, c.workspace: + if not dirExists(c.workspace / destDir) and not dirExists(c.depsDir / destDir): + withDir c, (if i == 0: c.workspace else: c.depsDir): let err = cloneUrl(c, w.url, destDir, false) if err != "": error c, w.name, err @@ -405,7 +423,9 @@ proc patchNimCfg(c: var AtlasContext; deps: seq[string]; cfgPath: string) = var paths = "--noNimblePath\n" for d in deps: let pkgname = toDestDir d.PackageName - let x = relativePath(c.workspace / pkgname, cfgPath, '/') + let pkgdir = if dirExists(c.workspace / pkgname): c.workspace / pkgname + else: c.depsDir / pkgName + let x = relativePath(pkgdir, cfgPath, '/') paths.add "--path:\"" & x & "\"\n" var cfgContent = configPatternBegin & paths & configPatternEnd @@ -448,14 +468,14 @@ proc installDependencies(c: var AtlasContext; nimbleFile: string) = # 1. find .nimble file in CWD # 2. install deps from .nimble var work: seq[Dependency] = @[] - let (path, pkgname, _) = splitFile(nimbleFile) + let (_, pkgname, _) = splitFile(nimbleFile) let dep = Dependency(name: toName(pkgname), url: "", commit: "") discard collectDeps(c, work, dep, nimbleFile) let paths = cloneLoop(c, work) patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c)) -proc updateWorkspace(c: var AtlasContext; filter: string) = - for kind, file in walkDir(c.workspace): +proc updateWorkspace(c: var AtlasContext; dir, filter: string) = + for kind, file in walkDir(dir): if kind == pcDir and dirExists(file / ".git"): c.withDir file: let pkg = PackageName(file) @@ -508,6 +528,11 @@ proc main = createDir(val) else: writeHelp() + of "deps": + if val.len > 0: + c.depsDir = val + else: + writeHelp() of "cfghere": c.cfgHere = true else: writeHelp() of cmdEnd: assert false, "cannot happen" @@ -518,6 +543,19 @@ proc main = c.workspace = getCurrentDir() while c.workspace.len > 0 and dirExists(c.workspace / ".git"): c.workspace = c.workspace.parentDir() + + when MockupRun: + c.depsDir = c.workspace + else: + if c.depsDir.len > 0: + if c.depsDir == ".": + c.depsDir = c.workspace + elif not isAbsolute(c.depsDir): + c.depsDir = c.workspace / c.depsDir + else: + c.depsDir = c.workspace / "_deps" + createDir(c.depsDir) + echo "Using workspace ", c.workspace case action @@ -553,13 +591,18 @@ proc main = updatePackages(c) search getPackages(c.workspace), args of "update": - updateWorkspace(c, if args.len == 0: "" else: args[0]) + updateWorkspace(c, c.workspace, if args.len == 0: "" else: args[0]) + updateWorkspace(c, c.depsDir, if args.len == 0: "" else: args[0]) of "extract": singleArg() if fileExists(args[0]): echo toJson(extractRequiresInfo(args[0])) else: error "File does not exist: " & args[0] + of "build", "test", "doc", "tasks": + nimbleExec(action, args) + of "task": + nimbleExec("", args) else: error "Invalid action: " & action From bdccc9fef93d6598ec453a19152c4e98539f783f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Tue, 23 May 2023 19:10:24 +0100 Subject: [PATCH 118/489] small refactor in preparation to fix #21889 (#21892) --- compiler/cgen.nim | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 0e6e02c7a4..4b2d4fe09d 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -623,6 +623,27 @@ proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool = # and s.owner.kind == skModule # owner isn't always a module (global pragma on local var) # and s.loc.k == locGlobalVar # loc isn't always initialized when this proc is used +proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) = + let s = n.sym + if s.constraint.isNil: + if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: + decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)] + if p.hcrOn: decl.add("static ") + elif sfImportc in s.flags: decl.add("extern ") + elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ") + else: decl.add("N_LIB_PRIVATE ") + if s.kind == skLet and value != "": decl.add("NIM_CONST ") + decl.add(td) + if p.hcrOn: decl.add("*") + if sfRegister in s.flags: decl.add(" register") + if sfVolatile in s.flags: decl.add(" volatile") + if sfNoalias in s.flags: decl.add(" NIM_NOALIAS") + else: + if value != "": + decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value]) + else: + decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r]) + proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = let s = n.sym if s.loc.k == locNone: @@ -649,19 +670,8 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = else: var decl: Rope = "" var td = getTypeDesc(p.module, s.loc.t, dkVar) + genGlobalVarDecl(p, n, td, value, decl) if s.constraint.isNil: - if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: - decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)] - if p.hcrOn: decl.add("static ") - elif sfImportc in s.flags: decl.add("extern ") - elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ") - else: decl.add("N_LIB_PRIVATE ") - if s.kind == skLet and value != "": decl.add("NIM_CONST ") - decl.add(td) - if p.hcrOn: decl.add("*") - if sfRegister in s.flags: decl.add(" register") - if sfVolatile in s.flags: decl.add(" volatile") - if sfNoalias in s.flags: decl.add(" NIM_NOALIAS") if value != "": if p.module.compileToCpp and value.startsWith "{{}": # TODO: taking this branch, re"\{\{\}(,\s\{\})*\}" might be emitted, resulting in @@ -682,11 +692,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = decl.addf(" $1 = $2;$n", [s.loc.r, value]) else: decl.addf(" $1;$n", [s.loc.r]) - else: - if value != "": - decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value]) - else: - decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r]) + p.module.s[cfsVars].add(decl) if p.withinLoop > 0 and value == "": # fixes tests/run/tzeroarray: From 9493e6729138ecfdbc3f6ad433a32fcf19467a34 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 23 May 2023 23:48:00 +0200 Subject: [PATCH 119/489] =?UTF-8?q?Atlas:=20first=20lockfiles=20implementa?= =?UTF-8?q?tion;=20cleared=20up=20upated=20vs=20updateWor=E2=80=A6=20(#218?= =?UTF-8?q?95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atlas: first lockfiles implementation; cleared up upated vs updateWorkspace commands --- tools/atlas/atlas.md | 10 ++++-- tools/atlas/atlas.nim | 84 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/tools/atlas/atlas.md b/tools/atlas/atlas.md index cbdb54b9a7..3e9bc32e57 100644 --- a/tools/atlas/atlas.md +++ b/tools/atlas/atlas.md @@ -60,17 +60,21 @@ patch the `nim.cfg` then. Atlas supports the following commands: -### Clone +### Clone/Update Clones a URL and all of its dependencies (recursively) into the workspace. Creates or patches a `nim.cfg` file with the required `--path` entries. +**Note**: Due to the used algorithms an `update` is the same as a `clone`. -### Clone + +### Clone/Update The `` is translated into an URL via `packages.json` and then `clone ` is performed. +**Note**: Due to the used algorithms an `update` is the same as a `clone`. + ### Search @@ -82,7 +86,7 @@ in its description (or name or list of tags). Use the .nimble file to setup the project's dependencies. -### Update [filter] +### UpdateWorkspace [filter] Update every package in the workspace that has a remote URL that matches `filter` if a filter is given. The package is only updated diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 4662edf9d9..0358e107cc 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -9,13 +9,14 @@ ## Simple tool to automate frequent workflows: Can "clone" ## a Nimble dependency and its dependencies recursively. -import std/[parseopt, strutils, os, osproc, tables, sets, json, jsonutils] +import std / [parseopt, strutils, os, osproc, tables, sets, json, jsonutils] import parse_requires, osutils, packagesjson from unicode import nil const - Version = "0.2" + Version = "0.3" + LockFileName = "atlas.lock" Usage = "atlas - Nim Package Cloner Version " & Version & """ (c) 2021 Andreas Rumpf @@ -23,11 +24,13 @@ Usage: atlas [options] [command] [arguments] Command: clone url|pkgname clone a package and all of its dependencies + update url|pkgname update a package and all of its dependencies install proj.nimble use the .nimble file to setup the project's dependencies search keyw keywB... search for package that contains the given keywords extract file.nimble extract the requirements and custom commands from the given Nimble file - update [filter] update every package in the workspace that has a remote + updateWorkspace [filter] + update every package in the workspace that has a remote URL that matches `filter` if a filter is given build|test|doc|tasks currently delegates to `nimble build|test|doc` task currently delegates to `nimble ` @@ -40,6 +43,8 @@ Options: --deps=DIR store dependencies in DIR instead of the workspace (if DIR is a relative path, it is interpreted to be relative to the workspace) + --genlock generate a lock file (use with `clone` and `update`) + --uselock use the lock file for the build --version show the version --help show this help """ @@ -59,6 +64,12 @@ const TestsDir = "tools/atlas/tests" type + LockOption = enum + noLock, genLock, useLock + + LockFileEntry = object + dir, url, commit: string + PackageName = distinct string DepRelation = enum normal, strictlyLess, strictlyGreater @@ -75,6 +86,9 @@ type p: Table[string, string] # name -> url mapping processed: HashSet[string] # the key is (url / commit) errors: int + lockOption: LockOption + lockFileToWrite: seq[LockFileEntry] + lockFileToUse: Table[string, LockFileEntry] when MockupRun: currentDir: string step: int @@ -279,23 +293,51 @@ proc needsCommitLookup(commit: string): bool {.inline.} = proc isShortCommitHash(commit: string): bool {.inline.} = commit.len >= 4 and commit.len < 40 +proc getRequiredCommit(c: var AtlasContext; w: Dependency): string = + if needsCommitLookup(w.commit): versionToCommit(c, w) + elif isShortCommitHash(w.commit): shortToCommit(c, w.commit) + else: w.commit + +proc getRemoteUrl(): string = + execProcess("git config --get remote.origin.url").strip() + +proc genLockEntry(c: var AtlasContext; w: Dependency; dir: string) = + let url = getRemoteUrl() + var commit = getRequiredCommit(c, w) + if commit.len == 0 or needsCommitLookup(commit): + commit = execProcess("git log -1 --pretty=format:%H").strip() + c.lockFileToWrite.add LockFileEntry(dir: relativePath(dir, c.workspace, '/'), url: url, commit: commit) + +proc commitFromLockFile(c: var AtlasContext; dir: string): string = + let url = getRemoteUrl() + let d = relativePath(dir, c.workspace, '/') + if d in c.lockFileToUse: + result = c.lockFileToUse[d].commit + let wanted = c.lockFileToUse[d].url + if wanted != url: + error c, PackageName(d), "remote URL has been compromised: got: " & + url & " but wanted: " & wanted + else: + error c, PackageName(d), "package is not listed in the lock file" + proc checkoutCommit(c: var AtlasContext; w: Dependency) = var dir = c.workspace / w.name.string if not dirExists(dir): dir = c.depsDir / w.name.string withDir c, dir: - if w.commit.len == 0 or cmpIgnoreCase(w.commit, "head") == 0: + if c.lockOption == genLock: + genLockEntry(c, w, dir) + elif c.lockOption == useLock: + checkoutGitCommit(c, w.name, commitFromLockFile(c, dir)) + elif w.commit.len == 0 or cmpIgnoreCase(w.commit, "head") == 0: gitPull(c, w.name) else: let err = isCleanGit(c) if err != "": warn c, w.name, err else: - let requiredCommit = - if needsCommitLookup(w.commit): versionToCommit(c, w) - elif isShortCommitHash(w.commit): shortToCommit(c, w.commit) - else: w.commit + let requiredCommit = getRequiredCommit(c, w) let (cc, status) = exec(c, GitCurrentCommit, []) let currentCommit = strutils.strip(cc) if requiredCommit == "" or status != 0: @@ -403,6 +445,14 @@ proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]): seq[string] = collectNewDeps(c, work, w, result, i == 0) inc i +proc readLockFile(c: var AtlasContext) = + let jsonAsStr = readFile(c.projectDir / LockFileName) + let jsonTree = parseJson(jsonAsStr) + let data = to(jsonTree, seq[LockFileEntry]) + c.lockFileToUse = initTable[string, LockFileEntry]() + for d in items(data): + c.lockFileToUse[d.dir] = d + proc clone(c: var AtlasContext; start: string): seq[string] = # non-recursive clone. let url = toUrl(c, start) @@ -413,7 +463,11 @@ proc clone(c: var AtlasContext; start: string): seq[string] = return c.projectDir = c.workspace / toDestDir(work[0].name) + if c.lockOption == useLock: + readLockFile c result = cloneLoop(c, work) + if c.lockOption == genLock: + writeFile c.projectDir / LockFileName, toJson(c.lockFileToWrite).pretty const configPatternBegin = "############# begin Atlas config section ##########\n" @@ -534,6 +588,16 @@ proc main = else: writeHelp() of "cfghere": c.cfgHere = true + of "genlock": + if c.lockOption != useLock: + c.lockOption = genLock + else: + writeHelp() + of "uselock": + if c.lockOption != genLock: + c.lockOption = useLock + else: + writeHelp() else: writeHelp() of cmdEnd: assert false, "cannot happen" @@ -561,7 +625,7 @@ proc main = case action of "": error "No action." - of "clone": + of "clone", "update": singleArg() let deps = clone(c, args[0]) patchNimCfg c, deps, if c.cfgHere: getCurrentDir() else: findSrcDir(c) @@ -590,7 +654,7 @@ proc main = of "search", "list": updatePackages(c) search getPackages(c.workspace), args - of "update": + of "updateworkspace": updateWorkspace(c, c.workspace, if args.len == 0: "" else: args[0]) updateWorkspace(c, c.depsDir, if args.len == 0: "" else: args[0]) of "extract": From 761b927e4700ecda2dde8b16fb8beab791436e99 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 24 May 2023 13:43:30 +0800 Subject: [PATCH 120/489] fixes #21863; Incorrect enum field access can cause internal error (#21886) fixes 21863; Incorrect enum field access can cause internal error --- compiler/semexprs.nim | 2 +- tests/enum/t21863.nim | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/enum/t21863.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f90ef48701..ae118159cf 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1047,7 +1047,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType if s != nil: setGenericParams(c, n[0]) return semDirectOp(c, n, flags, expectedType) - elif isSymChoice(n[0]): + elif isSymChoice(n[0]) and nfDotField notin n.flags: # overloaded generic procs e.g. newSeq[int] can end up here return semDirectOp(c, n, flags, expectedType) diff --git a/tests/enum/t21863.nim b/tests/enum/t21863.nim new file mode 100644 index 0000000000..d0d8b1fcd8 --- /dev/null +++ b/tests/enum/t21863.nim @@ -0,0 +1,28 @@ +discard """ +cmd: "nim check --hints:off $file" +action: reject +nimout: ''' +t21863.nim(28, 16) Error: undeclared field: 'A' + found 'A' [enumField declared in t21863.nim(24, 18)] + found 'A' [enumField declared in t21863.nim(25, 18)] +t21863.nim(28, 16) Error: undeclared field: '.' +t21863.nim(28, 16) Error: undeclared field: '.' +t21863.nim(28, 16) Error: expression '' has no type (or is ambiguous) +''' +""" + + + + + + + + + +block: + type + EnumA = enum A, B + EnumB = enum A + EnumC = enum C + + discard EnumC.A From 266cc69f1973773228534f074febd153c472b949 Mon Sep 17 00:00:00 2001 From: Bung Date: Wed, 24 May 2023 21:30:14 +0800 Subject: [PATCH 121/489] fix #21896 asign parameter to global variable generates invalid code (#21900) --- compiler/semstmts.nim | 2 +- tests/global/t21896.nim | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/global/t21896.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 579af973ef..6e2fb92528 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -563,7 +563,7 @@ proc semVarMacroPragma(c: PContext, a: PNode, n: PNode): PNode = return result template isLocalSym(sym: PSym): bool = - sym.kind in {skVar, skLet} and not + sym.kind in {skVar, skLet, skParam} and not ({sfGlobal, sfPure} * sym.flags != {} or sfCompileTime in sym.flags) or sym.kind in {skProc, skFunc, skIterator} and diff --git a/tests/global/t21896.nim b/tests/global/t21896.nim new file mode 100644 index 0000000000..c7765c4dd1 --- /dev/null +++ b/tests/global/t21896.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "cannot assign local to global variable" + line: 7 +""" + +proc example(a:int) = + let b {.global.} = a + +example(1) From b63b5c930e143139197dbacd24bad7d263bbd2e3 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 24 May 2023 16:39:58 +0200 Subject: [PATCH 122/489] Atlas: added 'use' command (#21902) * Atlas: added 'use' command * typo --- tools/atlas/atlas.md | 21 ++++++++++ tools/atlas/atlas.nim | 90 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 104 insertions(+), 7 deletions(-) diff --git a/tools/atlas/atlas.md b/tools/atlas/atlas.md index 3e9bc32e57..40cf6411e8 100644 --- a/tools/atlas/atlas.md +++ b/tools/atlas/atlas.md @@ -60,6 +60,27 @@ patch the `nim.cfg` then. Atlas supports the following commands: +## Use / + +Clone the package behind `url` or `package name` and its dependencies into +the `_deps` directory and make it available for your current project which +should be in the current working directory. Atlas will create or patch +the files `$project.nimble` and `nim.cfg` for you so that you can simply +import the required modules. + +For example: + +``` + mkdir newproject + cd newproject + git init + atlas use lexim + # add `import lexim` to your example.nim file + nim c example.nim + +``` + + ### Clone/Update Clones a URL and all of its dependencies (recursively) into the workspace. diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 0358e107cc..ddfbbd0863 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -23,6 +23,8 @@ const Usage: atlas [options] [command] [arguments] Command: + use url|pkgname clone a package and all of its dependencies and make + it importable for the current project clone url|pkgname clone a package and all of its dependencies update url|pkgname update a package and all of its dependencies install proj.nimble use the .nimble file to setup the project's dependencies @@ -193,13 +195,14 @@ proc message(c: var AtlasContext; category: string; p: PackageName; args: vararg msg.add ' ' msg.add a stdout.writeLine msg - inc c.errors proc warn(c: var AtlasContext; p: PackageName; args: varargs[string]) = message(c, "[Warning] ", p, args) + inc c.errors proc error(c: var AtlasContext; p: PackageName; args: varargs[string]) = message(c, "[Error] ", p, args) + inc c.errors proc sameVersionAs(tag, ver: string): bool = const VersionChars = {'0'..'9', '.'} @@ -424,7 +427,7 @@ proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency]; else: result.add toDestDir(dep.name) -proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]): seq[string] = +proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]; startIsDep: bool): seq[string] = result = @[] var i = 0 while i < work.len: @@ -433,7 +436,7 @@ proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]): seq[string] = let oldErrors = c.errors if not dirExists(c.workspace / destDir) and not dirExists(c.depsDir / destDir): - withDir c, (if i == 0: c.workspace else: c.depsDir): + withDir c, (if i != 0 or startIsDep: c.depsDir else: c.workspace): let err = cloneUrl(c, w.url, destDir, false) if err != "": error c, w.name, err @@ -453,7 +456,7 @@ proc readLockFile(c: var AtlasContext) = for d in items(data): c.lockFileToUse[d.dir] = d -proc clone(c: var AtlasContext; start: string): seq[string] = +proc clone(c: var AtlasContext; start: string; startIsDep: bool): seq[string] = # non-recursive clone. let url = toUrl(c, start) var work = @[Dependency(name: toName(start), url: url, commit: "")] @@ -465,7 +468,7 @@ proc clone(c: var AtlasContext; start: string): seq[string] = c.projectDir = c.workspace / toDestDir(work[0].name) if c.lockOption == useLock: readLockFile c - result = cloneLoop(c, work) + result = cloneLoop(c, work, startIsDep) if c.lockOption == genLock: writeFile c.projectDir / LockFileName, toJson(c.lockFileToWrite).pretty @@ -525,7 +528,7 @@ proc installDependencies(c: var AtlasContext; nimbleFile: string) = let (_, pkgname, _) = splitFile(nimbleFile) let dep = Dependency(name: toName(pkgname), url: "", commit: "") discard collectDeps(c, work, dep, nimbleFile) - let paths = cloneLoop(c, work) + let paths = cloneLoop(c, work, startIsDep = true) patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c)) proc updateWorkspace(c: var AtlasContext; dir, filter: string) = @@ -549,6 +552,71 @@ proc updateWorkspace(c: var AtlasContext; dir, filter: string) = else: error c, pkg, "could not fetch current branch name" +proc addUnique[T](s: var seq[T]; elem: sink T) = + if not s.contains(elem): s.add elem + +proc addDepFromNimble(c: var AtlasContext; deps: var seq[string]; project: PackageName; dep: string) = + var depDir = c.workspace / dep + if not dirExists(depDir): + depDir = c.depsDir / dep + if dirExists(depDir): + withDir c, depDir: + let src = findSrcDir(c) + if src.len != 0: + deps.addUnique dep / src + else: + deps.addUnique dep + else: + warn c, project, "cannot find: " & depDir + +proc patchNimbleFile(c: var AtlasContext; dep: string; deps: var seq[string]) = + let thisProject = getCurrentDir().splitPath.tail + let oldErrors = c.errors + let url = toUrl(c, dep) + if oldErrors != c.errors: + warn c, toName(dep), "cannot resolve package name" + else: + var nimbleFile = "" + for x in walkFiles("*.nimble"): + if nimbleFile.len == 0: + nimbleFile = x + else: + # ambiguous .nimble file + warn c, toName(dep), "cannot determine `.nimble` file; there are multiple to choose from" + return + # see if we have this requirement already listed. If so, do nothing: + var found = false + if nimbleFile.len > 0: + let nimbleInfo = extractRequiresInfo(c, nimbleFile) + for r in nimbleInfo.requires: + var tokens: seq[string] = @[] + for token in tokenizeRequires(r): + tokens.add token + if tokens.len > 0: + let oldErrors = c.errors + let urlB = toUrl(c, tokens[0]) + if oldErrors != c.errors: + warn c, toName(tokens[0]), "cannot resolve package name; found in: " & nimbleFile + if url == urlB: + found = true + + if cmpIgnoreCase(tokens[0], "nim") != 0: + c.addDepFromNimble deps, toName(thisProject), tokens[0] + + if not found: + let line = "requires \"$1@#head\"\n" % dep.escape("", "") + if nimbleFile.len > 0: + let oldContent = readFile(nimbleFile) + writeFile nimbleFile, oldContent & "\n" & line + message(c, "[Info] ", toName(thisProject), "updated: " & nimbleFile) + else: + let outfile = thisProject & ".nimble" + writeFile outfile, line + message(c, "[Info] ", toName(thisProject), "created: " & outfile) + c.addDepFromNimble deps, toName(thisProject), dep + else: + message(c, "[Info] ", toName(thisProject), "up to date: " & nimbleFile) + proc main = var action = "" var args: seq[string] = @[] @@ -627,7 +695,7 @@ proc main = error "No action." of "clone", "update": singleArg() - let deps = clone(c, args[0]) + let deps = clone(c, args[0], startIsDep = false) patchNimCfg c, deps, if c.cfgHere: getCurrentDir() else: findSrcDir(c) when MockupRun: if not c.mockupSuccess: @@ -635,6 +703,14 @@ proc main = else: if c.errors > 0: error "There were problems." + of "use": + singleArg() + discard clone(c, args[0], startIsDep = true) + var deps: seq[string] = @[] + patchNimbleFile(c, args[0], deps) + patchNimCfg c, deps, getCurrentDir() + if c.errors > 0: + error "There were problems." of "install": if args.len > 1: error "install command takes a single argument" From c7f25419149d6b4b0723f0ef177bbaad72d7bc3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Wed, 24 May 2023 15:42:53 +0100 Subject: [PATCH 123/489] actually fixes #21889 "constructor pragma doing nothing in globals" (#21897) actually fixes #21889 --- compiler/ccgstmts.nim | 48 +++++++++++++++++++++++--------------- compiler/cgen.nim | 17 ++++++++++++-- tests/cpp/tconstructor.nim | 24 +++++++++++++++++++ 3 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 tests/cpp/tconstructor.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index b57864b466..1ed546256d 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -288,15 +288,32 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) = #echo "New code produced for ", v.name.s, " ", p.config $ value.info genBracedInit(p, value, isConst = false, v.typ, result) +proc genCppVarForConstructor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) = + var params = newRopeAppender() + var argsCounter = 0 + let typ = skipTypes(value[0].typ, abstractInst) + assert(typ.kind == tyProc) + for i in 1..x = inX; + this->y = inY; + } + //CppClass() = default; +}; +""".} + +type CppClass* {.importcpp.} = object + x: int32 + y: int32 + +proc makeCppClass(x, y: int32): CppClass {.importcpp: "CppClass(@)", constructor.} + +var shouldCompile = makeCppClass(1, 2) From 4d6be458a00a642555e95055ff640daba59513f7 Mon Sep 17 00:00:00 2001 From: metagn Date: Wed, 24 May 2023 18:55:09 +0300 Subject: [PATCH 124/489] js -r defines nodejs & program result undeclared if unavailable (#21849) * js -r defines nodejs & program result undefined if unavailable fixes #16985, fixes #16074 * fix * add changelog too * minor word change --- changelogs/changelog_2_0_0.md | 4 ++++ compiler/commands.nim | 6 ++++++ lib/pure/unittest.nim | 6 ++++++ lib/std/exitprocs.nim | 10 +++------- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index b15818ae69..11fa8cba35 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -249,6 +249,10 @@ these deprecated aliases are likely not used anymore and it may make sense to simply remove these statements. +- `getProgramResult` and `setProgramResult` in `std/exitprocs` are no longer + declared when they are not available on the backend. Previously it would call + `doAssert false` at runtime despite the condition being compile-time. + ## Standard library additions and changes [//]: # "Changes:" diff --git a/compiler/commands.nim b/compiler/commands.nim index 93a36e714b..4980ff2685 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -654,6 +654,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if backend == TBackend.default: localError(conf, info, "invalid backend: '$1'" % arg) if backend == backendJs: # bug #21209 conf.globalOptions.excl {optThreadAnalysis, optThreads} + if optRun in conf.globalOptions: + # for now, -r uses nodejs, so define nodejs + defineSymbol(conf.symbols, "nodejs") conf.backend = backend of "doccmd": conf.docCmd = arg of "define", "d": @@ -864,6 +867,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; setTarget(conf.target, conf.target.targetOS, cpu) of "run", "r": processOnOffSwitchG(conf, {optRun}, arg, pass, info) + if conf.backend == backendJs: + # for now, -r uses nodejs, so define nodejs + defineSymbol(conf.symbols, "nodejs") of "maxloopiterationsvm": expectArg(conf, switch, arg, pass, info) conf.maxLoopIterationsVM = parseInt(arg) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 9dafa8f037..964fba0e4b 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -519,6 +519,12 @@ proc exceptionTypeName(e: ref Exception): string {.inline.} = if e == nil: "" else: $e.name +when not declared(setProgramResult): + {.warning: "setProgramResult not available on platform, unittest will not" & + " give failing exit code on test failure".} + template setProgramResult(a: int) = + discard + template test*(name, body) {.dirty.} = ## Define a single test case identified by `name`. ## diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim index 736bf06d1b..c44eb30d65 100644 --- a/lib/std/exitprocs.nim +++ b/lib/std/exitprocs.nim @@ -69,23 +69,19 @@ proc addExitProc*(cl: proc() {.noconv.}) = fun() gFuns.add Fun(kind: kNoconv, fun2: cl) -when not defined(nimscript): +when not defined(nimscript) and (not defined(js) or defined(nodejs)): proc getProgramResult*(): int = when defined(js) and defined(nodejs): asm """ `result` = process.exitCode; """ - elif not defined(js): - result = programResult else: - doAssert false + result = programResult proc setProgramResult*(a: int) = when defined(js) and defined(nodejs): asm """ process.exitCode = `a`; """ - elif not defined(js): - programResult = a else: - doAssert false + programResult = a From cb3f6fdc6665298ec2b75ade95ac7bc9af5a5f66 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 24 May 2023 12:55:48 -0300 Subject: [PATCH 125/489] Improve times (#21901) * . * Improve times --- lib/pure/times.nim | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index ae101bc343..61971ba3a1 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -422,7 +422,7 @@ else: # Still track when using older versions {.pragma: parseFormatRaises, raises: [TimeParseError, TimeFormatParseError, Defect].} {.pragma: parseRaises, raises: [TimeParseError, Defect].} - + # # Helper procs @@ -608,8 +608,8 @@ proc stringifyUnit(value: int | int64, unit: TimeUnit): string = ## Stringify time unit with it's name, lowercased let strUnit = $unit result = "" - result.add($value) - result.add(" ") + result.addInt value + result.add ' ' if abs(value) != 1: result.add(strUnit.toLowerAscii()) else: @@ -1502,16 +1502,25 @@ proc getDateStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} runnableExamples: echo getDateStr(now() - 1.months) assertDateTimeInitialized dt - result = $dt.year & '-' & intToStr(dt.monthZero, 2) & - '-' & intToStr(dt.monthday, 2) + result = newStringOfCap(10) # len("YYYY-MM-DD") == 10 + result.addInt dt.year + result.add '-' + result.add intToStr(dt.monthZero, 2) + result.add '-' + result.add intToStr(dt.monthday, 2) proc getClockStr*(dt = now()): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = ## Gets the current local clock time as a string of the format `HH:mm:ss`. runnableExamples: echo getClockStr(now() - 1.hours) assertDateTimeInitialized dt - result = intToStr(dt.hour, 2) & ':' & intToStr(dt.minute, 2) & - ':' & intToStr(dt.second, 2) + result = newStringOfCap(8) # len("HH:mm:ss") == 8 + result.add intToStr(dt.hour, 2) + result.add ':' + result.add intToStr(dt.minute, 2) + result.add ':' + result.add intToStr(dt.second, 2) + # # Iso week @@ -2154,19 +2163,19 @@ proc toDateTimeByWeek(p: ParsedTime, zone: Timezone, f: TimeFormat, var isoyear = p.isoyear.get(0) var yearweek = p.yearweek.get(1) var weekday = p.weekday.get(dMon) - + if p.amPm != apUnknown: raiseParseException(f, input, "Parsing iso weekyear dates does not support am/pm") - + if p.year.isSome: raiseParseException(f, input, "Use iso-year GG or GGGG as year with iso week number") - + if p.month.isSome: raiseParseException(f, input, "Use either iso week number V or VV or month") - + if p.monthday.isSome: raiseParseException(f, input, "Use weekday ddd or dddd as day with with iso week number") - + if p.isoyear.isNone: raiseParseException(f, input, "Need iso-year with week number") From 446e5fbbb3941820847ad209576493a73d78bb61 Mon Sep 17 00:00:00 2001 From: metagn Date: Wed, 24 May 2023 21:39:40 +0300 Subject: [PATCH 126/489] when T is both a type symbol and a routine symbol in scope of a generic proc do not account for the type symbol when doing `a.T()` (#21899) fix #21883 --- compiler/semgnrc.nim | 10 ++++++---- tests/generics/mdotlookup.nim | 3 +++ tests/generics/timports.nim | 6 ++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 7dec8a30df..44f3969962 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -138,7 +138,8 @@ proc newDot(n, b: PNode): PNode = result.add(b) proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var GenericCtx; isMacro: var bool): PNode = + ctx: var GenericCtx; isMacro: var bool; + inCall = false): PNode = assert n.kind == nkDotExpr semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody) @@ -152,8 +153,9 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, result = n let n = n[1] let ident = considerQuotedIdent(c, n) - var candidates = searchInScopesFilterBy(c, ident, routineKinds+{skType}) - # skType here because could be type conversion + # could be type conversion if like a.T and not a.T() + let symKinds = if inCall: routineKinds else: routineKinds+{skType} + var candidates = searchInScopesFilterBy(c, ident, symKinds) if candidates.len > 0: let s = candidates[0] # XXX take into account the other candidates! isMacro = s.kind in {skTemplate, skMacro} @@ -281,7 +283,7 @@ proc semGenericStmt(c: PContext, n: PNode, onUse(fn.info, s) first = 1 elif fn.kind == nkDotExpr: - result[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext) + result[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext, inCall = true) first = 1 # Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)' # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim index 215f75003e..090b97771e 100644 --- a/tests/generics/mdotlookup.nim +++ b/tests/generics/mdotlookup.nim @@ -23,3 +23,6 @@ proc doStrip*[T](a: T): string = type Foo = int32 proc baz2*[T](y: int): auto = result = y.Foo + +proc set*(x: var int, a, b: string) = + x = a.len + b.len diff --git a/tests/generics/timports.nim b/tests/generics/timports.nim index df830c1f0e..43f096664e 100644 --- a/tests/generics/timports.nim +++ b/tests/generics/timports.nim @@ -40,6 +40,12 @@ block tdotlookup: doAssert doStrip(123) == "123" # bug #14254 doAssert baz2[float](1'i8) == 1 + # bug #21883 + proc abc[T: not not int](x: T): T = + var x = x + x.set("hello", "world") + result = x + doAssert abc(5) == 10 block tmodule_same_as_proc: # bug #1965 From b7925bf5c937bf3cb71290949d279872c4d0cb8e Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Thu, 25 May 2023 02:06:31 -0300 Subject: [PATCH 127/489] Remove GC (#21904) * . * Remove GC v2 --- lib/system/gc2.nim | 749 --------------------------------------------- 1 file changed, 749 deletions(-) delete mode 100644 lib/system/gc2.nim diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim deleted file mode 100644 index ed046b5fd9..0000000000 --- a/lib/system/gc2.nim +++ /dev/null @@ -1,749 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2017 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -# xxx deadcode, consider removing unless something could be reused. - - -# Garbage Collector -# -# The basic algorithm is an incremental mark -# and sweep GC to free cycles. It is hard realtime in that if you play -# according to its rules, no deadline will ever be missed. -# Since this kind of collector is very bad at recycling dead objects -# early, Nim's codegen emits ``nimEscape`` calls at strategic -# places. For this to work even 'unsureAsgnRef' needs to mark things -# so that only return values need to be considered in ``nimEscape``. - -{.push profiler:off.} - -const - CycleIncrease = 2 # is a multiplicative increase - InitialCycleThreshold = 512*1024 # start collecting after 500KB - ZctThreshold = 500 # we collect garbage if the ZCT's size - # reaches this threshold - # this seems to be a good value - withRealTime = defined(useRealtimeGC) - -when withRealTime and not declared(getTicks): - include "system/timers" -when defined(memProfiler): - proc nimProfile(requestedSize: int) {.benign.} - -when hasThreadSupport: - include sharedlist - -type - ObjectSpaceIter = object - state: range[-1..0] - -iterToProc(allObjects, ptr ObjectSpaceIter, allObjectsAsProc) - -const - escapedBit = 0b1000 # so that lowest 3 bits are not touched - rcBlackOrig = 0b000 - rcWhiteOrig = 0b001 - rcGrey = 0b010 # traditional color for incremental mark&sweep - rcUnused = 0b011 - colorMask = 0b011 -type - WalkOp = enum - waMarkGlobal, # part of the backup mark&sweep - waMarkGrey, - waZctDecRef, - waDebug - - Phase {.pure.} = enum - None, Marking, Sweeping - Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.} - # A ref type can have a finalizer that is called before the object's - # storage is freed. - - GcStat = object - stackScans: int # number of performed stack scans (for statistics) - completedCollections: int # number of performed full collections - maxThreshold: int # max threshold that has been set - maxStackSize: int # max stack size - maxStackCells: int # max stack cells in ``decStack`` - cycleTableSize: int # max entries in cycle table - maxPause: int64 # max measured GC pause in nanoseconds - - GcStack {.final, pure.} = object - when nimCoroutines: - prev: ptr GcStack - next: ptr GcStack - maxStackSize: int # Used to track statistics because we can not use - # GcStat.maxStackSize when multiple stacks exist. - bottom: pointer - - when withRealTime or nimCoroutines: - pos: pointer # Used with `withRealTime` only for code clarity, see GC_Step(). - when withRealTime: - bottomSaved: pointer - - GcHeap = object # this contains the zero count and - # non-zero count table - black, red: int # either 0 or 1. - stack: GcStack - when nimCoroutines: - activeStack: ptr GcStack # current executing coroutine stack. - phase: Phase - cycleThreshold: int - when useCellIds: - idGenerator: int - greyStack: CellSeq - recGcLock: int # prevent recursion via finalizers; no thread lock - when withRealTime: - maxPause: Nanos # max allowed pause in nanoseconds; active if > 0 - region: MemRegion # garbage collected region - stat: GcStat - additionalRoots: CellSeq # explicit roots for GC_ref/unref - spaceIter: ObjectSpaceIter - pDumpHeapFile: pointer # File that is used for GC_dumpHeap - when hasThreadSupport: - toDispose: SharedList[pointer] - gcThreadId: int - -var - gch {.rtlThreadVar.}: GcHeap - -when not defined(useNimRtl): - instantiateForRegion(gch.region) - -# Which color to use for new objects is tricky: When we're marking, -# they have to be *white* so that everything is marked that is only -# reachable from them. However, when we are sweeping, they have to -# be black, so that we don't free them prematuredly. In order to save -# a comparison gch.phase == Phase.Marking, we use the pseudo-color -# 'red' for new objects. -template allocColor(): untyped = gch.red - -template gcAssert(cond: bool, msg: string) = - when defined(useGcAssert): - if not cond: - echo "[GCASSERT] ", msg - GC_disable() - writeStackTrace() - rawQuit 1 - -proc cellToUsr(cell: PCell): pointer {.inline.} = - # convert object (=pointer to refcount) to pointer to userdata - result = cast[pointer](cast[int](cell)+%ByteAddress(sizeof(Cell))) - -proc usrToCell(usr: pointer): PCell {.inline.} = - # convert pointer to userdata to object (=pointer to refcount) - result = cast[PCell](cast[int](usr)-%ByteAddress(sizeof(Cell))) - -proc extGetCellType(c: pointer): PNimType {.compilerproc.} = - # used for code generation concerning debugging - result = usrToCell(c).typ - -proc internRefcount(p: pointer): int {.exportc: "getRefcount".} = - result = 0 - -# this that has to equals zero, otherwise we have to round up UnitsPerPage: -when BitsPerPage mod (sizeof(int)*8) != 0: - {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".} - -template color(c): untyped = c.refCount and colorMask -template setColor(c, col) = - c.refcount = c.refcount and not colorMask or col - -template markAsEscaped(c: PCell) = - c.refcount = c.refcount or escapedBit - -template didEscape(c: PCell): bool = - (c.refCount and escapedBit) != 0 - -proc writeCell(file: File; msg: cstring, c: PCell) = - var kind = -1 - if c.typ != nil: kind = ord(c.typ.kind) - let col = if c.color == rcGrey: 'g' - elif c.color == gch.black: 'b' - else: 'w' - when useCellIds: - let id = c.id - else: - let id = c - when defined(nimTypeNames): - c_fprintf(file, "%s %p %d escaped=%ld color=%c of type %s\n", - msg, id, kind, didEscape(c), col, c.typ.name) - elif leakDetector: - c_fprintf(file, "%s %p %d escaped=%ld color=%c from %s(%ld)\n", - msg, id, kind, didEscape(c), col, c.filename, c.line) - else: - c_fprintf(file, "%s %p %d escaped=%ld color=%c\n", - msg, id, kind, didEscape(c), col) - -proc writeCell(msg: cstring, c: PCell) = - stdout.writeCell(msg, c) - -proc myastToStr[T](x: T): string {.magic: "AstToStr", noSideEffect.} - -template gcTrace(cell, state: untyped) = - when traceGC: writeCell(myastToStr(state), cell) - -# forward declarations: -proc collectCT(gch: var GcHeap) {.benign.} -proc isOnStack(p: pointer): bool {.noinline, benign.} -proc forAllChildren(cell: PCell, op: WalkOp) {.benign.} -proc doOperation(p: pointer, op: WalkOp) {.benign.} -proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.} -# we need the prototype here for debugging purposes - -proc nimGCref(p: pointer) {.compilerproc.} = - let cell = usrToCell(p) - markAsEscaped(cell) - add(gch.additionalRoots, cell) - -proc nimGCunref(p: pointer) {.compilerproc.} = - let cell = usrToCell(p) - var L = gch.additionalRoots.len-1 - var i = L - let d = gch.additionalRoots.d - while i >= 0: - if d[i] == cell: - d[i] = d[L] - dec gch.additionalRoots.len - break - dec(i) - -proc nimGCunrefNoCycle(p: pointer) {.compilerproc, inline.} = - discard "can we do some freeing here?" - -proc nimGCunrefRC1(p: pointer) {.compilerproc, inline.} = - discard "can we do some freeing here?" - -template markGrey(x: PCell) = - if x.color != 1-gch.black and gch.phase == Phase.Marking: - if not isAllocatedPtr(gch.region, x): - c_fprintf(stdout, "[GC] markGrey proc: %p\n", x) - #GC_dumpHeap() - sysAssert(false, "wtf") - x.setColor(rcGrey) - add(gch.greyStack, x) - -proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} = - # the code generator calls this proc! - gcAssert(not isOnStack(dest), "asgnRef") - # BUGFIX: first incRef then decRef! - if src != nil: - let s = usrToCell(src) - markAsEscaped(s) - markGrey(s) - dest[] = src - -proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline, - deprecated: "old compiler compat".} = asgnRef(dest, src) - -proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc.} = - # unsureAsgnRef marks 'src' as grey only if dest is not on the - # stack. It is used by the code generator if it cannot decide whether a - # reference is in the stack or not (this can happen for var parameters). - if src != nil: - let s = usrToCell(src) - markAsEscaped(s) - if not isOnStack(dest): markGrey(s) - dest[] = src - -proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = - var d = cast[int](dest) - case n.kind - of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op) - of nkList: - for i in 0..n.len-1: - forAllSlotsAux(dest, n.sons[i], op) - of nkCase: - var m = selectBranch(dest, n) - if m != nil: forAllSlotsAux(dest, m, op) - of nkNone: sysAssert(false, "forAllSlotsAux") - -proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) = - var d = cast[int](dest) - if dest == nil: return # nothing to do - if ntfNoRefs notin mt.flags: - case mt.kind - of tyRef, tyString, tySequence: # leaf: - doOperation(cast[PPointer](d)[], op) - of tyObject, tyTuple: - forAllSlotsAux(dest, mt.node, op) - of tyArray, tyArrayConstr, tyOpenArray: - for i in 0..(mt.size div mt.base.size)-1: - forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op) - else: discard - -proc forAllChildren(cell: PCell, op: WalkOp) = - gcAssert(cell != nil, "forAllChildren: 1") - gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2") - gcAssert(cell.typ != nil, "forAllChildren: 3") - gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 4" - let marker = cell.typ.marker - if marker != nil: - marker(cellToUsr(cell), op.int) - else: - case cell.typ.kind - of tyRef: # common case - forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) - of tySequence: - var d = cast[int](cellToUsr(cell)) - var s = cast[PGenericSeq](d) - if s != nil: - for i in 0..s.len-1: - forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op) - else: discard - -{.push stackTrace: off, profiler:off.} -proc gcInvariant*() = - sysAssert(allocInv(gch.region), "injected") - when declared(markForDebug): - markForDebug(gch) -{.pop.} - -include gc_common - -proc initGC() = - when not defined(useNimRtl): - gch.red = (1-gch.black) - gch.cycleThreshold = InitialCycleThreshold - gch.stat.stackScans = 0 - gch.stat.completedCollections = 0 - gch.stat.maxThreshold = 0 - gch.stat.maxStackSize = 0 - gch.stat.maxStackCells = 0 - gch.stat.cycleTableSize = 0 - # init the rt - init(gch.additionalRoots) - init(gch.greyStack) - when hasThreadSupport: - init(gch.toDispose) - gch.gcThreadId = atomicInc(gHeapidGenerator) - 1 - gcAssert(gch.gcThreadId >= 0, "invalid computed thread ID") - -proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = - # generates a new object and sets its reference counter to 0 - sysAssert(allocInv(gch.region), "rawNewObj begin") - gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") - collectCT(gch) - var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell))) - gcAssert((cast[int](res) and (MemAlign-1)) == 0, "newObj: 2") - # now it is buffered in the ZCT - res.typ = typ - when leakDetector and not hasThreadSupport: - if framePtr != nil and framePtr.prev != nil: - res.filename = framePtr.prev.filename - res.line = framePtr.prev.line - # refcount is zero, color is black, but mark it to be in the ZCT - res.refcount = allocColor() - sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3") - when logGC: writeCell("new cell", res) - gcTrace(res, csAllocated) - when useCellIds: - inc gch.idGenerator - res.id = gch.idGenerator - result = cellToUsr(res) - sysAssert(allocInv(gch.region), "rawNewObj end") - -{.pop.} - -proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} = - result = rawNewObj(typ, size, gch) - when defined(memProfiler): nimProfile(size) - -proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} = - result = rawNewObj(typ, size, gch) - zeroMem(result, size) - when defined(memProfiler): nimProfile(size) - -proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} = - # `newObj` already uses locks, so no need for them here. - let size = addInt(align(GenericSeqSize, typ.base.align), mulInt(len, typ.base.size)) - result = newObj(typ, size) - cast[PGenericSeq](result).len = len - cast[PGenericSeq](result).reserved = len - when defined(memProfiler): nimProfile(size) - -proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = - result = newObj(typ, size) - -proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = - result = newSeq(typ, len) - -proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer = - collectCT(gch) - var ol = usrToCell(old) - sysAssert(ol.typ != nil, "growObj: 1") - gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2") - - var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell))) - var elemSize, elemAlign = 1 - if ol.typ.kind != tyString: - elemSize = ol.typ.base.size - elemAlign = ol.typ.base.align - incTypeSize ol.typ, newsize - - var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len*elemSize - copyMem(res, ol, oldsize + sizeof(Cell)) - zeroMem(cast[pointer](cast[int](res)+% oldsize +% sizeof(Cell)), - newsize-oldsize) - sysAssert((cast[int](res) and (MemAlign-1)) == 0, "growObj: 3") - when false: - # this is wrong since seqs can be shared via 'shallow': - when reallyDealloc: rawDealloc(gch.region, ol) - else: - zeroMem(ol, sizeof(Cell)) - when useCellIds: - inc gch.idGenerator - res.id = gch.idGenerator - result = cellToUsr(res) - when defined(memProfiler): nimProfile(newsize-oldsize) - -proc growObj(old: pointer, newsize: int): pointer {.rtl.} = - result = growObj(old, newsize, gch) - -{.push profiler:off.} - - -template takeStartTime(workPackageSize) {.dirty.} = - const workPackage = workPackageSize - var debugticker = 1000 - when withRealTime: - var steps = workPackage - var t0: Ticks - if gch.maxPause > 0: t0 = getticks() - -template takeTime {.dirty.} = - when withRealTime: dec steps - dec debugticker - -template checkTime {.dirty.} = - if debugticker <= 0: - #echo "in loop" - debugticker = 1000 - when withRealTime: - if steps == 0: - steps = workPackage - if gch.maxPause > 0: - let duration = getticks() - t0 - # the GC's measuring is not accurate and needs some cleanup actions - # (stack unmarking), so subtract some short amount of time in - # order to miss deadlines less often: - if duration >= gch.maxPause - 50_000: - return false - -# ---------------- dump heap ---------------- - -template dumpHeapFile(gch: var GcHeap): File = - cast[File](gch.pDumpHeapFile) - -proc debugGraph(s: PCell) = - c_fprintf(gch.dumpHeapFile, "child %p\n", s) - -proc dumpRoot(gch: var GcHeap; s: PCell) = - if isAllocatedPtr(gch.region, s): - c_fprintf(gch.dumpHeapFile, "global_root %p\n", s) - else: - c_fprintf(gch.dumpHeapFile, "global_root_invalid %p\n", s) - -proc GC_dumpHeap*(file: File) = - ## Dumps the GCed heap's content to a file. Can be useful for - ## debugging. Produces an undocumented text file format that - ## can be translated into "dot" syntax via the "heapdump2dot" tool. - gch.pDumpHeapFile = file - var spaceIter: ObjectSpaceIter - when false: - var d = gch.decStack.d - for i in 0 .. gch.decStack.len-1: - if isAllocatedPtr(gch.region, d[i]): - c_fprintf(file, "onstack %p\n", d[i]) - else: - c_fprintf(file, "onstack_invalid %p\n", d[i]) - if gch.gcThreadId == 0: - for i in 0 .. globalMarkersLen-1: globalMarkers[i]() - for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]() - while true: - let x = allObjectsAsProc(gch.region, addr spaceIter) - if spaceIter.state < 0: break - if isCell(x): - # cast to PCell is correct here: - var c = cast[PCell](x) - writeCell(file, "cell ", c) - forAllChildren(c, waDebug) - c_fprintf(file, "end\n") - gch.pDumpHeapFile = nil - -proc GC_dumpHeap() = - var f: File - if open(f, "heap.txt", fmWrite): - GC_dumpHeap(f) - f.close() - else: - c_fprintf(stdout, "cannot write heap.txt") - -# ---------------- cycle collector ------------------------------------------- - -proc freeCyclicCell(gch: var GcHeap, c: PCell) = - gcAssert(isAllocatedPtr(gch.region, c), "freeCyclicCell: freed pointer?") - prepareDealloc(c) - gcTrace(c, csCycFreed) - when logGC: writeCell("cycle collector dealloc cell", c) - when reallyDealloc: - sysAssert(allocInv(gch.region), "free cyclic cell") - rawDealloc(gch.region, c) - else: - gcAssert(c.typ != nil, "freeCyclicCell") - zeroMem(c, sizeof(Cell)) - -proc sweep(gch: var GcHeap): bool = - takeStartTime(100) - #echo "loop start" - let white = 1-gch.black - #c_fprintf(stdout, "black is %d\n", black) - while true: - let x = allObjectsAsProc(gch.region, addr gch.spaceIter) - if gch.spaceIter.state < 0: break - takeTime() - if isCell(x): - # cast to PCell is correct here: - var c = cast[PCell](x) - gcAssert c.color != rcGrey, "cell is still grey?" - if c.color == white: freeCyclicCell(gch, c) - # Since this is incremental, we MUST not set the object to 'white' here. - # We could set all the remaining objects to white after the 'sweep' - # completed but instead we flip the meaning of black/white to save one - # traversal over the heap! - checkTime() - # prepare for next iteration: - #echo "loop end" - gch.spaceIter = ObjectSpaceIter() - result = true - -proc markRoot(gch: var GcHeap, c: PCell) {.inline.} = - if c.color == 1-gch.black: - c.setColor(rcGrey) - add(gch.greyStack, c) - -proc markIncremental(gch: var GcHeap): bool = - var L = addr(gch.greyStack.len) - takeStartTime(100) - while L[] > 0: - var c = gch.greyStack.d[0] - if not isAllocatedPtr(gch.region, c): - c_fprintf(stdout, "[GC] not allocated anymore: %p\n", c) - #GC_dumpHeap() - sysAssert(false, "wtf") - - #sysAssert(isAllocatedPtr(gch.region, c), "markIncremental: isAllocatedPtr") - gch.greyStack.d[0] = gch.greyStack.d[L[] - 1] - dec(L[]) - takeTime() - if c.color == rcGrey: - c.setColor(gch.black) - forAllChildren(c, waMarkGrey) - elif c.color == (1-gch.black): - gcAssert false, "wtf why are there white objects in the greystack?" - checkTime() - gcAssert gch.greyStack.len == 0, "markIncremental: greystack not empty " - result = true - -proc markGlobals(gch: var GcHeap) = - if gch.gcThreadId == 0: - for i in 0 .. globalMarkersLen-1: globalMarkers[i]() - for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]() - -proc doOperation(p: pointer, op: WalkOp) = - if p == nil: return - var c: PCell = usrToCell(p) - gcAssert(c != nil, "doOperation: 1") - # the 'case' should be faster than function pointers because of easy - # prediction: - case op - of waZctDecRef: - #if not isAllocatedPtr(gch.region, c): - # c_fprintf(stdout, "[GC] decref bug: %p", c) - gcAssert(isAllocatedPtr(gch.region, c), "decRef: waZctDecRef") - discard "use me for nimEscape?" - of waMarkGlobal: - template handleRoot = - if gch.dumpHeapFile.isNil: - markRoot(gch, c) - else: - dumpRoot(gch, c) - handleRoot() - discard allocInv(gch.region) - of waMarkGrey: - when false: - if not isAllocatedPtr(gch.region, c): - c_fprintf(stdout, "[GC] not allocated anymore: MarkGrey %p\n", c) - #GC_dumpHeap() - sysAssert(false, "wtf") - if c.color == 1-gch.black: - c.setColor(rcGrey) - add(gch.greyStack, c) - of waDebug: debugGraph(c) - -proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = - doOperation(d, WalkOp(op)) - -proc gcMark(gch: var GcHeap, p: pointer) {.inline.} = - # the addresses are not as cells on the stack, so turn them to cells: - sysAssert(allocInv(gch.region), "gcMark begin") - var cell = usrToCell(p) - var c = cast[int](cell) - if c >% PageSize: - # fast check: does it look like a cell? - var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell)) - if objStart != nil: - # mark the cell: - markRoot(gch, objStart) - sysAssert(allocInv(gch.region), "gcMark end") - -proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} = - forEachStackSlot(gch, gcMark) - -proc collectALittle(gch: var GcHeap): bool = - case gch.phase - of Phase.None: - if getOccupiedMem(gch.region) >= gch.cycleThreshold: - gch.phase = Phase.Marking - markGlobals(gch) - result = collectALittle(gch) - #when false: c_fprintf(stdout, "collectALittle: introduced bug E %ld\n", gch.phase) - #discard allocInv(gch.region) - of Phase.Marking: - when hasThreadSupport: - for c in gch.toDispose: - nimGCunref(c) - prepareForInteriorPointerChecking(gch.region) - markStackAndRegisters(gch) - inc(gch.stat.stackScans) - if markIncremental(gch): - gch.phase = Phase.Sweeping - gch.red = 1 - gch.red - of Phase.Sweeping: - gcAssert gch.greyStack.len == 0, "greystack not empty" - when hasThreadSupport: - for c in gch.toDispose: - nimGCunref(c) - if sweep(gch): - gch.phase = Phase.None - # flip black/white meanings: - gch.black = 1 - gch.black - gcAssert gch.red == 1 - gch.black, "red color is wrong" - inc(gch.stat.completedCollections) - result = true - -proc collectCTBody(gch: var GcHeap) = - when withRealTime: - let t0 = getticks() - sysAssert(allocInv(gch.region), "collectCT: begin") - - when not nimCoroutines: - gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize()) - #gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len) - if collectALittle(gch): - gch.cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() * - CycleIncrease) - gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold) - sysAssert(allocInv(gch.region), "collectCT: end") - when withRealTime: - let duration = getticks() - t0 - gch.stat.maxPause = max(gch.stat.maxPause, duration) - when defined(reportMissedDeadlines): - if gch.maxPause > 0 and duration > gch.maxPause: - c_fprintf(stdout, "[GC] missed deadline: %ld\n", duration) - -when nimCoroutines: - proc currentStackSizes(): int = - for stack in items(gch.stack): - result = result + stack.stackSize() - -proc collectCT(gch: var GcHeap) = - # stackMarkCosts prevents some pathological behaviour: Stack marking - # becomes more expensive with large stacks and large stacks mean that - # cells with RC=0 are more likely to be kept alive by the stack. - when nimCoroutines: - let stackMarkCosts = max(currentStackSizes() div (16*sizeof(int)), ZctThreshold) - else: - let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold) - if (gch.greyStack.len >= stackMarkCosts or (cycleGC and - getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and - gch.recGcLock == 0: - collectCTBody(gch) - -when withRealTime: - proc toNano(x: int): Nanos {.inline.} = - result = x * 1000 - - proc GC_setMaxPause*(MaxPauseInUs: int) = - gch.maxPause = MaxPauseInUs.toNano - - proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) = - gch.maxPause = us.toNano - #if (getOccupiedMem(gch.region)>=gch.cycleThreshold) or - # alwaysGC or strongAdvice: - collectCTBody(gch) - - proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} = - if stackSize >= 0: - var stackTop {.volatile.}: pointer - gch.getActiveStack().pos = addr(stackTop) - - for stack in gch.stack.items(): - stack.bottomSaved = stack.bottom - when stackIncreases: - stack.bottom = cast[pointer]( - cast[int](stack.pos) - sizeof(pointer) * 6 - stackSize) - else: - stack.bottom = cast[pointer]( - cast[int](stack.pos) + sizeof(pointer) * 6 + stackSize) - - GC_step(gch, us, strongAdvice) - - if stackSize >= 0: - for stack in gch.stack.items(): - stack.bottom = stack.bottomSaved - -when not defined(useNimRtl): - proc GC_disable() = - inc(gch.recGcLock) - proc GC_enable() = - if gch.recGcLock > 0: - dec(gch.recGcLock) - - proc GC_setStrategy(strategy: GC_Strategy) = - discard - - proc GC_enableMarkAndSweep() = discard - proc GC_disableMarkAndSweep() = discard - - proc GC_fullCollect() = - var oldThreshold = gch.cycleThreshold - gch.cycleThreshold = 0 # forces cycle collection - collectCT(gch) - gch.cycleThreshold = oldThreshold - - proc GC_getStatistics(): string = - GC_disable() - result = "[GC] total memory: " & $(getTotalMem()) & "\n" & - "[GC] occupied memory: " & $(getOccupiedMem()) & "\n" & - "[GC] stack scans: " & $gch.stat.stackScans & "\n" & - "[GC] stack cells: " & $gch.stat.maxStackCells & "\n" & - "[GC] completed collections: " & $gch.stat.completedCollections & "\n" & - "[GC] max threshold: " & $gch.stat.maxThreshold & "\n" & - "[GC] grey stack capacity: " & $gch.greyStack.cap & "\n" & - "[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" & - "[GC] max pause time [ms]: " & $(gch.stat.maxPause div 1000_000) & "\n" - when nimCoroutines: - result.add "[GC] number of stacks: " & $gch.stack.len & "\n" - for stack in items(gch.stack): - result.add "[GC] stack " & stack.bottom.repr & "[GC] max stack size " & $stack.maxStackSize & "\n" - else: - result.add "[GC] max stack size: " & $gch.stat.maxStackSize & "\n" - GC_enable() - -{.pop.} From a8718d8a9e1aba7df55b1a3df1ce48a3f4f62bff Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Thu, 25 May 2023 15:08:36 +1000 Subject: [PATCH 128/489] Fix const in async regression (#21898) * Add test case for a const being used inside an async proc * Use `typeof` to get the type of the block instead of overloaded templates This removes the problem with the symbol having different types I am unsure why I didn't use this in the first place. IIRC I had problems with `typeof` when I first tried to use it in the original implementation --- lib/pure/asyncmacro.nim | 12 +++++------- tests/async/t21893.nim | 13 +++++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 tests/async/t21893.nim diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index d80a471017..e41568b8c1 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -221,13 +221,11 @@ proc asyncSingleProc(prc: NimNode): NimNode = procBody = newStmtList() let resultIdent = ident"result" procBody.add quote do: - template nimAsyncDispatchSetResult(x: `subRetType`) {.used.} = - # If the proc has implicit return then this will get called - `resultIdent` = x - template nimAsyncDispatchSetResult(x: untyped) {.used.} = - # If the proc doesn't have implicit return then this will get called - x - procBody.add newCall(ident"nimAsyncDispatchSetResult", blockStmt) + # Check whether there is an implicit return + when typeof(`blockStmt`) is void: + `blockStmt` + else: + `resultIdent` = `blockStmt` procBody.add(createFutureVarCompletions(futureVarIdents, nil)) procBody.insert(0): quote do: {.push warning[resultshadowed]: off.} diff --git a/tests/async/t21893.nim b/tests/async/t21893.nim new file mode 100644 index 0000000000..658cb02ebc --- /dev/null +++ b/tests/async/t21893.nim @@ -0,0 +1,13 @@ +discard """ +output: "@[97]\ntrue" +""" + +import asyncdispatch + +proc test(): Future[bool] {.async.} = + const S4 = @[byte('a')] + echo S4 + return true + +echo waitFor test() + From 0eb508e43405662eaddf113aba171119623d6bdb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 25 May 2023 22:23:07 +0200 Subject: [PATCH 129/489] atlas: better docs (#21911) * atlas: better docs * better workspace/project handling * make tests green again * bugfix --- tools/atlas/atlas.md | 72 +++++++++++++------ tools/atlas/atlas.nim | 160 ++++++++++++++++++++++++++++-------------- 2 files changed, 156 insertions(+), 76 deletions(-) diff --git a/tools/atlas/atlas.md b/tools/atlas/atlas.md index 40cf6411e8..c898bc00e9 100644 --- a/tools/atlas/atlas.md +++ b/tools/atlas/atlas.md @@ -7,6 +7,55 @@ Atlas is compatible with Nimble in the sense that it supports the Nimble file format. +## Concepts + +Atlas uses three concepts: + +1. Workspaces +2. Projects +3. Dependencies + +### Workspaces + +Every workspace is isolated, nothing is shared between workspaces. +A workspace is a directory that has a file `atlas.workspace` inside it. If `atlas` +is run on a (sub-)directory that is not within a workspace, a workspace is created +automatically for you. Atlas picks the current directory or one of its parent directories +that has no `.git` subdirectory inside it as its workspace. + +Thanks to this setup, it's easy to develop multiple projects at the same time. + +A project plus its dependencies are stored in a workspace: + + $workspace / main project + $workspace / _deps / dependency A + $workspace / _deps / dependency B + +The deps directory can be set via `--deps:DIR` explicitly. It defaults to `_deps`. +If you want it to be the same as the workspace use `--deps:.`. + + +### Projects + +A workspace contains one or multiple "projects". These projects can use each other and it +is easy to develop multiple projects at the same time. + +### Dependencies + +Inside a workspace there can be a `_deps` directory where your dependencies are kept. It is +easy to move a dependency one level up and out the `_deps` directory, turning it into a project. +Likewise, you can move a project to the `_deps` directory, turning it into a dependency. + +The only distinction between a project and a dependency is its location. For dependency resolution +a project always has a higher priority than a dependency. + + +## No magic + +Atlas works by managing two files for you, the `project.nimble` file and the `nim.cfg` file. You can +edit these manually too, Atlas doesn't touch what should be left untouched. + + ## How it works Atlas uses git commits internally; version requirements are translated @@ -31,29 +80,6 @@ The version selection is deterministic, it picks up the *minimum* required version. Thanks to this design, lock files are much less important. -## Dependencies - -Dependencies are neither installed globally, nor locally into the current -project. Instead a "workspace" is used. The workspace is the nearest parent -directory of the current directory that does not contain a `.git` subdirectory. -Dependencies are managed as **siblings**, not as children. Dependencies are -kept as git repositories. - -Thanks to this setup, it's easy to develop multiple projects at the same time. - -A project plus its dependencies are stored in a workspace: - - $workspace / main project - $workspace / _deps / dependency A - $workspace / _deps / dependency B - -The deps directory can be set via `--deps:DIR` explicitly. It defaults to `_deps`. -If you want it to be the same as the workspace use `--deps:.`. - -You can move a dependency out of the `_deps` subdirectory into the workspace. -This can be convenient should you decide to work on a dependency too. You need to -patch the `nim.cfg` then. - ## Commands diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index ddfbbd0863..c3d942d22d 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -9,20 +9,26 @@ ## Simple tool to automate frequent workflows: Can "clone" ## a Nimble dependency and its dependencies recursively. -import std / [parseopt, strutils, os, osproc, tables, sets, json, jsonutils] +import std / [parseopt, strutils, os, osproc, tables, sets, json, jsonutils, + parsecfg, streams] import parse_requires, osutils, packagesjson from unicode import nil const - Version = "0.3" + Version = "0.4" LockFileName = "atlas.lock" + AtlasWorkspace = "atlas.workspace" Usage = "atlas - Nim Package Cloner Version " & Version & """ (c) 2021 Andreas Rumpf Usage: atlas [options] [command] [arguments] Command: + init initializes the current directory as a workspace + --deps=DIR use DIR as the directory for dependencies + (default: store directly in the workspace) + use url|pkgname clone a package and all of its dependencies and make it importable for the current project clone url|pkgname clone a package and all of its dependencies @@ -31,8 +37,11 @@ Command: search keyw keywB... search for package that contains the given keywords extract file.nimble extract the requirements and custom commands from the given Nimble file - updateWorkspace [filter] - update every package in the workspace that has a remote + updateProjects [filter] + update every project that has a remote + URL that matches `filter` if a filter is given + updateDeps [filter] + update every dependency that has a remote URL that matches `filter` if a filter is given build|test|doc|tasks currently delegates to `nimble build|test|doc` task currently delegates to `nimble ` @@ -42,9 +51,6 @@ Options: --cfgHere also create/maintain a nim.cfg in the current working directory --workspace=DIR use DIR as workspace - --deps=DIR store dependencies in DIR instead of the workspace - (if DIR is a relative path, it is interpreted to - be relative to the workspace) --genlock generate a lock file (use with `clone` and `update`) --uselock use the lock file for the build --version show the version @@ -323,11 +329,13 @@ proc commitFromLockFile(c: var AtlasContext; dir: string): string = else: error c, PackageName(d), "package is not listed in the lock file" -proc checkoutCommit(c: var AtlasContext; w: Dependency) = - var dir = c.workspace / w.name.string - if not dirExists(dir): - dir = c.depsDir / w.name.string +proc dependencyDir(c: AtlasContext; w: Dependency): string = + result = c.workspace / w.name.string + if not dirExists(result): + result = c.depsDir / w.name.string +proc checkoutCommit(c: var AtlasContext; w: Dependency) = + let dir = dependencyDir(c, w) withDir c, dir: if c.lockOption == genLock: genLockEntry(c, w, dir) @@ -369,10 +377,11 @@ proc findNimbleFile(c: AtlasContext; dep: Dependency): string = result = TestsDir / dep.name.string & ".nimble" doAssert fileExists(result), "file does not exist " & result else: - result = c.workspace / dep.name.string / (dep.name.string & ".nimble") + let dir = dependencyDir(c, dep) + result = dir / (dep.name.string & ".nimble") if not fileExists(result): result = "" - for x in walkFiles(c.workspace / dep.name.string / "*.nimble"): + for x in walkFiles(dir / "*.nimble"): if result.len == 0: result = x else: @@ -531,7 +540,7 @@ proc installDependencies(c: var AtlasContext; nimbleFile: string) = let paths = cloneLoop(c, work, startIsDep = true) patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c)) -proc updateWorkspace(c: var AtlasContext; dir, filter: string) = +proc updateDir(c: var AtlasContext; dir, filter: string) = for kind, file in walkDir(dir): if kind == pcDir and dirExists(file / ".git"): c.withDir file: @@ -617,6 +626,58 @@ proc patchNimbleFile(c: var AtlasContext; dep: string; deps: var seq[string]) = else: message(c, "[Info] ", toName(thisProject), "up to date: " & nimbleFile) +proc detectWorkspace(): string = + result = getCurrentDir() + while result.len > 0: + if fileExists(result / AtlasWorkspace): + return result + result = result.parentDir() + +proc absoluteDepsDir(workspace, value: string): string = + if value == ".": + result = workspace + elif isAbsolute(value): + result = value + else: + result = workspace / value + +when MockupRun: + proc autoWorkspace(): string = + result = getCurrentDir() + while result.len > 0 and dirExists(result / ".git"): + result = result.parentDir() + +proc createWorkspaceIn(workspace, depsDir: string) = + if not fileExists(workspace / AtlasWorkspace): + writeFile workspace / AtlasWorkspace, "deps=\"$#\"" % escape(depsDir, "", "") + createDir absoluteDepsDir(workspace, depsDir) + +proc readConfig(c: var AtlasContext) = + let configFile = c.workspace / AtlasWorkspace + var f = newFileStream(configFile, fmRead) + if f == nil: + error c, toName(configFile), "cannot open: " & configFile + return + var p: CfgParser + open(p, f, configFile) + while true: + var e = next(p) + case e.kind + of cfgEof: break + of cfgSectionStart: + discard "who cares about sections" + of cfgKeyValuePair: + case e.key.normalize + of "deps": + c.depsDir = absoluteDepsDir(c.workspace, e.value) + else: + warn c, toName(configFile), "ignored unknown setting: " & e.key + of cfgOption: + discard "who cares about options" + of cfgError: + error c, toName(configFile), e.msg + close(p) + proc main = var action = "" var args: seq[string] = @[] @@ -628,6 +689,11 @@ proc main = if args.len != 0: error action & " command takes no arguments" + template projectCmd() = + if getCurrentDir() == c.workspace or getCurrentDir() == c.depsDir: + error action & " command must be executed in a project, not in the workspace" + return + var c = AtlasContext( projectDir: getCurrentDir(), workspace: "") @@ -645,9 +711,13 @@ proc main = of "version", "v": writeVersion() of "keepcommits": c.keepCommits = true of "workspace": - if val.len > 0: + if val == ".": + c.workspace = getCurrentDir() + createWorkspaceIn c.workspace, c.depsDir + elif val.len > 0: c.workspace = val createDir(val) + createWorkspaceIn c.workspace, c.depsDir else: writeHelp() of "deps": @@ -671,28 +741,27 @@ proc main = if c.workspace.len > 0: if not dirExists(c.workspace): error "Workspace directory '" & c.workspace & "' not found." - else: - c.workspace = getCurrentDir() - while c.workspace.len > 0 and dirExists(c.workspace / ".git"): - c.workspace = c.workspace.parentDir() + elif action != "init": + when MockupRun: + c.workspace = autoWorkspace() + else: + c.workspace = detectWorkspace() + if c.workspace.len > 0: + readConfig c + else: + error "No workspace found. Run `atlas init` if you want this current directory to be your workspace." + return + echo "Using workspace ", c.workspace when MockupRun: c.depsDir = c.workspace - else: - if c.depsDir.len > 0: - if c.depsDir == ".": - c.depsDir = c.workspace - elif not isAbsolute(c.depsDir): - c.depsDir = c.workspace / c.depsDir - else: - c.depsDir = c.workspace / "_deps" - createDir(c.depsDir) - - echo "Using workspace ", c.workspace case action of "": error "No action." + of "init": + c.workspace = getCurrentDir() + createWorkspaceIn c.workspace, c.depsDir of "clone", "update": singleArg() let deps = clone(c, args[0], startIsDep = false) @@ -704,6 +773,7 @@ proc main = if c.errors > 0: error "There were problems." of "use": + projectCmd() singleArg() discard clone(c, args[0], startIsDep = true) var deps: seq[string] = @[] @@ -712,6 +782,7 @@ proc main = if c.errors > 0: error "There were problems." of "install": + projectCmd() if args.len > 1: error "install command takes a single argument" var nimbleFile = "" @@ -730,9 +801,10 @@ proc main = of "search", "list": updatePackages(c) search getPackages(c.workspace), args - of "updateworkspace": - updateWorkspace(c, c.workspace, if args.len == 0: "" else: args[0]) - updateWorkspace(c, c.depsDir, if args.len == 0: "" else: args[0]) + of "updateprojects": + updateDir(c, c.workspace, if args.len == 0: "" else: args[0]) + of "updatedeps": + updateDir(c, c.depsDir, if args.len == 0: "" else: args[0]) of "extract": singleArg() if fileExists(args[0]): @@ -740,8 +812,10 @@ proc main = else: error "File does not exist: " & args[0] of "build", "test", "doc", "tasks": + projectCmd() nimbleExec(action, args) of "task": + projectCmd() nimbleExec("", args) else: error "Invalid action: " & action @@ -749,23 +823,3 @@ proc main = when isMainModule: main() -when false: - # some testing code for the `patchNimCfg` logic: - var c = AtlasContext( - projectDir: getCurrentDir(), - workspace: getCurrentDir().parentDir) - - patchNimCfg(c, @[PackageName"abc", PackageName"xyz"]) - -when false: - assert sameVersionAs("v0.2.0", "0.2.0") - assert sameVersionAs("v1", "1") - - assert sameVersionAs("1.90", "1.90") - - assert sameVersionAs("v1.2.3-zuzu", "1.2.3") - assert sameVersionAs("foo-1.2.3.4", "1.2.3.4") - - assert not sameVersionAs("foo-1.2.3.4", "1.2.3") - assert not sameVersionAs("foo", "1.2.3") - assert not sameVersionAs("", "1.2.3") From 609bf3d7c8bf880dea70f6e8211976f3ec1567a0 Mon Sep 17 00:00:00 2001 From: heterodoxic <122719743+heterodoxic@users.noreply.github.com> Date: Fri, 26 May 2023 03:20:56 +0200 Subject: [PATCH 130/489] fix #21501 by making --app:lib and --app:staticLib imply --noMain (#21910) --- compiler/cgen.nim | 12 +++++------- compiler/commands.nim | 2 ++ doc/backends.md | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 6ceda109f4..8c85db2f84 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1490,9 +1490,9 @@ proc genMainProc(m: BModule) = var posixCmdLine: Rope if optNoMain notin m.config.globalOptions: - posixCmdLine.add "\tN_LIB_PRIVATE int cmdCount;\L" - posixCmdLine.add "\tN_LIB_PRIVATE char** cmdLine;\L" - posixCmdLine.add "\tN_LIB_PRIVATE char** gEnv;\L" + posixCmdLine.add "N_LIB_PRIVATE int cmdCount;\L" + posixCmdLine.add "N_LIB_PRIVATE char** cmdLine;\L" + posixCmdLine.add "N_LIB_PRIVATE char** gEnv;\L" const # The use of a volatile function pointer to call Pre/NimMainInner @@ -1517,7 +1517,7 @@ proc genMainProc(m: BModule) = "}$N$N" MainProcs = - "\t\t$^NimMain();$N" + "\t$^NimMain();$N" MainProcsWithResult = MainProcs & ("\treturn $1nim_program_result;$N") @@ -1633,7 +1633,7 @@ proc genMainProc(m: BModule) = appcg(m, m.s[cfsProcs], nimMain, [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) - if optNoMain notin m.config.globalOptions: + if optNoMain notin m.config.globalOptions or optGenDynLib in m.config.globalOptions: if m.config.cppCustomNamespace.len > 0: closeNamespaceNim(m.s[cfsProcs]) m.s[cfsProcs].add "using namespace " & m.config.cppCustomNamespace & ";\L" @@ -1940,8 +1940,6 @@ proc genModule(m: BModule, cfile: Cfile): Rope = openNamespaceNim(m.config.cppCustomNamespace, result) if m.s[cfsFrameDefines].len > 0: result.add(m.s[cfsFrameDefines]) - else: - result.add("#define nimfr_(x, y)\n#define nimln_(x)\n\n#define nimlf_(x, y)\n") for i in cfsForwardTypes..cfsProcs: if m.s[i].len > 0: diff --git a/compiler/commands.nim b/compiler/commands.nim index 4980ff2685..f881a4f576 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -799,11 +799,13 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "consoleapp") of "lib": incl(conf.globalOptions, optGenDynLib) + incl(conf.globalOptions, optNoMain) excl(conf.globalOptions, optGenGuiApp) defineSymbol(conf.symbols, "library") defineSymbol(conf.symbols, "dll") of "staticlib": incl(conf.globalOptions, optGenStaticLib) + incl(conf.globalOptions, optNoMain) excl(conf.globalOptions, optGenGuiApp) defineSymbol(conf.symbols, "library") defineSymbol(conf.symbols, "staticlib") diff --git a/doc/backends.md b/doc/backends.md index 5258e9b4dc..27b6548907 100644 --- a/doc/backends.md +++ b/doc/backends.md @@ -300,7 +300,7 @@ Instead of depending on the generation of the individual ``.c`` files you can also ask the Nim compiler to generate a statically linked library: ```cmd - nim c --app:staticLib --noMain fib.nim + nim c --app:staticLib fib.nim gcc -o m -Inimcache -Ipath/to/nim/lib maths.c libfib.nim.a ``` From 908e9717324f83225eff66982c8c9a94f64ad29b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 26 May 2023 09:24:01 +0200 Subject: [PATCH 131/489] Atlas: misc (#21919) * Atlas: misc * Atlas: use the lockfile if one exists --- tools/atlas/atlas.md | 14 +++++--------- tools/atlas/atlas.nim | 45 ++++++++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/tools/atlas/atlas.md b/tools/atlas/atlas.md index c898bc00e9..d0a45c866d 100644 --- a/tools/atlas/atlas.md +++ b/tools/atlas/atlas.md @@ -18,21 +18,17 @@ Atlas uses three concepts: ### Workspaces Every workspace is isolated, nothing is shared between workspaces. -A workspace is a directory that has a file `atlas.workspace` inside it. If `atlas` -is run on a (sub-)directory that is not within a workspace, a workspace is created -automatically for you. Atlas picks the current directory or one of its parent directories -that has no `.git` subdirectory inside it as its workspace. +A workspace is a directory that has a file `atlas.workspace` inside it. Use `atlas init` +to create a workspace out of the current working directory. -Thanks to this setup, it's easy to develop multiple projects at the same time. - -A project plus its dependencies are stored in a workspace: +Projects plus their dependencies are stored in a workspace: $workspace / main project + $workspace / other project $workspace / _deps / dependency A $workspace / _deps / dependency B -The deps directory can be set via `--deps:DIR` explicitly. It defaults to `_deps`. -If you want it to be the same as the workspace use `--deps:.`. +The deps directory can be set via `--deps:DIR` during `atlas init`. ### Projects diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index c3d942d22d..d455fd676e 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -389,23 +389,43 @@ proc findNimbleFile(c: AtlasContext; dep: Dependency): string = return "" proc addUniqueDep(c: var AtlasContext; work: var seq[Dependency]; - tokens: seq[string]) = + tokens: seq[string]; lockfile: Table[string, LockFileEntry]) = + let pkgName = tokens[0] let oldErrors = c.errors - let url = toUrl(c, tokens[0]) + let url = toUrl(c, pkgName) if oldErrors != c.errors: - warn c, toName(tokens[0]), "cannot resolve package name" + warn c, toName(pkgName), "cannot resolve package name" elif not c.processed.containsOrIncl(url / tokens[2]): - work.add Dependency(name: toName(tokens[0]), url: url, commit: tokens[2], - rel: toDepRelation(tokens[1])) + if lockfile.contains(pkgName): + work.add Dependency(name: toName(pkgName), + url: lockfile[pkgName].url, + commit: lockfile[pkgName].commit, + rel: normal) + else: + work.add Dependency(name: toName(pkgName), url: url, commit: tokens[2], + rel: toDepRelation(tokens[1])) template toDestDir(p: PackageName): string = p.string +proc readLockFile(filename: string): Table[string, LockFileEntry] = + let jsonAsStr = readFile(filename) + let jsonTree = parseJson(jsonAsStr) + let data = to(jsonTree, seq[LockFileEntry]) + result = initTable[string, LockFileEntry]() + for d in items(data): + result[d.dir] = d + proc collectDeps(c: var AtlasContext; work: var seq[Dependency]; dep: Dependency; nimbleFile: string): string = # If there is a .nimble file, return the dependency path & srcDir # else return "". assert nimbleFile != "" let nimbleInfo = extractRequiresInfo(c, nimbleFile) + + let lockFilePath = dependencyDir(c, dep) / LockFileName + let lockFile = if fileExists(lockFilePath): readLockFile(lockFilePath) + else: initTable[string, LockFileEntry]() + for r in nimbleInfo.requires: var tokens: seq[string] = @[] for token in tokenizeRequires(r): @@ -423,7 +443,7 @@ proc collectDeps(c: var AtlasContext; work: var seq[Dependency]; tokens.add commit if tokens.len >= 3 and cmpIgnoreCase(tokens[0], "nim") != 0: - c.addUniqueDep work, tokens + c.addUniqueDep work, tokens, lockFile result = toDestDir(dep.name) / nimbleInfo.srcDir proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency]; @@ -457,14 +477,6 @@ proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]; startIsDep: bool) collectNewDeps(c, work, w, result, i == 0) inc i -proc readLockFile(c: var AtlasContext) = - let jsonAsStr = readFile(c.projectDir / LockFileName) - let jsonTree = parseJson(jsonAsStr) - let data = to(jsonTree, seq[LockFileEntry]) - c.lockFileToUse = initTable[string, LockFileEntry]() - for d in items(data): - c.lockFileToUse[d.dir] = d - proc clone(c: var AtlasContext; start: string; startIsDep: bool): seq[string] = # non-recursive clone. let url = toUrl(c, start) @@ -476,7 +488,7 @@ proc clone(c: var AtlasContext; start: string; startIsDep: bool): seq[string] = c.projectDir = c.workspace / toDestDir(work[0].name) if c.lockOption == useLock: - readLockFile c + c.lockFileToUse = readLockFile(c.projectDir / LockFileName) result = cloneLoop(c, work, startIsDep) if c.lockOption == genLock: writeFile c.projectDir / LockFileName, toJson(c.lockFileToWrite).pretty @@ -794,7 +806,8 @@ proc main = break if nimbleFile.len == 0: error "could not find a .nimble file" - installDependencies(c, nimbleFile) + else: + installDependencies(c, nimbleFile) of "refresh": noArgs() updatePackages(c) From ab4d044a813c6033cf96d4653e3ae347cf5d75cd Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 26 May 2023 15:24:43 +0800 Subject: [PATCH 132/489] fixes #21887; Type conversion on overloaded enum field does not always call (#21908) * fixes #21887; Type conversion on overloaded enum field does not always call * remove comments * add a test case * restrict it to enums --- compiler/semexprs.nim | 3 +++ tests/enum/toverloadable_enums.nim | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index ae118159cf..44a73cf10c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -349,6 +349,9 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode = targetType.skipTypes(abstractPtrs).kind == tyObject: localError(c.config, n.info, "object construction uses ':', not '='") var op = semExprWithType(c, n[1]) + if op.kind == nkClosedSymChoice and op.len > 0 and + op[0].sym.kind == skEnumField: # resolves overloadedable enums + op = ambiguousSymChoice(c, n, op) if targetType.kind != tyGenericParam and targetType.isMetaType: let final = inferWithMetatype(c, targetType, op, true) result.add final diff --git a/tests/enum/toverloadable_enums.nim b/tests/enum/toverloadable_enums.nim index 9bb5514674..5fdcb18238 100644 --- a/tests/enum/toverloadable_enums.nim +++ b/tests/enum/toverloadable_enums.nim @@ -118,3 +118,11 @@ block: # test with macros/templates doAssert isOneMS(e2) doAssert isOneT(e1) doAssert isOneT(e2) + +block: # bug #21908 + type + EnumA = enum A = 300, B + EnumB = enum A = 10 + EnumC = enum C + + doAssert typeof(EnumC(A)) is EnumC From b50babd0ae248b1b62f04090f0c88b7803c8818c Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Fri, 26 May 2023 14:36:20 +0200 Subject: [PATCH 133/489] Atlas: Actually use deps for use command (#21922) Co-authored-by: SirOlaf <> --- tools/atlas/atlas.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index d455fd676e..066adb3fc7 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -787,8 +787,7 @@ proc main = of "use": projectCmd() singleArg() - discard clone(c, args[0], startIsDep = true) - var deps: seq[string] = @[] + var deps = clone(c, args[0], startIsDep = true) patchNimbleFile(c, args[0], deps) patchNimCfg c, deps, getCurrentDir() if c.errors > 0: From f2d26f2973098c2f48484fe321cee6db4bc53caf Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Fri, 26 May 2023 09:37:59 -0300 Subject: [PATCH 134/489] Fix Nimgrab (#21918) * . * Fix nimgrab client not closing * Fix nimgrab client not closing * Fix nimgrab client not closing --- tools/nimgrab.nim | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/nimgrab.nim b/tools/nimgrab.nim index 7e4161fafc..c86159739a 100644 --- a/tools/nimgrab.nim +++ b/tools/nimgrab.nim @@ -1,13 +1,20 @@ import std/[os, httpclient] proc syncDownload(url, file: string) = - var client = newHttpClient() + let client = newHttpClient() proc onProgressChanged(total, progress, speed: BiggestInt) = - echo "Downloading " & url & " " & $(speed div 1000) & "kb/s" - echo clamp(int(progress*100 div total), 0, 100), "%" + var message = "Downloading " + message.add url + message.add ' ' + message.addInt speed div 1000 + message.add "kb/s\n" + message.add $clamp(int(progress * 100 div total), 0, 100) + message.add '%' + echo message client.onProgressChanged = onProgressChanged client.downloadFile(url, file) + client.close() echo "100%" if os.paramCount() != 2: From 656706026b2357a6ff195e3f509f793553e95e8a Mon Sep 17 00:00:00 2001 From: Zoom Date: Fri, 26 May 2023 14:40:53 +0000 Subject: [PATCH 135/489] JS: Add some to-cstring converters for DateTime (#21912) Add some to-cstring converters for DateTime Changelog update --- changelogs/changelog_2_0_0.md | 10 ++++++---- lib/js/jscore.nim | 15 +++++++++++---- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 11fa8cba35..8c2cad6507 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -175,7 +175,7 @@ type _ = float ``` -- - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages. +- Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages. - The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) for 64-bit integer types (`int64` and `uint64`) by default. As this affects @@ -310,9 +310,6 @@ - Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`. - Added `std/cmdline` for reading command line parameters. - Added `sep` parameter in `std/uri` to specify the query separator. -- Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) - and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask) - in `jscore` for JavaScript targets. - Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`. - Added `complex.sgn` for obtaining the phase of complex numbers. - Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`, @@ -327,6 +324,11 @@ - Added `safe` parameter to `base64.encodeMime`. - Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes. - Added `minmax` to `sequtils`, as a more efficient `(min(_), max(_))` over sequences. +- `std/jscore` for JavaScript targets: + + Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) + and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask). + + Added `toDateString`, `toISOString`, `toJSON`, `toTimeString`, `toUTCString` converters for `DateTime`. + [//]: # "Deprecations:" - Deprecated `selfExe` for Nimscript. diff --git a/lib/js/jscore.nim b/lib/js/jscore.nim index 5147b550d8..be353875c8 100644 --- a/lib/js/jscore.nim +++ b/lib/js/jscore.nim @@ -95,20 +95,27 @@ proc getMilliseconds*(d: DateTime): int {.importcpp.} proc getMinutes*(d: DateTime): int {.importcpp.} proc getMonth*(d: DateTime): int {.importcpp.} proc getSeconds*(d: DateTime): int {.importcpp.} -proc getYear*(d: DateTime): int {.importcpp.} proc getTime*(d: DateTime): int {.importcpp.} -proc toString*(d: DateTime): cstring {.importcpp.} +proc getTimezoneOffset*(d: DateTime): int {.importcpp.} proc getUTCDate*(d: DateTime): int {.importcpp.} +proc getUTCDay*(d: DateTime): int {.importcpp.} proc getUTCFullYear*(d: DateTime): int {.importcpp.} proc getUTCHours*(d: DateTime): int {.importcpp.} proc getUTCMilliseconds*(d: DateTime): int {.importcpp.} proc getUTCMinutes*(d: DateTime): int {.importcpp.} proc getUTCMonth*(d: DateTime): int {.importcpp.} proc getUTCSeconds*(d: DateTime): int {.importcpp.} -proc getUTCDay*(d: DateTime): int {.importcpp.} -proc getTimezoneOffset*(d: DateTime): int {.importcpp.} +proc getYear*(d: DateTime): int {.importcpp.} + proc setFullYear*(d: DateTime, year: int) {.importcpp.} +func toDateString*(d: DateTime): cstring {.importcpp.} +func toISOString*(d: DateTime): cstring {.importcpp.} +func toJSON*(d: DateTime): cstring {.importcpp.} +proc toString*(d: DateTime): cstring {.importcpp.} +func toTimeString*(d: DateTime): cstring {.importcpp.} +func toUTCString*(d: DateTime): cstring {.importcpp.} + #JSON library proc stringify*(l: JsonLib, s: JsRoot): cstring {.importcpp.} proc parse*(l: JsonLib, s: cstring): JsRoot {.importcpp.} From 1aaff9dc48337b58d5606cc18c5ba777cab1a0ba Mon Sep 17 00:00:00 2001 From: metagn Date: Fri, 26 May 2023 18:07:37 +0300 Subject: [PATCH 136/489] fix & add test for basic hot code reloading case (#21915) fixes #21885 --- compiler/cgen.nim | 5 ++++- testament/categories.nim | 1 + tests/dll/nimhcr_basic.nim | 7 +++++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/dll/nimhcr_basic.nim diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 8c85db2f84..b332c6cd76 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -2180,7 +2180,10 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode = if m.hcrOn: # make sure this is pulled in (meaning hcrGetGlobal() is called for it during init) - cgsym(m, "programResult") + let sym = magicsys.getCompilerProc(m.g.graph, "programResult") + # ignore when not available, could be a module imported early in `system` + if sym != nil: + cgsymImpl m, sym if m.inHcrInitGuard: endBlock(m.initProc) diff --git a/testament/categories.nim b/testament/categories.nim index d554ebe349..d5964225f3 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -80,6 +80,7 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string, isOrc = testSpec r, makeTest("tests/dll/client.nim", options & " --threads:on" & rpath, cat) testSpec r, makeTest("tests/dll/nimhcr_unit.nim", options & " --threads:off" & rpath, cat) testSpec r, makeTest("tests/dll/visibility.nim", options & " --threads:off" & rpath, cat) + testSpec r, makeTest("tests/dll/nimhcr_basic.nim", options & " --threads:off" & rpath, cat) if "boehm" notin options: # force build required - see the comments in the .nim file for more details diff --git a/tests/dll/nimhcr_basic.nim b/tests/dll/nimhcr_basic.nim new file mode 100644 index 0000000000..340c3fc4e9 --- /dev/null +++ b/tests/dll/nimhcr_basic.nim @@ -0,0 +1,7 @@ +discard """ + output: ''' +Hello world +''' +""" + +echo "Hello world" From 2beea7281061822b69e77715c8b0c30ed4d55a5c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 26 May 2023 21:24:29 +0200 Subject: [PATCH 137/489] atlas: better code (#21926) --- tools/atlas/atlas.nim | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 066adb3fc7..d463787969 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -447,16 +447,14 @@ proc collectDeps(c: var AtlasContext; work: var seq[Dependency]; result = toDestDir(dep.name) / nimbleInfo.srcDir proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency]; - dep: Dependency; result: var seq[string]; - isMainProject: bool) = + dep: Dependency; isMainProject: bool): string = let nimbleFile = findNimbleFile(c, dep) if nimbleFile != "": - let x = collectDeps(c, work, dep, nimbleFile) - result.add x + result = collectDeps(c, work, dep, nimbleFile) else: - result.add toDestDir(dep.name) + result = toDestDir(dep.name) -proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]; startIsDep: bool): seq[string] = +proc traverseLoop(c: var AtlasContext; work: var seq[Dependency]; startIsDep: bool): seq[string] = result = @[] var i = 0 while i < work.len: @@ -474,11 +472,11 @@ proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]; startIsDep: bool) # even if the checkout fails, we can make use of the somewhat # outdated .nimble file to clone more of the most likely still relevant # dependencies: - collectNewDeps(c, work, w, result, i == 0) + result.add collectNewDeps(c, work, w, i == 0) inc i -proc clone(c: var AtlasContext; start: string; startIsDep: bool): seq[string] = - # non-recursive clone. +proc traverse(c: var AtlasContext; start: string; startIsDep: bool): seq[string] = + # returns the list of paths for the nim.cfg file. let url = toUrl(c, start) var work = @[Dependency(name: toName(start), url: url, commit: "")] @@ -489,7 +487,7 @@ proc clone(c: var AtlasContext; start: string; startIsDep: bool): seq[string] = c.projectDir = c.workspace / toDestDir(work[0].name) if c.lockOption == useLock: c.lockFileToUse = readLockFile(c.projectDir / LockFileName) - result = cloneLoop(c, work, startIsDep) + result = traverseLoop(c, work, startIsDep) if c.lockOption == genLock: writeFile c.projectDir / LockFileName, toJson(c.lockFileToWrite).pretty @@ -549,7 +547,7 @@ proc installDependencies(c: var AtlasContext; nimbleFile: string) = let (_, pkgname, _) = splitFile(nimbleFile) let dep = Dependency(name: toName(pkgname), url: "", commit: "") discard collectDeps(c, work, dep, nimbleFile) - let paths = cloneLoop(c, work, startIsDep = true) + let paths = traverseLoop(c, work, startIsDep = true) patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c)) proc updateDir(c: var AtlasContext; dir, filter: string) = @@ -706,9 +704,7 @@ proc main = error action & " command must be executed in a project, not in the workspace" return - var c = AtlasContext( - projectDir: getCurrentDir(), - workspace: "") + var c = AtlasContext(projectDir: getCurrentDir(), workspace: "") for kind, key, val in getopt(): case kind @@ -776,7 +772,7 @@ proc main = createWorkspaceIn c.workspace, c.depsDir of "clone", "update": singleArg() - let deps = clone(c, args[0], startIsDep = false) + let deps = traverse(c, args[0], startIsDep = false) patchNimCfg c, deps, if c.cfgHere: getCurrentDir() else: findSrcDir(c) when MockupRun: if not c.mockupSuccess: @@ -787,7 +783,7 @@ proc main = of "use": projectCmd() singleArg() - var deps = clone(c, args[0], startIsDep = true) + var deps = traverse(c, args[0], startIsDep = true) patchNimbleFile(c, args[0], deps) patchNimCfg c, deps, getCurrentDir() if c.errors > 0: From 09f36f51989dd8045129781285902f4eaa07779b Mon Sep 17 00:00:00 2001 From: Gruruya Date: Sat, 27 May 2023 00:54:21 -0400 Subject: [PATCH 138/489] atlas: search improvements (#21929) * Get description and license from github json response * Allow running `atlas search` outside of a workspace * Check `len` instead of `dirExists` * make `list` identical to `search` --- tools/atlas/atlas.nim | 10 ++++++---- tools/atlas/packagesjson.nim | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index d463787969..97e6afbb9a 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -756,10 +756,10 @@ proc main = c.workspace = detectWorkspace() if c.workspace.len > 0: readConfig c - else: + echo "Using workspace ", c.workspace + elif action notin ["search", "list"]: error "No workspace found. Run `atlas init` if you want this current directory to be your workspace." return - echo "Using workspace ", c.workspace when MockupRun: c.depsDir = c.workspace @@ -807,8 +807,10 @@ proc main = noArgs() updatePackages(c) of "search", "list": - updatePackages(c) - search getPackages(c.workspace), args + if c.workspace.len != 0: + updatePackages(c) + search getPackages(c.workspace), args + else: search @[], args of "updateprojects": updateDir(c, c.workspace, if args.len == 0: "" else: args[0]) of "updatedeps": diff --git a/tools/atlas/packagesjson.nim b/tools/atlas/packagesjson.nim index 5ceef706f2..4c4d42595d 100644 --- a/tools/atlas/packagesjson.nim +++ b/tools/atlas/packagesjson.nim @@ -92,7 +92,8 @@ proc githubSearch(seen: var HashSet[string]; terms: seq[string]) = url: j.getOrDefault("html_url").getStr, downloadMethod: "git", tags: toTags(j.getOrDefault("topics")), - description: ", not listed in packages.json", + description: j.getOrDefault("description").getStr, + license: j.getOrDefault("license").getOrDefault("spdx_id").getStr, web: j.getOrDefault("html_url").getStr ) if not seen.containsOrIncl(p.url): From 6128ef53c5bbc6c1de4e3cadcb70db580f74dbcd Mon Sep 17 00:00:00 2001 From: heterodoxic <122719743+heterodoxic@users.noreply.github.com> Date: Sat, 27 May 2023 06:54:41 +0200 Subject: [PATCH 139/489] fix #10964 by honoring pointer deref syntax if a reified openarray is used to get an array's length (#21925) * fix #10964 * add test --- compiler/ccgexprs.nim | 13 +++++++++++-- tests/ccgbugs/t10964.nim | 6 ++++++ 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/ccgbugs/t10964.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index fe776e8d30..f5033bdc3b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1882,8 +1882,17 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)") else: unaryExpr(p, e, d, "$1Len_0") else: - if op == mHigh: unaryExpr(p, e, d, "($1.Field1-1)") - else: unaryExpr(p, e, d, "$1.Field1") + let isDeref = a.kind in {nkHiddenDeref, nkDerefExpr} + if op == mHigh: + if isDeref: + unaryExpr(p, e, d, "($1->Field1-1)") + else: + unaryExpr(p, e, d, "($1.Field1-1)") + else: + if isDeref: + unaryExpr(p, e, d, "$1->Field1") + else: + unaryExpr(p, e, d, "$1.Field1") of tyCstring: if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)") else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)") diff --git a/tests/ccgbugs/t10964.nim b/tests/ccgbugs/t10964.nim new file mode 100644 index 0000000000..a331b16cdc --- /dev/null +++ b/tests/ccgbugs/t10964.nim @@ -0,0 +1,6 @@ +func test*(input: var openArray[int32], start: int = 0, fin: int = input.len - 1) = + discard + +var someSeq = @[1'i32] + +test(someSeq) \ No newline at end of file From 38fdf139824bea54add1ce0d627b80916006ed3e Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 27 May 2023 02:44:15 -0300 Subject: [PATCH 140/489] Clean nimbase (#21927) * . * Clean out nimbase.h * Clean out nimbase.h --- changelogs/changelog_2_0_0.md | 2 ++ lib/nimbase.h | 34 +++++++--------------------------- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 8c2cad6507..31c495a69f 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -481,6 +481,8 @@ - Removed deprecated `LineTooLong` hint. - Line numbers and filenames of source files work correctly inside templates for JavaScript targets. +- Removed support for LCC (Local C), Pelles C, Digital Mars, Watcom compilers. + ## Docgen diff --git a/lib/nimbase.h b/lib/nimbase.h index 570b50b081..3a1289b6fa 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -10,11 +10,7 @@ /* compiler symbols: __BORLANDC__ _MSC_VER -__WATCOMC__ -__LCC__ __GNUC__ -__DMC__ -__POCC__ __TINYC__ __clang__ __AVR__ @@ -89,11 +85,8 @@ __AVR__ #endif /* calling convention mess ----------------------------------------------- */ -#if defined(__GNUC__) || defined(__LCC__) || defined(__POCC__) \ - || defined(__TINYC__) +#if defined(__GNUC__) || defined(__TINYC__) /* these should support C99's inline */ - /* the test for __POCC__ has to come before the test for _MSC_VER, - because PellesC defines _MSC_VER too. This is brain-dead. */ # define N_INLINE(rettype, name) inline rettype name #elif defined(__BORLANDC__) || defined(_MSC_VER) /* Borland's compiler is really STRANGE here; note that the __fastcall @@ -101,21 +94,13 @@ __AVR__ the return type, so we do not handle this mess in the code generator but rather here. */ # define N_INLINE(rettype, name) __inline rettype name -#elif defined(__DMC__) -# define N_INLINE(rettype, name) inline rettype name -#elif defined(__WATCOMC__) -# define N_INLINE(rettype, name) __inline rettype name #else /* others are less picky: */ # define N_INLINE(rettype, name) rettype __inline name #endif #define N_INLINE_PTR(rettype, name) rettype (*name) -#if defined(__POCC__) -# define NIM_CONST /* PCC is really picky with const modifiers */ -# undef _MSC_VER /* Yeah, right PCC defines _MSC_VER even if it is - not that compatible. Well done. */ -#elif defined(__cplusplus) +#if defined(__cplusplus) # define NIM_CONST /* C++ is picky with const modifiers */ #else # define NIM_CONST const @@ -126,7 +111,7 @@ __AVR__ http://stackoverflow.com/questions/18298280/how-to-declare-a-variable-as-thread-local-portably */ #if defined _WIN32 -# if defined _MSC_VER || defined __DMC__ || defined __BORLANDC__ +# if defined _MSC_VER || defined __BORLANDC__ # define NIM_THREADVAR __declspec(thread) # else # define NIM_THREADVAR __thread @@ -136,7 +121,6 @@ __AVR__ #elif defined _WIN32 && ( \ defined _MSC_VER || \ defined __ICL || \ - defined __DMC__ || \ defined __BORLANDC__ ) # define NIM_THREADVAR __declspec(thread) #elif defined(__TINYC__) || defined(__GENODE__) @@ -155,8 +139,7 @@ __AVR__ #endif /* --------------- how int64 constants should be declared: ----------- */ -#if defined(__GNUC__) || defined(__LCC__) || \ - defined(__POCC__) || defined(__DMC__) || defined(_MSC_VER) +#if defined(__GNUC__) || defined(_MSC_VER) # define IL64(x) x##LL #else /* works only without LL */ # define IL64(x) ((NI64)x) @@ -247,8 +230,7 @@ __AVR__ #define N_NOINLINE_PTR(rettype, name) rettype (*name) -#if defined(__BORLANDC__) || defined(__WATCOMC__) || \ - defined(__POCC__) || defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) +#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) /* these compilers have a fastcall so use it: */ # ifdef __TINYC__ # define N_NIMCALL(rettype, name) rettype __attribute((__fastcall)) name @@ -296,8 +278,7 @@ __AVR__ #endif /* Known compiler with stdint.h that doesn't fit the general pattern? */ -#if defined(__LCC__) || defined(__DMC__) || defined(__POCC__) || \ - defined(__AVR__) || (defined(__cplusplus) && (__cplusplus < 201103)) +#if defined(__AVR__) || (defined(__cplusplus) && (__cplusplus < 201103)) # define HAVE_STDINT_H #endif @@ -357,8 +338,7 @@ NIM_STATIC_ASSERT(CHAR_BIT == 8, ""); the generated code does not rely on it anymore */ #endif -#if defined(__BORLANDC__) || defined(__DMC__) \ - || defined(__WATCOMC__) || defined(_MSC_VER) +#if defined(__BORLANDC__) || defined(_MSC_VER) typedef signed char NI8; typedef signed short int NI16; typedef signed int NI32; From b0e1bc02c6381a8910195a91a073e62186ebd837 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sat, 27 May 2023 05:24:32 -0300 Subject: [PATCH 141/489] Remove unused dead code (#21931) * . * Remove dead code --- .gitlab-ci.yml | 62 -------------------------------------------------- 1 file changed, 62 deletions(-) delete mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 31908d2238..0000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,62 +0,0 @@ -# xxx unused, out of date - -image: ubuntu:18.04 - -stages: - - pre-build - - build - - deploy - - test - -.linux_set_path: &linux_set_path_def - before_script: - - export PATH=$(pwd)/bin${PATH:+:$PATH} - tags: - - linux - -.windows_set_path: &win_set_path_def - before_script: - - set PATH=%CD%\bin;%PATH% - tags: - - windows - - -build-windows: - stage: build - script: - - ci\build.bat - artifacts: - paths: - - bin\nim.exe - - bin\nimd.exe - - compiler\nim.exe - - koch.exe - expire_in: 1 week - tags: - - windows - -deploy-windows: - stage: deploy - script: - - koch.exe winrelease - artifacts: - paths: - - build/*.exe - - build/*.zip - expire_in: 1 week - tags: - - windows - - fast - - - -test-windows: - stage: test - <<: *win_set_path_def - script: - - call ci\deps.bat - - nim c testament\tester - - testament\tester.exe all - tags: - - windows - - fast From 6048367a9f3ba1af739a19d410ca2798a8c33fe0 Mon Sep 17 00:00:00 2001 From: Gruruya Date: Sat, 27 May 2023 04:55:31 -0400 Subject: [PATCH 142/489] Atlas: clone with `--recursive` (#21933) --- tools/atlas/osutils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/atlas/osutils.nim b/tools/atlas/osutils.nim index 6134830b50..66cd29be58 100644 --- a/tools/atlas/osutils.nim +++ b/tools/atlas/osutils.nim @@ -32,7 +32,7 @@ proc cloneUrl*(url, dest: string; cloneUsingHttps: bool): string = if xcode == QuitSuccess: # retry multiple times to avoid annoying github timeouts: - let cmd = "git clone " & modUrl & " " & dest + let cmd = "git clone --recursive " & modUrl & " " & dest for i in 0..4: if execShellCmd(cmd) == 0: return "" os.sleep(4000) From 73095e2abbc46ce6f6582f08b30548431f28ed62 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 27 May 2023 13:53:07 +0200 Subject: [PATCH 143/489] Atlas: fixes 'use' command (#21932) * Atlas: fixes 'use' command * Atlas: refactoring + make tests green again --- tools/atlas/atlas.nim | 95 ++++++++++++++++++--------------------- tools/atlas/tests/nim.cfg | 1 - 2 files changed, 43 insertions(+), 53 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 97e6afbb9a..e2b86a422d 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -79,6 +79,7 @@ type dir, url, commit: string PackageName = distinct string + CfgPath = distinct string # put into a config `--path:"../x"` DepRelation = enum normal, strictlyLess, strictlyGreater @@ -102,6 +103,8 @@ type step: int mockupSuccess: bool +proc `==`(a, b: CfgPath): bool {.borrow.} + const InvalidCommit = "" ProduceTest = false @@ -210,6 +213,9 @@ proc error(c: var AtlasContext; p: PackageName; args: varargs[string]) = message(c, "[Error] ", p, args) inc c.errors +proc info(c: var AtlasContext; p: PackageName; args: varargs[string]) = + message(c, "[Info] ", p, args) + proc sameVersionAs(tag, ver: string): bool = const VersionChars = {'0'..'9', '.'} @@ -416,7 +422,7 @@ proc readLockFile(filename: string): Table[string, LockFileEntry] = result[d.dir] = d proc collectDeps(c: var AtlasContext; work: var seq[Dependency]; - dep: Dependency; nimbleFile: string): string = + dep: Dependency; nimbleFile: string): CfgPath = # If there is a .nimble file, return the dependency path & srcDir # else return "". assert nimbleFile != "" @@ -444,17 +450,20 @@ proc collectDeps(c: var AtlasContext; work: var seq[Dependency]; if tokens.len >= 3 and cmpIgnoreCase(tokens[0], "nim") != 0: c.addUniqueDep work, tokens, lockFile - result = toDestDir(dep.name) / nimbleInfo.srcDir + result = CfgPath(toDestDir(dep.name) / nimbleInfo.srcDir) proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency]; - dep: Dependency; isMainProject: bool): string = + dep: Dependency; isMainProject: bool): CfgPath = let nimbleFile = findNimbleFile(c, dep) if nimbleFile != "": result = collectDeps(c, work, dep, nimbleFile) else: - result = toDestDir(dep.name) + result = CfgPath toDestDir(dep.name) -proc traverseLoop(c: var AtlasContext; work: var seq[Dependency]; startIsDep: bool): seq[string] = +proc addUnique[T](s: var seq[T]; elem: sink T) = + if not s.contains(elem): s.add elem + +proc traverseLoop(c: var AtlasContext; work: var seq[Dependency]; startIsDep: bool): seq[CfgPath] = result = @[] var i = 0 while i < work.len: @@ -472,10 +481,10 @@ proc traverseLoop(c: var AtlasContext; work: var seq[Dependency]; startIsDep: bo # even if the checkout fails, we can make use of the somewhat # outdated .nimble file to clone more of the most likely still relevant # dependencies: - result.add collectNewDeps(c, work, w, i == 0) + result.addUnique collectNewDeps(c, work, w, i == 0) inc i -proc traverse(c: var AtlasContext; start: string; startIsDep: bool): seq[string] = +proc traverse(c: var AtlasContext; start: string; startIsDep: bool): seq[CfgPath] = # returns the list of paths for the nim.cfg file. let url = toUrl(c, start) var work = @[Dependency(name: toName(start), url: url, commit: "")] @@ -495,10 +504,12 @@ const configPatternBegin = "############# begin Atlas config section ##########\n" configPatternEnd = "############# end Atlas config section ##########\n" -proc patchNimCfg(c: var AtlasContext; deps: seq[string]; cfgPath: string) = +template projectFromCurrentDir(): PackageName = PackageName(getCurrentDir().splitPath.tail) + +proc patchNimCfg(c: var AtlasContext; deps: seq[CfgPath]; cfgPath: string) = var paths = "--noNimblePath\n" for d in deps: - let pkgname = toDestDir d.PackageName + let pkgname = toDestDir d.string.PackageName let pkgdir = if dirExists(c.workspace / pkgname): c.workspace / pkgname else: c.depsDir / pkgName let x = relativePath(pkgdir, cfgPath, '/') @@ -514,6 +525,7 @@ proc patchNimCfg(c: var AtlasContext; deps: seq[string]; cfgPath: string) = error(c, c.projectDir.PackageName, "could not write the nim.cfg") elif not fileExists(cfg): writeFile(cfg, cfgContent) + info(c, projectFromCurrentDir(), "created: " & cfg) else: let content = readFile(cfg) let start = content.find(configPatternBegin) @@ -528,6 +540,7 @@ proc patchNimCfg(c: var AtlasContext; deps: seq[string]; cfgPath: string) = # do not touch the file if nothing changed # (preserves the file date information): writeFile(cfg, cfgContent) + info(c, projectFromCurrentDir(), "updated: " & cfg) proc error*(msg: string) = when defined(debug): @@ -571,42 +584,25 @@ proc updateDir(c: var AtlasContext; dir, filter: string) = else: error c, pkg, "could not fetch current branch name" -proc addUnique[T](s: var seq[T]; elem: sink T) = - if not s.contains(elem): s.add elem - -proc addDepFromNimble(c: var AtlasContext; deps: var seq[string]; project: PackageName; dep: string) = - var depDir = c.workspace / dep - if not dirExists(depDir): - depDir = c.depsDir / dep - if dirExists(depDir): - withDir c, depDir: - let src = findSrcDir(c) - if src.len != 0: - deps.addUnique dep / src - else: - deps.addUnique dep - else: - warn c, project, "cannot find: " & depDir - -proc patchNimbleFile(c: var AtlasContext; dep: string; deps: var seq[string]) = +proc patchNimbleFile(c: var AtlasContext; dep: string): string = let thisProject = getCurrentDir().splitPath.tail let oldErrors = c.errors let url = toUrl(c, dep) + result = "" if oldErrors != c.errors: warn c, toName(dep), "cannot resolve package name" else: - var nimbleFile = "" for x in walkFiles("*.nimble"): - if nimbleFile.len == 0: - nimbleFile = x + if result.len == 0: + result = x else: # ambiguous .nimble file warn c, toName(dep), "cannot determine `.nimble` file; there are multiple to choose from" - return + return "" # see if we have this requirement already listed. If so, do nothing: var found = false - if nimbleFile.len > 0: - let nimbleInfo = extractRequiresInfo(c, nimbleFile) + if result.len > 0: + let nimbleInfo = extractRequiresInfo(c, result) for r in nimbleInfo.requires: var tokens: seq[string] = @[] for token in tokenizeRequires(r): @@ -615,26 +611,23 @@ proc patchNimbleFile(c: var AtlasContext; dep: string; deps: var seq[string]) = let oldErrors = c.errors let urlB = toUrl(c, tokens[0]) if oldErrors != c.errors: - warn c, toName(tokens[0]), "cannot resolve package name; found in: " & nimbleFile + warn c, toName(tokens[0]), "cannot resolve package name; found in: " & result if url == urlB: found = true - - if cmpIgnoreCase(tokens[0], "nim") != 0: - c.addDepFromNimble deps, toName(thisProject), tokens[0] + break if not found: - let line = "requires \"$1@#head\"\n" % dep.escape("", "") - if nimbleFile.len > 0: - let oldContent = readFile(nimbleFile) - writeFile nimbleFile, oldContent & "\n" & line - message(c, "[Info] ", toName(thisProject), "updated: " & nimbleFile) + let line = "requires \"$1#head\"\n" % dep.escape("", "") + if result.len > 0: + let oldContent = readFile(result) + writeFile result, oldContent & "\n" & line + info(c, toName(thisProject), "updated: " & result) else: - let outfile = thisProject & ".nimble" - writeFile outfile, line - message(c, "[Info] ", toName(thisProject), "created: " & outfile) - c.addDepFromNimble deps, toName(thisProject), dep + result = thisProject & ".nimble" + writeFile result, line + info(c, toName(thisProject), "created: " & result) else: - message(c, "[Info] ", toName(thisProject), "up to date: " & nimbleFile) + info(c, toName(thisProject), "up to date: " & result) proc detectWorkspace(): string = result = getCurrentDir() @@ -783,11 +776,9 @@ proc main = of "use": projectCmd() singleArg() - var deps = traverse(c, args[0], startIsDep = true) - patchNimbleFile(c, args[0], deps) - patchNimCfg c, deps, getCurrentDir() - if c.errors > 0: - error "There were problems." + let nimbleFile = patchNimbleFile(c, args[0]) + if nimbleFile.len > 0: + installDependencies(c, nimbleFile) of "install": projectCmd() if args.len > 1: diff --git a/tools/atlas/tests/nim.cfg b/tools/atlas/tests/nim.cfg index 5f568569b9..3982b12bb4 100644 --- a/tools/atlas/tests/nim.cfg +++ b/tools/atlas/tests/nim.cfg @@ -6,6 +6,5 @@ --path:"../sync" --path:"../npeg/src" --path:"../testes" ---path:"../grok" --path:"../nim-bytes2human/src" ############# end Atlas config section ########## From af3fd5a010b2f30a007c410858effb3095ef2598 Mon Sep 17 00:00:00 2001 From: heterodoxic <122719743+heterodoxic@users.noreply.github.com> Date: Sat, 27 May 2023 15:27:42 +0200 Subject: [PATCH 144/489] fixes #15428 by updating deep open array copy codegen (#21935) * fix #15428 * add test --- compiler/ccgexprs.nim | 5 +++-- tests/ccgbugs/t15428.nim | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 tests/ccgbugs/t15428.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index f5033bdc3b..b2510f5be4 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -450,9 +450,10 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = [addrLoc(p.config, dest), rdLoc(src), genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tyOpenArray, tyVarargs: + let source = addrLocOrTemp(src) linefmt(p, cpsStmts, - "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", - [addrLoc(p.config, dest), addrLocOrTemp(src), + "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $2->Field1, $3);$n", + [addrLoc(p.config, dest), source, genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tySet: if mapSetType(p.config, ty) == ctArray: diff --git a/tests/ccgbugs/t15428.nim b/tests/ccgbugs/t15428.nim new file mode 100644 index 0000000000..d9ae8ff160 --- /dev/null +++ b/tests/ccgbugs/t15428.nim @@ -0,0 +1,22 @@ +discard """ + cmd: "nim $target --mm:refc $file" + output: '''5 +5 +[1, 2, 3, 4, 5] +(data: [1, 2, 3, 4, 5]) +''' +""" + +proc take[T](f: openArray[T]) = + echo f.len +let f = @[0,1,2,3,4] +take(f.toOpenArray(0,4)) + +{.experimental: "views".} +type + Foo = object + data: openArray[int] +let f2 = Foo(data: [1,2,3,4,5]) +echo f2.data.len +echo f2.data +echo f2 \ No newline at end of file From ef3c0bec1cf02049402a482393581c0a80dd884b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 27 May 2023 16:48:10 +0200 Subject: [PATCH 145/489] Atlas: explicit graph representation (#21937) --- tools/atlas/atlas.nim | 83 ++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index e2b86a422d..13a2bb7857 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -87,13 +87,17 @@ type name: PackageName url, commit: string rel: DepRelation # "requires x < 1.0" is silly, but Nimble allows it so we have too. + parents: seq[int] # why we need this dependency + DepGraph = object + nodes: seq[Dependency] + processed: Table[string, int] # the key is (url / commit) + AtlasContext = object projectDir, workspace, depsDir: string hasPackageList: bool keepCommits: bool cfgHere: bool p: Table[string, string] # name -> url mapping - processed: HashSet[string] # the key is (url / commit) errors: int lockOption: LockOption lockFileToWrite: seq[LockFileEntry] @@ -394,22 +398,32 @@ proc findNimbleFile(c: AtlasContext; dep: Dependency): string = # ambiguous .nimble file return "" -proc addUniqueDep(c: var AtlasContext; work: var seq[Dependency]; +proc addUnique[T](s: var seq[T]; elem: sink T) = + if not s.contains(elem): s.add elem + +proc addUniqueDep(c: var AtlasContext; g: var DepGraph; parent: int; tokens: seq[string]; lockfile: Table[string, LockFileEntry]) = let pkgName = tokens[0] let oldErrors = c.errors let url = toUrl(c, pkgName) if oldErrors != c.errors: warn c, toName(pkgName), "cannot resolve package name" - elif not c.processed.containsOrIncl(url / tokens[2]): - if lockfile.contains(pkgName): - work.add Dependency(name: toName(pkgName), - url: lockfile[pkgName].url, - commit: lockfile[pkgName].commit, - rel: normal) + else: + let key = url / tokens[2] + if g.processed.hasKey(key): + g.nodes[g.processed[key]].parents.addUnique parent else: - work.add Dependency(name: toName(pkgName), url: url, commit: tokens[2], - rel: toDepRelation(tokens[1])) + g.processed[key] = g.nodes.len + if lockfile.contains(pkgName): + g.nodes.add Dependency(name: toName(pkgName), + url: lockfile[pkgName].url, + commit: lockfile[pkgName].commit, + rel: normal, + parents: @[parent]) + else: + g.nodes.add Dependency(name: toName(pkgName), url: url, commit: tokens[2], + rel: toDepRelation(tokens[1]), + parents: @[parent]) template toDestDir(p: PackageName): string = p.string @@ -421,7 +435,7 @@ proc readLockFile(filename: string): Table[string, LockFileEntry] = for d in items(data): result[d.dir] = d -proc collectDeps(c: var AtlasContext; work: var seq[Dependency]; +proc collectDeps(c: var AtlasContext; g: var DepGraph; parent: int; dep: Dependency; nimbleFile: string): CfgPath = # If there is a .nimble file, return the dependency path & srcDir # else return "". @@ -449,25 +463,22 @@ proc collectDeps(c: var AtlasContext; work: var seq[Dependency]; tokens.add commit if tokens.len >= 3 and cmpIgnoreCase(tokens[0], "nim") != 0: - c.addUniqueDep work, tokens, lockFile + c.addUniqueDep g, parent, tokens, lockFile result = CfgPath(toDestDir(dep.name) / nimbleInfo.srcDir) -proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency]; - dep: Dependency; isMainProject: bool): CfgPath = +proc collectNewDeps(c: var AtlasContext; g: var DepGraph; parent: int; + dep: Dependency): CfgPath = let nimbleFile = findNimbleFile(c, dep) if nimbleFile != "": - result = collectDeps(c, work, dep, nimbleFile) + result = collectDeps(c, g, parent, dep, nimbleFile) else: result = CfgPath toDestDir(dep.name) -proc addUnique[T](s: var seq[T]; elem: sink T) = - if not s.contains(elem): s.add elem - -proc traverseLoop(c: var AtlasContext; work: var seq[Dependency]; startIsDep: bool): seq[CfgPath] = +proc traverseLoop(c: var AtlasContext; g: var DepGraph; startIsDep: bool): seq[CfgPath] = result = @[] var i = 0 - while i < work.len: - let w = work[i] + while i < g.nodes.len: + let w = g.nodes[i] let destDir = toDestDir(w.name) let oldErrors = c.errors @@ -481,22 +492,22 @@ proc traverseLoop(c: var AtlasContext; work: var seq[Dependency]; startIsDep: bo # even if the checkout fails, we can make use of the somewhat # outdated .nimble file to clone more of the most likely still relevant # dependencies: - result.addUnique collectNewDeps(c, work, w, i == 0) + result.addUnique collectNewDeps(c, g, i, w) inc i proc traverse(c: var AtlasContext; start: string; startIsDep: bool): seq[CfgPath] = # returns the list of paths for the nim.cfg file. let url = toUrl(c, start) - var work = @[Dependency(name: toName(start), url: url, commit: "")] + var g = DepGraph(nodes: @[Dependency(name: toName(start), url: url, commit: "")]) if url == "": error c, toName(start), "cannot resolve package name" return - c.projectDir = c.workspace / toDestDir(work[0].name) + c.projectDir = c.workspace / toDestDir(g.nodes[0].name) if c.lockOption == useLock: c.lockFileToUse = readLockFile(c.projectDir / LockFileName) - result = traverseLoop(c, work, startIsDep) + result = traverseLoop(c, g, startIsDep) if c.lockOption == genLock: writeFile c.projectDir / LockFileName, toJson(c.lockFileToWrite).pretty @@ -553,14 +564,30 @@ proc findSrcDir(c: var AtlasContext): string = return nimbleInfo.srcDir return "" +proc generateDepGraph(g: DepGraph) = + # currently unused. + var dotGraph = "" + for i in 0 ..< g.nodes.len: + for p in items g.nodes[i].parents: + if p >= 0: + dotGraph.addf("\"$1\" -> \"$2\";\n", [g.nodes[p].name.string, g.nodes[i].name.string]) + writeFile("deps.dot", "digraph deps {\n$1}\n" % dotGraph) + let graphvizDotPath = findExe("dot") + if graphvizDotPath.len == 0: + #echo("gendepend: Graphviz's tool dot is required, " & + # "see https://graphviz.org/download for downloading") + discard + else: + discard execShellCmd("dot -Tpng -odeps.png deps.dot") + proc installDependencies(c: var AtlasContext; nimbleFile: string) = # 1. find .nimble file in CWD # 2. install deps from .nimble - var work: seq[Dependency] = @[] + var g = DepGraph(nodes: @[]) let (_, pkgname, _) = splitFile(nimbleFile) let dep = Dependency(name: toName(pkgname), url: "", commit: "") - discard collectDeps(c, work, dep, nimbleFile) - let paths = traverseLoop(c, work, startIsDep = true) + discard collectDeps(c, g, -1, dep, nimbleFile) + let paths = traverseLoop(c, g, startIsDep = true) patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c)) proc updateDir(c: var AtlasContext; dir, filter: string) = From 2dcc7195daab5964a68d7eb6edf897edc0cf2052 Mon Sep 17 00:00:00 2001 From: metagn Date: Sat, 27 May 2023 21:09:34 +0300 Subject: [PATCH 146/489] support generic void return type for templates (#21934) fixes #21920 --- compiler/sem.nim | 7 +++++-- tests/template/template_issues.nim | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index 3b20579d57..e6d92d1f02 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -467,8 +467,11 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, retType = generateTypeInstance(c, paramTypes, macroResult.info, retType) - result = semExpr(c, result, flags, expectedType) - result = fitNode(c, retType, result, result.info) + if retType.kind == tyVoid: + result = semStmt(c, result, flags) + else: + result = semExpr(c, result, flags, expectedType) + result = fitNode(c, retType, result, result.info) #globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0])) dec(c.config.evalTemplateCounter) discard c.friendModules.pop() diff --git a/tests/template/template_issues.nim b/tests/template/template_issues.nim index 1fed694efb..58c40941db 100644 --- a/tests/template/template_issues.nim +++ b/tests/template/template_issues.nim @@ -296,3 +296,9 @@ block: # bug #12595 discard {i: ""} test() + +block: # bug #21920 + template t[T](): T = + discard + + t[void]() # Error: expression has no type: discard From d5ba14db619eb52cb97f66f37cd04a240d84223d Mon Sep 17 00:00:00 2001 From: Gruruya Date: Sat, 27 May 2023 14:49:19 -0400 Subject: [PATCH 147/489] Atlas: add `atlas tag` command (#21936) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial structure, `GitTags` → `GitRefsTags` * Determine if we should use v prefix * get tag from latest tag, patch nimble file * Just do tags for now * atlas tag now tags and pushes * Improve UX of `atlas tag` * better description for `tag` * Small fixup * Consistent naming * strip after checking status * Take major/minor/patch as arg for `atlas tag` * undo testing comment * Fix for `v` prefixed versions * Avoid useless assignment * Remove uselss enum assignment * Consistent parameter seperation * Add error handling for non-semver tags * Use `assert` to quit on error * Update tools/atlas/atlas.nim Co-authored-by: Andreas Rumpf * Don't push tags if errors occurred * Allow `atlas tag [tag]` again * Add atlas tag `a..z` for fields > 3 * Document the three input options * Take up less lines in help * Less or in help * One last doc pass * Check args length * clarify last tag * consistency/order --------- Co-authored-by: Andreas Rumpf --- tools/atlas/atlas.nim | 88 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 4 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 13a2bb7857..9361cf0431 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -43,6 +43,10 @@ Command: updateDeps [filter] update every dependency that has a remote URL that matches `filter` if a filter is given + tag [major|minor|patch] + add and push a new tag, input must be one of: + ['major'|'minor'|'patch'] or a SemVer tag like ['1.0.3'] + or a letter ['a'..'z']: a.b.c.d.e.f.g build|test|doc|tasks currently delegates to `nimble build|test|doc` task currently delegates to `nimble ` @@ -83,6 +87,9 @@ type DepRelation = enum normal, strictlyLess, strictlyGreater + SemVerField = enum + major, minor, patch + Dependency = object name: PackageName url, commit: string @@ -116,9 +123,12 @@ const type Command = enum GitDiff = "git diff", + GitTag = "git tag", GitTags = "git show-ref --tags", + GitLastTaggedRef = "git rev-list --tags --max-count=1", GitRevParse = "git rev-parse", GitCheckout = "git checkout", + GitPush = "git push origin", GitPull = "git pull", GitCurrentCommit = "git log -n 1 --format=%H" GitMergeBase = "git merge-base" @@ -143,7 +153,7 @@ proc exec(c: var AtlasContext; cmd: Command; args: openArray[string]): (string, when MockupRun: assert TestLog[c.step].cmd == cmd, $(TestLog[c.step].cmd, cmd) case cmd - of GitDiff, GitTags, GitRevParse, GitPull, GitCurrentCommit: + of GitDiff, GitTag, GitTags, GitLastTaggedRef, GitRevParse, GitPush, GitPull, GitCurrentCommit: result = (TestLog[c.step].output, TestLog[c.step].exitCode) of GitCheckout: assert args[0] == TestLog[c.step].output @@ -209,6 +219,9 @@ proc message(c: var AtlasContext; category: string; p: PackageName; args: vararg msg.add a stdout.writeLine msg +proc info(c: var AtlasContext; p: PackageName; args: varargs[string]) = + message(c, "[Info] ", p, args) + proc warn(c: var AtlasContext; p: PackageName; args: varargs[string]) = message(c, "[Warning] ", p, args) inc c.errors @@ -217,9 +230,6 @@ proc error(c: var AtlasContext; p: PackageName; args: varargs[string]) = message(c, "[Error] ", p, args) inc c.errors -proc info(c: var AtlasContext; p: PackageName; args: varargs[string]) = - message(c, "[Info] ", p, args) - proc sameVersionAs(tag, ver: string): bool = const VersionChars = {'0'..'9', '.'} @@ -270,6 +280,62 @@ proc gitPull(c: var AtlasContext; p: PackageName) = if status != 0: error(c, p, "could not 'git pull'") +proc gitTag(c: var AtlasContext; tag: string) = + let (_, status) = exec(c, GitTag, [tag]) + if status != 0: + error(c, c.projectDir.PackageName, "could not 'git tag " & tag & "'") + +proc pushTag(c: var AtlasContext; tag: string) = + let (outp, status) = exec(c, GitPush, [tag]) + if status != 0: + error(c, c.projectDir.PackageName, "could not 'git push " & tag & "'") + elif outp.strip() == "Everything up-to-date": + info(c, c.projectDir.PackageName, "is up-to-date") + else: + info(c, c.projectDir.PackageName, "successfully pushed tag: " & tag) + +proc incrementTag(lastTag: string; field: Natural): string = + var startPos = + if lastTag[0] in {'0'..'9'}: 0 + else: 1 + var endPos = lastTag.find('.', startPos) + if field >= 1: + for i in 1 .. field: + assert endPos != -1, "the last tag '" & lastTag & "' is missing . periods" + startPos = endPos + 1 + endPos = lastTag.find('.', startPos) + if endPos == -1: + endPos = len(lastTag) + let patchNumber = parseInt(lastTag[startPos.. Date: Sat, 27 May 2023 15:52:08 -0300 Subject: [PATCH 148/489] Refactor pragma inline (#21930) * Add __force_inline support --- changelogs/changelog_2_0_0.md | 3 +++ lib/nimbase.h | 31 ++++++++++++++++++++----------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 31c495a69f..00c20f3978 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -253,6 +253,9 @@ declared when they are not available on the backend. Previously it would call `doAssert false` at runtime despite the condition being compile-time. +- Pragma `{.inline.}` generates `__forceinline` if `__has_attribute(__forceinline)` for GCC and Clang. + + ## Standard library additions and changes [//]: # "Changes:" diff --git a/lib/nimbase.h b/lib/nimbase.h index 3a1289b6fa..1b9268881e 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -84,20 +84,29 @@ __AVR__ # define __DECLSPEC_SUPPORTED 1 #endif -/* calling convention mess ----------------------------------------------- */ -#if defined(__GNUC__) || defined(__TINYC__) - /* these should support C99's inline */ -# define N_INLINE(rettype, name) inline rettype name -#elif defined(__BORLANDC__) || defined(_MSC_VER) -/* Borland's compiler is really STRANGE here; note that the __fastcall - keyword cannot be before the return type, but __inline cannot be after - the return type, so we do not handle this mess in the code generator - but rather here. */ + +/* Calling conventions and inline attributes for the supported C compilers */ +#if defined(__GNUC__) || defined(__clang__) /* GCC and Clang */ +# if __has_attribute(__forceinline) +# define N_INLINE(rettype, name) __attribute__((__forceinline)) rettype name +# else +# define N_INLINE(rettype, name) inline rettype name +# endif +#elif defined(_MSC_VER) /* MSVC */ +# if _MSC_VER > 1200 +# define N_INLINE(rettype, name) __forceinline rettype name +# else +# define N_INLINE(rettype, name) inline rettype name +# endif +#elif defined(__TINYC__) || defined(__BORLANDC__) /* TinyC and BorlandC */ # define N_INLINE(rettype, name) __inline rettype name -#else /* others are less picky: */ -# define N_INLINE(rettype, name) rettype __inline name +#elif defined(__AVR__) /* Atmel Advanced Virtual RISC */ +# define N_INLINE(rettype, name) inline rettype name +#else /* Unsupported C compilers */ +# define N_INLINE(rettype, name) rettype name #endif + #define N_INLINE_PTR(rettype, name) rettype (*name) #if defined(__cplusplus) From 2900987c2fc2109b636f5f92358fd4ac221fe565 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 28 May 2023 05:54:32 +0200 Subject: [PATCH 149/489] Atlas: use colored output (#21939) * Atlas: use colored output * fixes merge conflict * another tiny improvement --- tools/atlas/atlas.nim | 86 ++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 9361cf0431..6065786136 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -10,7 +10,7 @@ ## a Nimble dependency and its dependencies recursively. import std / [parseopt, strutils, os, osproc, tables, sets, json, jsonutils, - parsecfg, streams] + parsecfg, streams, terminal] import parse_requires, osutils, packagesjson from unicode import nil @@ -57,6 +57,7 @@ Options: --workspace=DIR use DIR as workspace --genlock generate a lock file (use with `clone` and `update`) --uselock use the lock file for the build + --colors=on|off turn on|off colored output --version show the version --help show this help """ @@ -113,6 +114,7 @@ type currentDir: string step: int mockupSuccess: bool + noColors: bool proc `==`(a, b: CfgPath): bool {.borrow.} @@ -212,24 +214,30 @@ proc isCleanGit(c: var AtlasContext): string = elif status != 0: result = "'git diff' returned non-zero" -proc message(c: var AtlasContext; category: string; p: PackageName; args: varargs[string]) = - var msg = category & "(" & p.string & ")" - for a in args: - msg.add ' ' - msg.add a +proc message(c: var AtlasContext; category: string; p: PackageName; arg: string) = + var msg = category & "(" & p.string & ") " & arg stdout.writeLine msg -proc info(c: var AtlasContext; p: PackageName; args: varargs[string]) = - message(c, "[Info] ", p, args) - -proc warn(c: var AtlasContext; p: PackageName; args: varargs[string]) = - message(c, "[Warning] ", p, args) +proc warn(c: var AtlasContext; p: PackageName; arg: string) = + if c.noColors: + message(c, "[Warning] ", p, arg) + else: + stdout.styledWriteLine(fgYellow, styleBright, "[Warning] ", resetStyle, fgCyan, "(", p.string, ")", fgDefault, " ", arg) inc c.errors -proc error(c: var AtlasContext; p: PackageName; args: varargs[string]) = - message(c, "[Error] ", p, args) +proc error(c: var AtlasContext; p: PackageName; arg: string) = + if c.noColors: + message(c, "[Error] ", p, arg) + else: + stdout.styledWriteLine(fgRed, styleBright, "[Error] ", resetStyle, fgCyan, "(", p.string, ")", fgDefault, " ", arg) inc c.errors +proc info(c: var AtlasContext; p: PackageName; arg: string) = + if c.noColors: + message(c, "[Info] ", p, arg) + else: + stdout.styledWriteLine(fgGreen, styleBright, "[Info] ", resetStyle, fgCyan, "(", p.string, ")", fgDefault, " ", arg) + proc sameVersionAs(tag, ver: string): bool = const VersionChars = {'0'..'9', '.'} @@ -273,7 +281,7 @@ proc shortToCommit(c: var AtlasContext; short: string): string = proc checkoutGitCommit(c: var AtlasContext; p: PackageName; commit: string) = let (_, status) = exec(c, GitCheckout, [commit]) if status != 0: - error(c, p, "could not checkout commit", commit) + error(c, p, "could not checkout commit " & commit) proc gitPull(c: var AtlasContext; p: PackageName) = let (_, status) = exec(c, GitPull, []) @@ -431,7 +439,7 @@ proc checkoutCommit(c: var AtlasContext; w: Dependency) = if requiredCommit == "" and w.commit == InvalidCommit: warn c, w.name, "package has no tagged releases" else: - warn c, w.name, "cannot find specified version/commit", w.commit + warn c, w.name, "cannot find specified version/commit " & w.commit else: if currentCommit != requiredCommit: # checkout the later commit: @@ -619,7 +627,7 @@ proc patchNimCfg(c: var AtlasContext; deps: seq[CfgPath]; cfgPath: string) = writeFile(cfg, cfgContent) info(c, projectFromCurrentDir(), "updated: " & cfg) -proc error*(msg: string) = +proc fatal*(msg: string) = when defined(debug): writeStackTrace() quit "[Error] " & msg @@ -646,14 +654,14 @@ proc generateDepGraph(g: DepGraph) = else: discard execShellCmd("dot -Tpng -odeps.png deps.dot") -proc installDependencies(c: var AtlasContext; nimbleFile: string) = +proc installDependencies(c: var AtlasContext; nimbleFile: string; startIsDep: bool) = # 1. find .nimble file in CWD # 2. install deps from .nimble var g = DepGraph(nodes: @[]) let (_, pkgname, _) = splitFile(nimbleFile) let dep = Dependency(name: toName(pkgname), url: "", commit: "") discard collectDeps(c, g, -1, dep, nimbleFile) - let paths = traverseLoop(c, g, startIsDep = true) + let paths = traverseLoop(c, g, startIsDep) patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c)) proc updateDir(c: var AtlasContext; dir, filter: string) = @@ -673,7 +681,7 @@ proc updateDir(c: var AtlasContext; dir, filter: string) = if exitCode != 0: error c, pkg, output else: - message(c, "[Hint] ", pkg, "successfully updated") + info(c, pkg, "successfully updated") else: error c, pkg, "could not fetch current branch name" @@ -779,16 +787,15 @@ proc main = var args: seq[string] = @[] template singleArg() = if args.len != 1: - error action & " command takes a single package name" + fatal action & " command takes a single package name" template noArgs() = if args.len != 0: - error action & " command takes no arguments" + fatal action & " command takes no arguments" template projectCmd() = if getCurrentDir() == c.workspace or getCurrentDir() == c.depsDir: - error action & " command must be executed in a project, not in the workspace" - return + fatal action & " command must be executed in a project, not in the workspace" var c = AtlasContext(projectDir: getCurrentDir(), workspace: "") @@ -830,11 +837,16 @@ proc main = c.lockOption = useLock else: writeHelp() + of "colors": + case val.normalize + of "off": c.noColors = true + of "on": c.noColors = false + else: writeHelp() else: writeHelp() of cmdEnd: assert false, "cannot happen" if c.workspace.len > 0: - if not dirExists(c.workspace): error "Workspace directory '" & c.workspace & "' not found." + if not dirExists(c.workspace): fatal "Workspace directory '" & c.workspace & "' not found." elif action != "init": when MockupRun: c.workspace = autoWorkspace() @@ -842,17 +854,16 @@ proc main = c.workspace = detectWorkspace() if c.workspace.len > 0: readConfig c - echo "Using workspace ", c.workspace + info c, toName(c.workspace), "is the current workspace" elif action notin ["search", "list"]: - error "No workspace found. Run `atlas init` if you want this current directory to be your workspace." - return + fatal "No workspace found. Run `atlas init` if you want this current directory to be your workspace." when MockupRun: c.depsDir = c.workspace case action of "": - error "No action." + fatal "No action." of "init": c.workspace = getCurrentDir() createWorkspaceIn c.workspace, c.depsDir @@ -862,20 +873,20 @@ proc main = patchNimCfg c, deps, if c.cfgHere: getCurrentDir() else: findSrcDir(c) when MockupRun: if not c.mockupSuccess: - error "There were problems." + fatal "There were problems." else: if c.errors > 0: - error "There were problems." + fatal "There were problems." of "use": projectCmd() singleArg() let nimbleFile = patchNimbleFile(c, args[0]) if nimbleFile.len > 0: - installDependencies(c, nimbleFile) + installDependencies(c, nimbleFile, startIsDep = false) of "install": projectCmd() if args.len > 1: - error "install command takes a single argument" + fatal "install command takes a single argument" var nimbleFile = "" if args.len == 1: nimbleFile = args[0] @@ -884,9 +895,9 @@ proc main = nimbleFile = x break if nimbleFile.len == 0: - error "could not find a .nimble file" + fatal "could not find a .nimble file" else: - installDependencies(c, nimbleFile) + installDependencies(c, nimbleFile, startIsDep = true) of "refresh": noArgs() updatePackages(c) @@ -904,7 +915,7 @@ proc main = if fileExists(args[0]): echo toJson(extractRequiresInfo(args[0])) else: - error "File does not exist: " & args[0] + fatal "File does not exist: " & args[0] of "tag": projectCmd() if args.len == 0: @@ -917,7 +928,7 @@ proc main = else: var field: SemVerField try: field = parseEnum[SemVerField](args[0]) - except: error "tag command takes one of 'patch' 'minor' 'major', a SemVer tag, or a letter from 'a' to 'z'" + except: fatal "tag command takes one of 'patch' 'minor' 'major', a SemVer tag, or a letter from 'a' to 'z'" tag(c, ord(field)) of "build", "test", "doc", "tasks": projectCmd() @@ -926,8 +937,7 @@ proc main = projectCmd() nimbleExec("", args) else: - error "Invalid action: " & action + fatal "Invalid action: " & action when isMainModule: main() - From c2abcb06cc3ad4a99f25df48c56dc862fd52877a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 28 May 2023 14:28:49 +0800 Subject: [PATCH 150/489] ship atlas and build documentation (#21945) * ship atlas and build documentation * move atlas.md and link it in tools' index --- compiler/installer.ini | 1 + {tools/atlas => doc}/atlas.md | 0 doc/tools.md | 4 ++++ koch.nim | 1 + 4 files changed, 6 insertions(+) rename {tools/atlas => doc}/atlas.md (100%) diff --git a/compiler/installer.ini b/compiler/installer.ini index 4d0eab86d1..49ee59b0d0 100644 --- a/compiler/installer.ini +++ b/compiler/installer.ini @@ -92,6 +92,7 @@ Files: "bin/nimgrab.exe" Files: "bin/nimpretty.exe" Files: "bin/testament.exe" Files: "bin/nim-gdb.bat" +Files: "bin/atlas.exe" Files: "koch.exe" Files: "finish.exe" diff --git a/tools/atlas/atlas.md b/doc/atlas.md similarity index 100% rename from tools/atlas/atlas.md rename to doc/atlas.md diff --git a/doc/tools.md b/doc/tools.md index 6849103f9e..f3fa9eb0cc 100644 --- a/doc/tools.md +++ b/doc/tools.md @@ -40,3 +40,7 @@ The standard distribution ships with the following tools: [simulated Dry-Runs](https://en.wikipedia.org/wiki/Dry_run_(testing)), has logging, can generate HTML reports, skip tests from a file, and more, so can be useful to run your tests, even the most complex ones. + +- | [atlas](atlas.html) + | `atlas`:cmd: is a simple package cloner tool that automates some of the + workflows and needs for Nim's stdlib evolution. diff --git a/koch.nim b/koch.nim index fe5427d43a..490b8925ee 100644 --- a/koch.nim +++ b/koch.nim @@ -179,6 +179,7 @@ proc bundleWinTools(args: string) = buildVccTool(args) nimCompile("tools/nimgrab.nim", options = "-d:ssl " & args) nimCompile("tools/nimgrep.nim", options = args) + nimCompile("tools/atlas/atlas.nim", options = args) nimCompile("testament/testament.nim", options = args) when false: # not yet a tool worth including From 9cb0fcf319976431a02d3f64520fb395c36aa70e Mon Sep 17 00:00:00 2001 From: Gruruya Date: Sun, 28 May 2023 02:57:29 -0400 Subject: [PATCH 151/489] Atlas: checkout latest tagged commit with `atlas use` (#21944) Now any deps with unspecified version reqs will checkout the last tagged commit instead of the first commit. --- tools/atlas/atlas.nim | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 6065786136..dc3d67fbe7 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -128,6 +128,7 @@ type GitTag = "git tag", GitTags = "git show-ref --tags", GitLastTaggedRef = "git rev-list --tags --max-count=1", + GitDescribe = "git describe", GitRevParse = "git rev-parse", GitCheckout = "git checkout", GitPush = "git push origin", @@ -155,7 +156,7 @@ proc exec(c: var AtlasContext; cmd: Command; args: openArray[string]): (string, when MockupRun: assert TestLog[c.step].cmd == cmd, $(TestLog[c.step].cmd, cmd) case cmd - of GitDiff, GitTag, GitTags, GitLastTaggedRef, GitRevParse, GitPush, GitPull, GitCurrentCommit: + of GitDiff, GitTag, GitTags, GitLastTaggedRef, GitDescribe, GitRevParse, GitPush, GitPull, GitCurrentCommit: result = (TestLog[c.step].output, TestLog[c.step].exitCode) of GitCheckout: assert args[0] == TestLog[c.step].output @@ -252,6 +253,18 @@ proc sameVersionAs(tag, ver: string): bool = result = safeCharAt(tag, idx-1) notin VersionChars and safeCharAt(tag, idx+ver.len) notin VersionChars +proc gitDescribeRefTag(c: var AtlasContext; commit: string): string = + let (lt, status) = exec(c, GitDescribe, ["--tags", commit]) + result = if status == 0: strutils.strip(lt) else: "" + +proc getLastTaggedCommit(c: var AtlasContext): string = + let (ltr, status) = exec(c, GitLastTaggedRef, []) + if status == 0: + let lastTaggedRef = ltr.strip() + let lastTag = gitDescribeRefTag(c, lastTaggedRef) + if lastTag.len != 0: + result = lastTag + proc versionToCommit(c: var AtlasContext; d: Dependency): string = let (outp, status) = exec(c, GitTags, []) if status == 0: @@ -264,7 +277,9 @@ proc versionToCommit(c: var AtlasContext; d: Dependency): string = if commitsAndTags[1].sameVersionAs(d.commit): return commitsAndTags[0] of strictlyLess: - if d.commit == InvalidCommit or not commitsAndTags[1].sameVersionAs(d.commit): + if d.commit == InvalidCommit: + return getLastTaggedCommit(c) + elif not commitsAndTags[1].sameVersionAs(d.commit): return commitsAndTags[0] of strictlyGreater: if commitsAndTags[1].sameVersionAs(d.commit): @@ -322,10 +337,8 @@ proc incrementLastTag(c: var AtlasContext; field: Natural): string = if status == 0: let lastTaggedRef = ltr.strip() - (lt, _) = osproc.execCmdEx("git describe --tags " & lastTaggedRef) - lastTag = lt.strip() - (cc, _) = exec(c, GitCurrentCommit, []) - currentCommit = cc.strip() + lastTag = gitDescribeRefTag(c, lastTaggedRef) + currentCommit = exec(c, GitCurrentCommit, [])[0].strip() if lastTaggedRef == currentCommit: info c, c.projectDir.PackageName, "the current commit '" & currentCommit & "' is already tagged '" & lastTag & "'" @@ -718,7 +731,7 @@ proc patchNimbleFile(c: var AtlasContext; dep: string): string = break if not found: - let line = "requires \"$1#head\"\n" % dep.escape("", "") + let line = "requires \"$1\"\n" % dep.escape("", "") if result.len > 0: let oldContent = readFile(result) writeFile result, oldContent & "\n" & line From 5997324709788aaf0e5a17aaa1ccfce208f84ce1 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 28 May 2023 14:58:23 +0800 Subject: [PATCH 152/489] fixes atlas logging colors on windows (#21946) fixes atlas logging colors --- tools/atlas/atlas.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index dc3d67fbe7..dc38c4e5ba 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -223,21 +223,21 @@ proc warn(c: var AtlasContext; p: PackageName; arg: string) = if c.noColors: message(c, "[Warning] ", p, arg) else: - stdout.styledWriteLine(fgYellow, styleBright, "[Warning] ", resetStyle, fgCyan, "(", p.string, ")", fgDefault, " ", arg) + stdout.styledWriteLine(fgYellow, styleBright, "[Warning] ", resetStyle, fgCyan, "(", p.string, ")", resetStyle, " ", arg) inc c.errors proc error(c: var AtlasContext; p: PackageName; arg: string) = if c.noColors: message(c, "[Error] ", p, arg) else: - stdout.styledWriteLine(fgRed, styleBright, "[Error] ", resetStyle, fgCyan, "(", p.string, ")", fgDefault, " ", arg) + stdout.styledWriteLine(fgRed, styleBright, "[Error] ", resetStyle, fgCyan, "(", p.string, ")", resetStyle, " ", arg) inc c.errors proc info(c: var AtlasContext; p: PackageName; arg: string) = if c.noColors: message(c, "[Info] ", p, arg) else: - stdout.styledWriteLine(fgGreen, styleBright, "[Info] ", resetStyle, fgCyan, "(", p.string, ")", fgDefault, " ", arg) + stdout.styledWriteLine(fgGreen, styleBright, "[Info] ", resetStyle, fgCyan, "(", p.string, ")", resetStyle, " ", arg) proc sameVersionAs(tag, ver: string): bool = const VersionChars = {'0'..'9', '.'} From 7ebb042f79b6c796e08e6ff89eaba3a9a67f9d6d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 28 May 2023 18:18:30 +0200 Subject: [PATCH 153/489] Atlas: some final cleanups (#21947) --- doc/atlas.md | 20 ++++++++------------ doc/tools.md | 4 ++-- tools/atlas/atlas.nim | 19 ++++++++++++------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/doc/atlas.md b/doc/atlas.md index d0a45c866d..2a4171a8be 100644 --- a/doc/atlas.md +++ b/doc/atlas.md @@ -1,7 +1,7 @@ # Atlas Package Cloner -Atlas is a simple package cloner tool that automates some of the -workflows and needs for Nim's stdlib evolution. +Atlas is a simple package cloner tool. It manages an isolated workspace that +contains projects and dependencies. Atlas is compatible with Nimble in the sense that it supports the Nimble file format. @@ -103,7 +103,7 @@ For example: ``` -### Clone/Update +### Clone/Update / Clones a URL and all of its dependencies (recursively) into the workspace. Creates or patches a `nim.cfg` file with the required `--path` entries. @@ -111,12 +111,8 @@ Creates or patches a `nim.cfg` file with the required `--path` entries. **Note**: Due to the used algorithms an `update` is the same as a `clone`. -### Clone/Update - -The `` is translated into an URL via `packages.json` and -then `clone ` is performed. - -**Note**: Due to the used algorithms an `update` is the same as a `clone`. +If a `` is given instead the name is first translated into an URL +via `packages.json` or via a github search. ### Search @@ -129,10 +125,10 @@ in its description (or name or list of tags). Use the .nimble file to setup the project's dependencies. -### UpdateWorkspace [filter] +### UpdateProjects / updateDeps [filter] -Update every package in the workspace that has a remote URL that -matches `filter` if a filter is given. The package is only updated +Update every project / dependency in the workspace that has a remote URL that +matches `filter` if a filter is given. The project / dependency is only updated if there are no uncommitted changes. ### Others diff --git a/doc/tools.md b/doc/tools.md index f3fa9eb0cc..43b7f6651e 100644 --- a/doc/tools.md +++ b/doc/tools.md @@ -42,5 +42,5 @@ The standard distribution ships with the following tools: so can be useful to run your tests, even the most complex ones. - | [atlas](atlas.html) - | `atlas`:cmd: is a simple package cloner tool that automates some of the - workflows and needs for Nim's stdlib evolution. + | `atlas`:cmd: is a simple package cloner tool. It manages an isolated workspace that + contains projects and dependencies. diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index dc38c4e5ba..a8b7371030 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -106,7 +106,7 @@ type keepCommits: bool cfgHere: bool p: Table[string, string] # name -> url mapping - errors: int + errors, warnings: int lockOption: LockOption lockFileToWrite: seq[LockFileEntry] lockFileToUse: Table[string, LockFileEntry] @@ -224,7 +224,7 @@ proc warn(c: var AtlasContext; p: PackageName; arg: string) = message(c, "[Warning] ", p, arg) else: stdout.styledWriteLine(fgYellow, styleBright, "[Warning] ", resetStyle, fgCyan, "(", p.string, ")", resetStyle, " ", arg) - inc c.errors + inc c.warnings proc error(c: var AtlasContext; p: PackageName; arg: string) = if c.noColors: @@ -239,6 +239,8 @@ proc info(c: var AtlasContext; p: PackageName; arg: string) = else: stdout.styledWriteLine(fgGreen, styleBright, "[Info] ", resetStyle, fgCyan, "(", p.string, ")", resetStyle, " ", arg) +template projectFromCurrentDir(): PackageName = PackageName(getCurrentDir().splitPath.tail) + proc sameVersionAs(tag, ver: string): bool = const VersionChars = {'0'..'9', '.'} @@ -317,14 +319,16 @@ proc pushTag(c: var AtlasContext; tag: string) = else: info(c, c.projectDir.PackageName, "successfully pushed tag: " & tag) -proc incrementTag(lastTag: string; field: Natural): string = +proc incrementTag(c: var AtlasContext; lastTag: string; field: Natural): string = var startPos = if lastTag[0] in {'0'..'9'}: 0 else: 1 var endPos = lastTag.find('.', startPos) if field >= 1: for i in 1 .. field: - assert endPos != -1, "the last tag '" & lastTag & "' is missing . periods" + if endPos == -1: + error c, projectFromCurrentDir(), "the last tag '" & lastTag & "' is missing . periods" + return "" startPos = endPos + 1 endPos = lastTag.find('.', startPos) if endPos == -1: @@ -344,7 +348,7 @@ proc incrementLastTag(c: var AtlasContext; field: Natural): string = info c, c.projectDir.PackageName, "the current commit '" & currentCommit & "' is already tagged '" & lastTag & "'" lastTag else: - incrementTag(lastTag, field) + incrementTag(c, lastTag, field) else: "v0.0.1" # assuming no tags have been made yet proc tag(c: var AtlasContext; tag: string) = @@ -602,8 +606,6 @@ const configPatternBegin = "############# begin Atlas config section ##########\n" configPatternEnd = "############# end Atlas config section ##########\n" -template projectFromCurrentDir(): PackageName = PackageName(getCurrentDir().splitPath.tail) - proc patchNimCfg(c: var AtlasContext; deps: seq[CfgPath]; cfgPath: string) = var paths = "--noNimblePath\n" for d in deps: @@ -936,6 +938,9 @@ proc main = elif args[0].len == 1 and args[0][0] in {'a'..'z'}: let field = ord(args[0][0]) - ord('a') tag(c, field) + elif args[0].len == 1 and args[0][0] in {'A'..'Z'}: + let field = ord(args[0][0]) - ord('A') + tag(c, field) elif '.' in args[0]: tag(c, args[0]) else: From 8c55e2999b27e3f088fca2e61739b33498fb07ef Mon Sep 17 00:00:00 2001 From: Simon Krauter Date: Sun, 28 May 2023 14:40:37 -0300 Subject: [PATCH 154/489] Fix documentation typo in endians.nim (#21949) --- lib/pure/endians.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/endians.nim b/lib/pure/endians.nim index a0dc97c1da..4c1d45ae5e 100644 --- a/lib/pure/endians.nim +++ b/lib/pure/endians.nim @@ -10,7 +10,7 @@ ## This module contains helpers that deal with different byte orders ## (`endian`:idx:). ## -## Endianess is the order of bytes of a value in memory. Big-endian means that +## Endianness is the order of bytes of a value in memory. Big-endian means that ## the most significant byte is stored at the smallest memory address, ## while little endian means that the least-significant byte is stored ## at the smallest address. See also https://en.wikipedia.org/wiki/Endianness. From f47b27d5320ce76757dc67936da9580f94ede293 Mon Sep 17 00:00:00 2001 From: heterodoxic <122719743+heterodoxic@users.noreply.github.com> Date: Mon, 29 May 2023 14:55:04 +0200 Subject: [PATCH 155/489] prevent spamming of thread local forward declarations in C/C++ output (#21955) --- compiler/cgen.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index b332c6cd76..985af4bbe7 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1387,10 +1387,10 @@ proc genVarPrototype(m: BModule, n: PNode) = if sym.owner.id != m.module.id: # else we already have the symbol generated! assert(sym.loc.r != "") + incl(m.declaredThings, sym.id) if sfThread in sym.flags: declareThreadVar(m, sym, true) else: - incl(m.declaredThings, sym.id) if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0: m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)] m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ") From 108410ac343c0b5e34f58e7aee2aa6a39850e3d9 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 29 May 2023 20:59:59 +0800 Subject: [PATCH 156/489] fixes fieldDefect loses enum type info in ORC; consistent with VM and refc (#21954) fixes fieldDefect loses enum type info in ORC --- compiler/ccgexprs.nim | 23 +++++++++++++---------- lib/system/chcks.nim | 4 ++++ tests/misc/trunner.nim | 3 +-- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b2510f5be4..6702c75370 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -933,10 +933,17 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = var discIndex = newRopeAppender() rdSetElemLoc(p.config, v, u.t, discIndex) if optTinyRtti in p.config.globalOptions: - # not sure how to use `genEnumToStr` here - if p.config.getStdlibVersion < (1, 5, 1): - const code = "{ #raiseFieldError($1); " - linefmt(p, cpsStmts, code, [strLit]) + let base = disc.typ.skipTypes(abstractInst+{tyRange}) + case base.kind + of tyEnum: + const code = "{ #raiseFieldErrorStr($1, $2); " + let toStrProc = getToStringProc(p.module.g.graph, base) + # XXX need to modify this logic for IC. + # need to analyze nkFieldCheckedExpr and marks procs "used" like range checks in dce + var toStr: TLoc + expr(p, newSymNode(toStrProc), toStr) + let enumStr = "$1($2)" % [rdLoc(toStr), rdLoc(v)] + linefmt(p, cpsStmts, code, [strLit, enumStr]) else: const code = "{ #raiseFieldError2($1, (NI)$2); " linefmt(p, cpsStmts, code, [strLit, discIndex]) @@ -947,12 +954,8 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = var firstLit = newRopeAppender() int64Literal(cast[int](first), firstLit) let discName = genTypeInfo(p.config, p.module, disc.sym.typ, e.info) - if p.config.getStdlibVersion < (1,5,1): - const code = "{ #raiseFieldError($1); " - linefmt(p, cpsStmts, code, [strLit]) - else: - const code = "{ #raiseFieldError2($1, #reprDiscriminant(((NI)$2) + (NI)$3, $4)); " - linefmt(p, cpsStmts, code, [strLit, discIndex, firstLit, discName]) + const code = "{ #raiseFieldError2($1, #reprDiscriminant(((NI)$2) + (NI)$3, $4)); " + linefmt(p, cpsStmts, code, [strLit, discIndex, firstLit, discName]) raiseInstr(p, p.s(cpsStmts)) linefmt p, cpsStmts, "}$n", [] diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index dd26d140d4..b488559644 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -38,6 +38,10 @@ when defined(nimV2): proc raiseFieldError2(f: string, discVal: int) {.compilerproc, noinline.} = ## raised when field is inaccessible given runtime value of discriminant sysFatal(FieldDefect, f & $discVal & "'") + + proc raiseFieldErrorStr(f: string, discVal: string) {.compilerproc, noinline.} = + ## raised when field is inaccessible given runtime value of discriminant + sysFatal(FieldDefect, formatFieldDefect(f, discVal)) else: proc raiseFieldError2(f: string, discVal: string) {.compilerproc, noinline.} = ## raised when field is inaccessible given runtime value of discriminant diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index aca19f72de..0fc7dcdfd7 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -434,7 +434,6 @@ mused3.nim(75, 10) Hint: duplicate import of 'mused3a'; previous import here: mu fn("-d:case2 --gc:refc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" fn("-d:case1 -b:js"): """mfield_defect.nim(25, 15) Error: field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" fn("-d:case2 -b:js"): """field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" - # 3 instead of k3, because of lack of RTTI - fn("-d:case2 --gc:arc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = 3'""" + fn("-d:case2 --gc:arc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'""" else: discard # only during debugging, tests added here will run with `-d:nimTestsTrunnerDebugging` enabled From ef060e818468da0bd53d52a501443ce3d01f06a1 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Mon, 29 May 2023 16:51:31 +0100 Subject: [PATCH 157/489] Suggest files and paths modules (#21950) --- lib/pure/os.nim | 1 + lib/std/files.nim | 3 +++ lib/std/paths.nim | 3 +++ 3 files changed, 7 insertions(+) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index e9408f8262..434fc3a26e 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -22,6 +22,7 @@ runnableExamples: assert myFile.changeFileExt("c") == "/path/to/my/file.c" ## **See also:** +## * `paths `_ and `files `_ modules for high-level file manipulation ## * `osproc module `_ for process communication beyond ## `execShellCmd proc`_ ## * `uri module `_ diff --git a/lib/std/files.nim b/lib/std/files.nim index 138bb5234e..b2161218b6 100644 --- a/lib/std/files.nim +++ b/lib/std/files.nim @@ -1,4 +1,7 @@ ## This module implements file handling. +## +## **See also:** +## * `paths module `_ for path manipulation from paths import Path, ReadDirEffect, WriteDirEffect diff --git a/lib/std/paths.nim b/lib/std/paths.nim index c290969827..f675e7445a 100644 --- a/lib/std/paths.nim +++ b/lib/std/paths.nim @@ -1,4 +1,7 @@ ## This module implements path handling. +## +## **See also:** +## * `files module `_ for file access import std/private/osseps export osseps From 244565397ddcd4af5a49b47b7874fe82e018e429 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 29 May 2023 21:31:53 +0200 Subject: [PATCH 158/489] fixes #21734; backport (#21957) --- lib/pure/ioselects/ioselectors_epoll.nim | 2 +- lib/pure/selectors.nim | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim index 08cb6ed744..510de8c514 100644 --- a/lib/pure/ioselects/ioselectors_epoll.nim +++ b/lib/pure/ioselects/ioselectors_epoll.nim @@ -138,7 +138,7 @@ template checkFd(s, f) = var numFD = s.numFD while numFD <= f: numFD *= 2 when hasThreadSupport: - s.fds = reallocSharedArray(s.fds, numFD) + s.fds = reallocSharedArray(s.fds, s.numFD, numFD) else: s.fds.setLen(numFD) for i in s.numFD ..< numFD: diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index fc65e0e9b5..2d10e3f321 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -247,8 +247,8 @@ else: proc allocSharedArray[T](nsize: int): ptr SharedArray[T] = result = cast[ptr SharedArray[T]](allocShared0(sizeof(T) * nsize)) - proc reallocSharedArray[T](sa: ptr SharedArray[T], nsize: int): ptr SharedArray[T] = - result = cast[ptr SharedArray[T]](reallocShared(sa, sizeof(T) * nsize)) + proc reallocSharedArray[T](sa: ptr SharedArray[T], oldsize, nsize: int): ptr SharedArray[T] = + result = cast[ptr SharedArray[T]](reallocShared0(sa, oldsize * sizeof(T), sizeof(T) * nsize)) proc deallocSharedArray[T](sa: ptr SharedArray[T]) = deallocShared(cast[pointer](sa)) From 171b916613bd0835ff3bf57061bd206a3df25f5e Mon Sep 17 00:00:00 2001 From: Mamy Ratsimbazafy Date: Tue, 30 May 2023 04:46:24 +0200 Subject: [PATCH 159/489] Add anti-regression for #21958 (#21960) Add anti-regression test to close #21958 --- tests/generics/t21958.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/generics/t21958.nim diff --git a/tests/generics/t21958.nim b/tests/generics/t21958.nim new file mode 100644 index 0000000000..f566b57cbb --- /dev/null +++ b/tests/generics/t21958.nim @@ -0,0 +1,11 @@ +discard """ + action: compile +""" + +type + Ct*[T: SomeUnsignedInt] = distinct T + +template `shr`*[T: Ct](x: T, y: SomeInteger): T = T(T.T(x) shr y) + +var x: Ct[uint64] +let y {.used.} = x shr 2 \ No newline at end of file From 7e055413f9bbec81fc9b7e1542695f2886787566 Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 30 May 2023 08:35:29 +0300 Subject: [PATCH 160/489] hot code reloading: fix regression? and PreMain with arc/orc (#21940) * fix PreMain for hot code reloading with arc/orc * fix regression? actually test nimhcr_basic --- compiler/ccgtypes.nim | 4 +++- compiler/cgen.nim | 15 +++++++++------ testament/categories.nim | 7 +++++-- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 33b0d92d3b..d6835cc501 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1158,6 +1158,8 @@ proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false) # (instead of forward declaration) or header for function body with "_actual" postfix let asPtrStr = rope(if asPtr: "_PTR" else: "") var name = prc.loc.r + if not asPtr and isReloadable(m, prc): + name.add("_actual") # careful here! don't access ``prc.ast`` as that could reload large parts of # the object graph! if prc.constraint.isNil: @@ -1809,4 +1811,4 @@ proc genTypeSection(m: BModule, n: PNode) = if sfExportc in n[i][0][p].sym.flags: discard getTypeDescAux(m, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind)) if m.g.generatedHeader != nil: - discard getTypeDescAux(m.g.generatedHeader, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind)) \ No newline at end of file + discard getTypeDescAux(m.g.generatedHeader, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind)) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 985af4bbe7..8c69463003 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1479,12 +1479,15 @@ proc genMainProc(m: BModule) = [handle, strLit]) preMainCode.add(loadLib("hcr_handle", "hcrGetProc")) - preMainCode.add("\tvoid* rtl_handle;\L") - preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom")) - preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr")) - preMainCode.add("\tinner = PreMain;\L") - preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L") - preMainCode.add("\t(*inner)();\L") + if m.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}: + preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix]) + else: + preMainCode.add("\tvoid* rtl_handle;\L") + preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom")) + preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr")) + preMainCode.add("\tinner = $1PreMain;\L" % [rope m.config.nimMainPrefix]) + preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L") + preMainCode.add("\t(*inner)();\L") else: preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix]) diff --git a/testament/categories.nim b/testament/categories.nim index d5964225f3..946f99fd6a 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -80,9 +80,12 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string, isOrc = testSpec r, makeTest("tests/dll/client.nim", options & " --threads:on" & rpath, cat) testSpec r, makeTest("tests/dll/nimhcr_unit.nim", options & " --threads:off" & rpath, cat) testSpec r, makeTest("tests/dll/visibility.nim", options & " --threads:off" & rpath, cat) - testSpec r, makeTest("tests/dll/nimhcr_basic.nim", options & " --threads:off" & rpath, cat) - if "boehm" notin options: + if "boehm" notin options and not isOrc: + # hcr tests + + testSpec r, makeTest("tests/dll/nimhcr_basic.nim", options & " --threads:off --forceBuild --hotCodeReloading:on " & rpath, cat) + # force build required - see the comments in the .nim file for more details var hcri = makeTest("tests/dll/nimhcr_integration.nim", options & " --threads:off --forceBuild --hotCodeReloading:on" & rpath, cat) From 40f88da90b0589a91f4f60b2ebf49859b79e2247 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 30 May 2023 19:40:09 +0800 Subject: [PATCH 161/489] alternative to #21914; split, rsplit now forbid an empty separator (#21961) --- changelogs/changelog_2_0_0.md | 1 + lib/pure/strutils.nim | 26 ++++++++++++++++++++++---- tests/stdlib/tstrutils.nim | 14 ++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 00c20f3978..4a15855f4c 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -255,6 +255,7 @@ - Pragma `{.inline.}` generates `__forceinline` if `__has_attribute(__forceinline)` for GCC and Clang. +- `strutils.split` and `strutils.rsplit` now forbid an empty separator. ## Standard library additions and changes diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 0a77e8bf6f..fe9f2a8c3d 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -487,12 +487,15 @@ iterator split*(s: string, seps: set[char] = Whitespace, ## "22" ## "08" ## "08.398990" + ## + ## .. warning:: `seps` should not be empty. ## ## See also: ## * `rsplit iterator<#rsplit.i,string,set[char],int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ ## * `split func<#split,string,set[char],int>`_ + assert seps.card > 0, "Empty separator" splitCommon(s, seps, maxsplit, 1) iterator split*(s: string, sep: string, maxsplit: int = -1): string = @@ -512,11 +515,14 @@ iterator split*(s: string, sep: string, maxsplit: int = -1): string = ## "is" ## "corrupted" ## + ## .. warning:: `sep` should not be empty. + ## ## See also: ## * `rsplit iterator<#rsplit.i,string,string,int,bool>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ ## * `split func<#split,string,string,int>`_ + assert sep.len > 0, "Empty separator" splitCommon(s, sep, maxsplit, sep.len) @@ -585,13 +591,16 @@ iterator rsplit*(s: string, seps: set[char] = Whitespace, ## "bar" ## "foo" ## - ## Substrings are separated from the right by the set of chars `seps` + ## Substrings are separated from the right by the set of chars `seps`. + ## + ## .. warning:: `seps` should not be empty. ## ## See also: ## * `split iterator<#split.i,string,set[char],int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ ## * `rsplit func<#rsplit,string,set[char],int>`_ + assert seps.card > 0, "Empty separator" rsplitCommon(s, seps, maxsplit, 1) iterator rsplit*(s: string, sep: string, maxsplit: int = -1, @@ -610,13 +619,16 @@ iterator rsplit*(s: string, sep: string, maxsplit: int = -1, ## "bar" ## "foo" ## - ## Substrings are separated from the right by the string `sep` + ## Substrings are separated from the right by the string `sep`. + ## + ## .. warning:: `sep` should not be empty. ## ## See also: ## * `split iterator<#split.i,string,string,int>`_ ## * `splitLines iterator<#splitLines.i,string>`_ ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ ## * `rsplit func<#rsplit,string,string,int>`_ + assert sep.len > 0, "Empty separator" rsplitCommon(s, sep, maxsplit, sep.len) iterator splitLines*(s: string, keepEol = false): string = @@ -728,6 +740,8 @@ func split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): seq[ ## The same as the `split iterator <#split.i,string,set[char],int>`_ (see its ## documentation), but is a func that returns a sequence of substrings. ## + ## .. warning:: `seps` should not be empty. + ## ## See also: ## * `split iterator <#split.i,string,set[char],int>`_ ## * `rsplit func<#rsplit,string,set[char],int>`_ @@ -745,6 +759,8 @@ func split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, ## Substrings are separated by the string `sep`. This is a wrapper around the ## `split iterator <#split.i,string,string,int>`_. ## + ## .. warning:: `sep` should not be empty. + ## ## See also: ## * `split iterator <#split.i,string,string,int>`_ ## * `rsplit func<#rsplit,string,string,int>`_ @@ -757,8 +773,6 @@ func split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, doAssert "a largely spaced sentence".split(" ") == @["a", "", "largely", "", "", "", "spaced", "sentence"] doAssert "a largely spaced sentence".split(" ", maxsplit = 1) == @["a", " largely spaced sentence"] - doAssert(sep.len > 0) - accResult(split(s, sep, maxsplit)) func rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string] {.rtl, @@ -808,6 +822,8 @@ func rsplit*(s: string, seps: set[char] = Whitespace, ## .. code-block:: nim ## @["Root#Object#Method", "Index"] ## + ## .. warning:: `seps` should not be empty. + ## ## See also: ## * `rsplit iterator <#rsplit.i,string,set[char],int>`_ ## * `split func<#split,string,set[char],int>`_ @@ -835,6 +851,8 @@ func rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, ## .. code-block:: nim ## @["Root#Object#Method", "Index"] ## + ## .. warning:: `sep` should not be empty. + ## ## See also: ## * `rsplit iterator <#rsplit.i,string,string,int,bool>`_ ## * `split func<#split,string,string,int>`_ diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 67eb5cf3a5..d53e9d8b4b 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -53,6 +53,13 @@ template main() = doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example "] doAssert s.split(' ', maxsplit = 1) == @["", "this is an example "] doAssert s.split(" ", maxsplit = 4) == @["", "this", "is", "an", "example "] + # Empty string: + doAssert "".split() == @[""] + doAssert "".split(" ") == @[""] + doAssert "".split({' '}) == @[""] + # Empty separators: + doAssertRaises(AssertionDefect): discard s.split({}) + doAssertRaises(AssertionDefect): discard s.split("") block: # splitLines let fixture = "a\nb\rc\r\nd" @@ -69,6 +76,13 @@ template main() = doAssert rsplit(":foo:bar", sep = ':', maxsplit = 2) == @["", "foo", "bar"] doAssert rsplit(":foo:bar", sep = ':', maxsplit = 3) == @["", "foo", "bar"] doAssert rsplit("foothebar", sep = "the") == @["foo", "bar"] + # Empty string: + doAssert "".rsplit() == @[""] + doAssert "".rsplit(" ") == @[""] + doAssert "".rsplit({' '}) == @[""] + # Empty separators: + doAssertRaises(AssertionDefect): discard "".rsplit({}) + doAssertRaises(AssertionDefect): discard "".rsplit("") block: # splitWhitespace let s = " this is an example " From 546af8c571fb4f09187e1b343b11cf449657bad8 Mon Sep 17 00:00:00 2001 From: heterodoxic <122719743+heterodoxic@users.noreply.github.com> Date: Tue, 30 May 2023 13:41:56 +0200 Subject: [PATCH 162/489] simple micro-optimizations of ropes' runtime-formatting (#21962) --- compiler/cgen.nim | 10 +++------- compiler/ropes.nim | 13 +++++-------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 8c69463003..fe5c253dd0 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -216,13 +216,9 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope = elif frmt[i] == '#' and frmt[i+1] == '#': inc(i, 2) strLit.add("#") - - var start = i - while i < frmt.len: - if frmt[i] != '$' and frmt[i] != '#': inc(i) - else: break - if i - 1 >= start: - strLit.add(substr(frmt, start, i - 1)) + else: + strLit.add(frmt[i]) + inc(i) flushStrLit() result.add newCall(ident"rope", resVar) diff --git a/compiler/ropes.nim b/compiler/ropes.nim index 5bf1543931..e96a3ed3ae 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -21,8 +21,8 @@ type # though it is not necessary) Rope* = string -proc newRopeAppender*(): string {.inline.} = - result = newString(0) +proc newRopeAppender*(cap = 80): string {.inline.} = + result = newStringOfCap(cap) proc freeze*(r: Rope) {.inline.} = discard @@ -102,12 +102,9 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope = inc(i) else: doAssert false, "invalid format string: " & frmt - var start = i - while i < frmt.len: - if frmt[i] != '$': inc(i) - else: break - if i - 1 >= start: - result.add(substr(frmt, start, i - 1)) + else: + result.add(frmt[i]) + inc(i) proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope = runtimeFormat(frmt, args) From 4d202274384ef13baf206ece37dde34caf6a54f8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 30 May 2023 14:00:09 +0200 Subject: [PATCH 163/489] Atlas: URL rewrite rules; --autoinit flag (#21963) --- doc/atlas.md | 37 +++++ tools/atlas/atlas.nim | 67 +++++++-- tools/atlas/compiledpatterns.nim | 246 +++++++++++++++++++++++++++++++ 3 files changed, 340 insertions(+), 10 deletions(-) create mode 100644 tools/atlas/compiledpatterns.nim diff --git a/doc/atlas.md b/doc/atlas.md index 2a4171a8be..c6b8c7a9a4 100644 --- a/doc/atlas.md +++ b/doc/atlas.md @@ -23,10 +23,12 @@ to create a workspace out of the current working directory. Projects plus their dependencies are stored in a workspace: +``` $workspace / main project $workspace / other project $workspace / _deps / dependency A $workspace / _deps / dependency B +``` The deps directory can be set via `--deps:DIR` during `atlas init`. @@ -134,3 +136,38 @@ if there are no uncommitted changes. ### Others Run `atlas --help` for more features. + + +### Overrides + +You can override how Atlas resolves a package name or a URL. The overrides use +a simple pattern matching language and are flexible enough to integrate private +gitlab repositories. + +To setup an override file, edit the `$workspace/atlas.workspace` file to contain +a line like `overrides="urls.rules"`. Then create a file `urls.rules` that can +contain lines like: + +``` +customProject -> https://gitlab.company.com/customProject +https://github.com/araq/ormin -> https://github.com/useMyForkInstead/ormin +``` + +The `$` has a special meaning in a pattern: + +================= ======================================================== +``$$`` Matches a single dollar sign. +``$*`` Matches until the token following the ``$*`` was found. + The match is allowed to be of 0 length. +``$+`` Matches until the token following the ``$+`` was found. + The match must consist of at least one char. +``$s`` Skips optional whitespace. +================= ======================================================== + +For example, here is how to override any github link: + +``` +https://github.com/$+ -> https://utopia.forall/$# +``` + +You can use `$1` or `$#` to refer to captures. diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index a8b7371030..3b84f4ce5a 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -11,7 +11,7 @@ import std / [parseopt, strutils, os, osproc, tables, sets, json, jsonutils, parsecfg, streams, terminal] -import parse_requires, osutils, packagesjson +import parse_requires, osutils, packagesjson, compiledpatterns from unicode import nil @@ -57,6 +57,7 @@ Options: --workspace=DIR use DIR as workspace --genlock generate a lock file (use with `clone` and `update`) --uselock use the lock file for the build + --autoinit auto initialize a workspace --colors=on|off turn on|off colored output --version show the version --help show this help @@ -105,8 +106,10 @@ type hasPackageList: bool keepCommits: bool cfgHere: bool + usesOverrides: bool p: Table[string, string] # name -> url mapping errors, warnings: int + overrides: Patterns lockOption: LockOption lockFileToWrite: seq[LockFileEntry] lockFileToUse: Table[string, LockFileEntry] @@ -382,14 +385,27 @@ proc fillPackageLookupTable(c: var AtlasContext) = proc toUrl(c: var AtlasContext; p: string): string = if p.isUrl: + if c.usesOverrides: + result = c.overrides.substitute(p) + if result.len > 0: return result result = p else: + # either the project name or the URL can be overwritten! + if c.usesOverrides: + result = c.overrides.substitute(p) + if result.len > 0: return result + fillPackageLookupTable(c) result = c.p.getOrDefault(unicode.toLower p) - if result.len == 0: - result = getUrlFromGithub(p) + if result.len == 0: - inc c.errors + result = getUrlFromGithub(p) + if result.len == 0: + inc c.errors + + if c.usesOverrides: + let newUrl = c.overrides.substitute(result) + if newUrl.len > 0: return newUrl proc toName(p: string): PackageName = if p.isUrl: @@ -760,17 +776,42 @@ proc absoluteDepsDir(workspace, value: string): string = else: result = workspace / value -when MockupRun: - proc autoWorkspace(): string = - result = getCurrentDir() - while result.len > 0 and dirExists(result / ".git"): - result = result.parentDir() +proc autoWorkspace(): string = + result = getCurrentDir() + while result.len > 0 and dirExists(result / ".git"): + result = result.parentDir() proc createWorkspaceIn(workspace, depsDir: string) = if not fileExists(workspace / AtlasWorkspace): writeFile workspace / AtlasWorkspace, "deps=\"$#\"" % escape(depsDir, "", "") createDir absoluteDepsDir(workspace, depsDir) +proc parseOverridesFile(c: var AtlasContext; filename: string) = + const Separator = " -> " + let path = c.workspace / filename + var f: File + if open(f, path): + c.usesOverrides = true + try: + var lineCount = 1 + for line in lines(path): + let splitPos = line.find(Separator) + if splitPos >= 0 and line[0] != '#': + let key = line.substr(0, splitPos-1) + let val = line.substr(splitPos+len(Separator)) + if key.len == 0 or val.len == 0: + error c, toName(path), "key/value must not be empty" + let err = c.overrides.addPattern(key, val) + if err.len > 0: + error c, toName(path), "(" & $lineCount & "): " & err + else: + discard "ignore the line" + inc lineCount + finally: + close f + else: + error c, toName(path), "cannot open: " & path + proc readConfig(c: var AtlasContext) = let configFile = c.workspace / AtlasWorkspace var f = newFileStream(configFile, fmRead) @@ -789,6 +830,8 @@ proc readConfig(c: var AtlasContext) = case e.key.normalize of "deps": c.depsDir = absoluteDepsDir(c.workspace, e.value) + of "overrides": + parseOverridesFile(c, e.value) else: warn c, toName(configFile), "ignored unknown setting: " & e.key of cfgOption: @@ -813,7 +856,7 @@ proc main = fatal action & " command must be executed in a project, not in the workspace" var c = AtlasContext(projectDir: getCurrentDir(), workspace: "") - + var autoinit = false for kind, key, val in getopt(): case kind of cmdArgument: @@ -842,6 +885,7 @@ proc main = else: writeHelp() of "cfghere": c.cfgHere = true + of "autoinit": autoinit = true of "genlock": if c.lockOption != useLock: c.lockOption = genLock @@ -870,6 +914,9 @@ proc main = if c.workspace.len > 0: readConfig c info c, toName(c.workspace), "is the current workspace" + elif autoinit: + c.workspace = autoWorkspace() + createWorkspaceIn c.workspace, c.depsDir elif action notin ["search", "list"]: fatal "No workspace found. Run `atlas init` if you want this current directory to be your workspace." diff --git a/tools/atlas/compiledpatterns.nim b/tools/atlas/compiledpatterns.nim new file mode 100644 index 0000000000..69751d82bf --- /dev/null +++ b/tools/atlas/compiledpatterns.nim @@ -0,0 +1,246 @@ +# +# Atlas Package Cloner +# (c) Copyright 2021 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +##[ + +Syntax taken from strscans.nim: + +================= ======================================================== +``$$`` Matches a single dollar sign. +``$*`` Matches until the token following the ``$*`` was found. + The match is allowed to be of 0 length. +``$+`` Matches until the token following the ``$+`` was found. + The match must consist of at least one char. +``$s`` Skips optional whitespace. +================= ======================================================== + +]## + +import tables +from strutils import continuesWith, Whitespace + +type + Opcode = enum + MatchVerbatim # needs verbatim match + Capture0Until + Capture1Until + Capture0UntilEnd + Capture1UntilEnd + SkipWhitespace + + Instr = object + opc: Opcode + arg1: uint8 + arg2: uint16 + + Pattern* = object + code: seq[Instr] + usedMatches: int + error: string + +# A rewrite rule looks like: +# +# foo$*bar -> https://gitlab.cross.de/$1 + +proc compile*(pattern: string; strings: var seq[string]): Pattern = + proc parseSuffix(s: string; start: int): int = + result = start + while result < s.len and s[result] != '$': + inc result + + result = Pattern(code: @[], usedMatches: 0, error: "") + var p = 0 + while p < pattern.len: + if pattern[p] == '$' and p+1 < pattern.len: + case pattern[p+1] + of '$': + if result.code.len > 0 and result.code[^1].opc in { + MatchVerbatim, Capture0Until, Capture1Until, Capture0UntilEnd, Capture1UntilEnd}: + # merge with previous opcode + let key = strings[result.code[^1].arg2] & "$" + var idx = find(strings, key) + if idx < 0: + idx = strings.len + strings.add key + result.code[^1].arg2 = uint16(idx) + else: + var idx = find(strings, "$") + if idx < 0: + idx = strings.len + strings.add "$" + result.code.add Instr(opc: MatchVerbatim, + arg1: uint8(0), arg2: uint16(idx)) + inc p, 2 + of '+', '*': + let isPlus = pattern[p+1] == '+' + + let pEnd = parseSuffix(pattern, p+2) + let suffix = pattern.substr(p+2, pEnd-1) + p = pEnd + if suffix.len == 0: + result.code.add Instr(opc: if isPlus: Capture1UntilEnd else: Capture0UntilEnd, + arg1: uint8(result.usedMatches), arg2: uint16(0)) + else: + var idx = find(strings, suffix) + if idx < 0: + idx = strings.len + strings.add suffix + result.code.add Instr(opc: if isPlus: Capture1Until else: Capture0Until, + arg1: uint8(result.usedMatches), arg2: uint16(idx)) + inc result.usedMatches + + of 's': + result.code.add Instr(opc: SkipWhitespace) + inc p, 2 + else: + result.error = "unknown syntax '$" & pattern[p+1] & "'" + break + elif pattern[p] == '$': + result.error = "unescaped '$'" + break + else: + let pEnd = parseSuffix(pattern, p) + let suffix = pattern.substr(p, pEnd-1) + var idx = find(strings, suffix) + if idx < 0: + idx = strings.len + strings.add suffix + result.code.add Instr(opc: MatchVerbatim, + arg1: uint8(0), arg2: uint16(idx)) + p = pEnd + +type + MatchObj = object + m: int + a: array[20, (int, int)] + +proc matches(s: Pattern; strings: seq[string]; input: string): MatchObj = + template failed = + result.m = -1 + return result + + var i = 0 + for instr in s.code: + case instr.opc + of MatchVerbatim: + if continuesWith(input, strings[instr.arg2], i): + inc i, strings[instr.arg2].len + else: + failed() + of Capture0Until, Capture1Until: + block searchLoop: + let start = i + while i < input.len: + if continuesWith(input, strings[instr.arg2], i): + if instr.opc == Capture1Until and i == start: + failed() + result.a[result.m] = (start, i-1) + inc result.m + inc i, strings[instr.arg2].len + break searchLoop + inc i + failed() + + of Capture0UntilEnd, Capture1UntilEnd: + if instr.opc == Capture1UntilEnd and i >= input.len: + failed() + result.a[result.m] = (i, input.len-1) + inc result.m + i = input.len + of SkipWhitespace: + while i < input.len and input[i] in Whitespace: inc i + if i < input.len: + # still unmatched stuff was left: + failed() + +proc translate(m: MatchObj; outputPattern, input: string): string = + result = newStringOfCap(outputPattern.len) + var i = 0 + var patternCount = 0 + while i < outputPattern.len: + if i+1 < outputPattern.len and outputPattern[i] == '$': + if outputPattern[i+1] == '#': + inc i, 2 + if patternCount < m.a.len: + let (a, b) = m.a[patternCount] + for j in a..b: result.add input[j] + inc patternCount + elif outputPattern[i+1] in {'1'..'9'}: + var n = ord(outputPattern[i+1]) - ord('0') + inc i, 2 + while i < outputPattern.len and outputPattern[i] in {'0'..'9'}: + n = n * 10 + (ord(outputPattern[i]) - ord('0')) + inc i + patternCount = n + if n-1 < m.a.len: + let (a, b) = m.a[n-1] + for j in a..b: result.add input[j] + else: + # just ignore the wrong pattern: + inc i + else: + result.add outputPattern[i] + inc i + +proc replace*(s: Pattern; outputPattern, input: string): string = + var strings: seq[string] = @[] + let m = s.matches(strings, input) + if m.m < 0: + result = "" + else: + result = translate(m, outputPattern, input) + + +type + Patterns* = object + s: seq[(Pattern, string)] + t: Table[string, string] + strings: seq[string] + +proc initPatterns*(): Patterns = + Patterns(s: @[], t: initTable[string, string](), strings: @[]) + +proc addPattern*(p: var Patterns; inputPattern, outputPattern: string): string = + if '$' notin inputPattern and '$' notin outputPattern: + p.t[inputPattern] = outputPattern + result = "" + else: + let code = compile(inputPattern, p.strings) + if code.error.len > 0: + result = code.error + else: + p.s.add (code, outputPattern) + result = "" + +proc substitute*(p: Patterns; input: string): string = + result = p.t.getOrDefault(input) + if result.len == 0: + for i in 0..= 0: + return translate(m, p.s[i][1], input) + +proc replacePattern*(inputPattern, outputPattern, input: string): string = + var strings: seq[string] = @[] + let code = compile(inputPattern, strings) + result = replace(code, outputPattern, input) + +when isMainModule: + # foo$*bar -> https://gitlab.cross.de/$1 + const realInput = "$fooXXbar$z00end" + var strings: seq[string] = @[] + let code = compile("$$foo$*bar$$$*z00$*", strings) + echo code + + let m = code.matches(strings, realInput) + echo m.m + + echo translate(m, "$1--$#-$#-", realInput) + + echo translate(m, "https://gitlab.cross.de/$1", realInput) + From a9385a6b4ab0862512992b2adf75460cf0c4ce74 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 30 May 2023 18:02:55 +0200 Subject: [PATCH 164/489] Atlas: virtual environments (#21965) * Atlas: virtual environments * fixes --- doc/atlas.md | 15 ++++++++ tools/atlas/atlas.nim | 79 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/doc/atlas.md b/doc/atlas.md index c6b8c7a9a4..9438546ba2 100644 --- a/doc/atlas.md +++ b/doc/atlas.md @@ -171,3 +171,18 @@ https://github.com/$+ -> https://utopia.forall/$# ``` You can use `$1` or `$#` to refer to captures. + + +### Virtual Nim environments + +Atlas supports setting up a virtual Nim environment via the `env` command. You can +even install multiple different Nim versions into the same workspace. + +For example: + +``` +atlas env 1.6.12 +atlas env devel +``` + +When completed, run `source nim-1.6.12/activate.sh` on UNIX and `nim-1.6.12/activate.bat` on Windows. diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 3b84f4ce5a..acc622dd43 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -10,7 +10,7 @@ ## a Nimble dependency and its dependencies recursively. import std / [parseopt, strutils, os, osproc, tables, sets, json, jsonutils, - parsecfg, streams, terminal] + parsecfg, streams, terminal, strscans] import parse_requires, osutils, packagesjson, compiledpatterns from unicode import nil @@ -49,6 +49,7 @@ Command: or a letter ['a'..'z']: a.b.c.d.e.f.g build|test|doc|tasks currently delegates to `nimble build|test|doc` task currently delegates to `nimble ` + env setup a Nim virtual environment Options: --keepCommits do not perform any `git checkouts` @@ -840,6 +841,79 @@ proc readConfig(c: var AtlasContext) = error c, toName(configFile), e.msg close(p) +const + BatchFile = """ +@echo off +set PATH="$1";%PATH% +""" + ShellFile = "export PATH=$1:$$PATH\n" + +proc setupNimEnv(c: var AtlasContext; nimVersion: string) = + template isDevel(nimVersion: string): bool = nimVersion == "devel" + + template exec(c: var AtlasContext; command: string) = + let cmd = command # eval once + if os.execShellCmd(cmd) != 0: + error c, toName("nim-" & nimVersion), "failed: " & cmd + return + + let nimDest = "nim-" & nimVersion + if dirExists(c.workspace / nimDest): + info c, toName(nimDest), "already exists; remove or rename and try again" + return + + var major, minor, patch: int + if nimVersion != "devel": + if not scanf(nimVersion, "$i.$i.$i", major, minor, patch): + error c, toName("nim"), "cannot parse version requirement" + return + let csourcesVersion = + if nimVersion.isDevel or (major >= 1 and minor >= 9) or major >= 2: + # already uses csources_v2 + "csources_v2" + elif major == 0: + "csources" # has some chance of working + else: + "csources_v1" + withDir c, c.workspace: + if not dirExists(csourcesVersion): + exec c, "git clone https://github.com/nim-lang/" & csourcesVersion + exec c, "git clone https://github.com/nim-lang/nim " & nimDest + withDir c, c.workspace / csourcesVersion: + when defined(windows): + exec c, "build.bat" + else: + let makeExe = findExe("make") + if makeExe.len == 0: + exec c, "sh build.sh" + else: + exec c, "make" + let nimExe0 = ".." / csourcesVersion / "bin" / "nim".addFileExt(ExeExt) + withDir c, c.workspace / nimDest: + let nimExe = "bin" / "nim".addFileExt(ExeExt) + copyFile nimExe0, nimExe + let dep = Dependency(name: toName(nimDest), rel: normal, commit: nimVersion) + if not nimVersion.isDevel: + let commit = versionToCommit(c, dep) + if commit.len == 0: + error c, toName(nimDest), "cannot resolve version to a commit" + return + checkoutGitCommit(c, dep.name, commit) + exec c, nimExe & " c --noNimblePath --skipUserCfg --skipParentCfg --hints:off koch" + let kochExe = when defined(windows): "koch.exe" else: "./koch" + exec c, kochExe & " boot -d:release --skipUserCfg --skipParentCfg --hints:off" + exec c, kochExe & " tools --skipUserCfg --skipParentCfg --hints:off" + # remove any old atlas binary that we now would end up using: + if cmpPaths(getAppDir(), c.workspace / nimDest / "bin") != 0: + removeFile "bin" / "atlas".addFileExt(ExeExt) + let pathEntry = (c.workspace / nimDest / "bin") + when defined(windows): + writeFile "activate.bat", BatchFile % pathEntry.replace('/', '\\') + info c, toName(nimDest), "RUN\nnim-" & nimVersion & "\\activate.bat" + else: + writeFile "activate.sh", ShellFile % pathEntry + info c, toName(nimDest), "RUN\nsource nim-" & nimVersion & "/activate.sh" + proc main = var action = "" var args: seq[string] = @[] @@ -1001,6 +1075,9 @@ proc main = of "task": projectCmd() nimbleExec("", args) + of "env": + singleArg() + setupNimEnv c, args[0] else: fatal "Invalid action: " & action From 20446b437bd6c35006fab78ed5e3bdd6f8056774 Mon Sep 17 00:00:00 2001 From: metagn Date: Tue, 30 May 2023 22:29:38 +0300 Subject: [PATCH 165/489] make `proc` not implicitly convert to `pointer` with a preview define (#21953) * test `proc` not converting to `pointer` * ignore define for now to test * remove cstring * fixes, changelog --- changelogs/changelog_2_0_0.md | 3 +++ compiler/nim.cfg | 1 + compiler/sigmatch.nim | 5 ++++- lib/pure/hashes.nim | 2 +- lib/wrappers/openssl.nim | 2 +- tests/dll/nimhcr_unit.nim | 6 +++--- tests/stdlib/config.nims | 3 ++- tests/tools/config.nims | 3 ++- tests/types/tissues_types.nim | 7 +++---- 9 files changed, 20 insertions(+), 12 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 4a15855f4c..690258bdc5 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -44,6 +44,9 @@ - Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore. +- Enabling `-d:nimPreviewProcConversion`, `proc` does not support conversion to + `pointer`. `cast` may be used instead. + - The `gc:v2` option is removed. - The `mainmodule` and `m` options are removed. diff --git a/compiler/nim.cfg b/compiler/nim.cfg index 5e70c2975e..5b418cfd3b 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -7,6 +7,7 @@ define:nimcore define:nimPreviewFloatRoundtrip define:nimPreviewSlimSystem define:nimPreviewCstringConversion +define:nimPreviewProcConversion define:nimPreviewRangeDefault threads:off diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 6c119b71f3..8f396840eb 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1380,7 +1380,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isEqual of tyNil: result = f.allowsNil of tyProc: - if a.callConv != ccClosure: result = isConvertible + if isDefined(c.c.config, "nimPreviewProcConversion"): + result = isNone + else: + if a.callConv != ccClosure: result = isConvertible of tyPtr: # 'pointer' is NOT compatible to regionized pointers # so 'dealloc(regionPtr)' fails: diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 8e5770a71f..daa7f93661 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -534,7 +534,7 @@ proc hash*[T: tuple | object | proc | iterator {.closure.}](x: T): Hash = when T is "closure": result = hash((rawProc(x), rawEnv(x))) elif T is (proc): - result = hash(pointer(x)) + result = hash(cast[pointer](x)) else: result = 0 for f in fields(x): diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index fcf52a8d95..fa72c6c246 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -589,7 +589,7 @@ when not useWinVersion and not defined(macosx) and not defined(android) and useN if p != nil: deallocShared(p) proc CRYPTO_malloc_init*() = - CRYPTO_set_mem_functions(allocWrapper, reallocWrapper, deallocWrapper) + CRYPTO_set_mem_functions(cast[pointer](allocWrapper), cast[pointer](reallocWrapper), cast[pointer](deallocWrapper)) else: proc CRYPTO_malloc_init*() = discard diff --git a/tests/dll/nimhcr_unit.nim b/tests/dll/nimhcr_unit.nim index 0b924bdf75..249f3f9f17 100644 --- a/tests/dll/nimhcr_unit.nim +++ b/tests/dll/nimhcr_unit.nim @@ -106,14 +106,14 @@ macro carryOutTests(callingConv: untyped): untyped = echo `procName`, " implementation #1 ", x return x + 1 - let fp1 = cast[F](hcrRegisterProc("dummy_module", `procName`, `p1`)) + let fp1 = cast[F](hcrRegisterProc("dummy_module", `procName`, cast[pointer](`p1`))) echo fp1(10) proc `p2`(x: int): int {.placeholder.} = echo `procName`, " implementation #2 ", x return x + 2 - let fp2 = cast[F](hcrRegisterProc("dummy_module", `procName`, `p2`)) + let fp2 = cast[F](hcrRegisterProc("dummy_module", `procName`, cast[pointer](`p2`))) echo fp1(20) echo fp2(20) @@ -121,7 +121,7 @@ macro carryOutTests(callingConv: untyped): untyped = echo `procName`, " implementation #3 ", x return x + 3 - let fp3 = cast[F](hcrRegisterProc("dummy_module", `procName`, `p3`)) + let fp3 = cast[F](hcrRegisterProc("dummy_module", `procName`, cast[pointer](`p3`))) echo fp1(30) echo fp2(30) echo fp3(30) diff --git a/tests/stdlib/config.nims b/tests/stdlib/config.nims index cf97152bab..dffae28120 100644 --- a/tests/stdlib/config.nims +++ b/tests/stdlib/config.nims @@ -1,4 +1,5 @@ switch("styleCheck", "usages") switch("styleCheck", "error") switch("define", "nimPreviewSlimSystem") -switch("define", "nimPreviewCstringConversion") \ No newline at end of file +switch("define", "nimPreviewCstringConversion") +switch("define", "nimPreviewProcConversion") diff --git a/tests/tools/config.nims b/tests/tools/config.nims index b4bb92b300..0f0cba8b45 100644 --- a/tests/tools/config.nims +++ b/tests/tools/config.nims @@ -1,2 +1,3 @@ --d:nimPreviewSlimSystem ---d:nimPreviewCstringConversion \ No newline at end of file +--d:nimPreviewCstringConversion +--d:nimPreviewProcConversion diff --git a/tests/types/tissues_types.nim b/tests/types/tissues_types.nim index 7ed0547bfc..275941caec 100644 --- a/tests/types/tissues_types.nim +++ b/tests/types/tissues_types.nim @@ -44,11 +44,10 @@ block t5648: g.bar = 3 var - mainPtr1: pointer = main - mainPtr2 = pointer(main) - mainPtr3 = cast[pointer](main) + mainPtr = cast[pointer](main) + mainFromPtr = cast[typeof(main)](mainPtr) - doAssert mainPtr1 == mainPtr2 and mainPtr2 == mainPtr3 + doAssert main == mainFromPtr main() From e43a51fcf3dff166838cdc3f2fc9690c5fa24846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Tue, 30 May 2023 20:47:26 +0100 Subject: [PATCH 166/489] Implements: [C++] constructor pragma improvement (fix #21921) (#21916) * implements: [C++] constructor pragma improvement (fix #21921) t * fix test so it doesnt use echo in globals * Update compiler/ccgtypes.nim * Update lib/std/private/dragonbox.nim --------- Co-authored-by: Andreas Rumpf --- compiler/ccgstmts.nim | 18 ++--- compiler/ccgtypes.nim | 120 ++++++++++++++++++++++------------ compiler/cgen.nim | 16 +++-- compiler/modulegraphs.nim | 2 +- compiler/pragmas.nim | 6 +- compiler/semstmts.nim | 59 ++++++++++++----- lib/std/private/dragonbox.nim | 4 +- lib/std/private/schubfach.nim | 4 +- tests/cpp/tconstructor.nim | 35 +++++++++- 9 files changed, 180 insertions(+), 84 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 1ed546256d..36ef4f3eae 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -35,7 +35,9 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} = if n.kind == nkEmpty: result = false elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc: - if isInvalidReturnType(conf, n[0].typ, true): + if n[0].kind == nkSym and sfConstructor in n[0].sym.flags: + result = true + elif isInvalidReturnType(conf, n[0].typ, true): # var v = f() # is transformed into: var v; f(addr v) # where 'f' **does not** initialize the result! @@ -288,7 +290,7 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) = #echo "New code produced for ", v.name.s, " ", p.config $ value.info genBracedInit(p, value, isConst = false, v.typ, result) -proc genCppVarForConstructor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) = +proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) = var params = newRopeAppender() var argsCounter = 0 let typ = skipTypes(value[0].typ, abstractInst) @@ -307,7 +309,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = genGotoVar(p, value) return let imm = isAssignedImmediately(p.config, value) - let isCppConstructorCall = p.module.compileToCpp and imm and + let isCppCtorCall = p.module.compileToCpp and imm and value.kind in nkCallKinds and value[0].kind == nkSym and v.typ.kind != tyPtr and sfConstructor in value[0].sym.flags var targetProc = p @@ -321,8 +323,8 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = if sfPure in v.flags: # v.owner.kind != skModule: targetProc = p.module.preInitProc - if isCppConstructorCall and not containsHiddenPointer(v.typ): - callGlobalVarCppConstructor(targetProc, v, vn, value) + if isCppCtorCall and not containsHiddenPointer(v.typ): + callGlobalVarCppCtor(targetProc, v, vn, value) else: assignGlobalVar(targetProc, vn, valueAsRope) @@ -356,8 +358,8 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = genLineDir(p, vn) var decl = localVarDecl(p, vn) var tmp: TLoc - if isCppConstructorCall: - genCppVarForConstructor(p, v, vn, value, decl) + if isCppCtorCall: + genCppVarForCtor(p, v, vn, value, decl) line(p, cpsStmts, decl) else: initLocExprSingleUse(p, value, tmp) @@ -388,7 +390,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = startBlock(targetProc) if value.kind != nkEmpty and valueAsRope.len == 0: genLineDir(targetProc, vn) - if not isCppConstructorCall: + if not isCppCtorCall: loadInto(targetProc, vn, value, v.loc) if forHcr: endBlock(targetProc) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index d6835cc501..9bcfa41eff 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -11,8 +11,7 @@ # ------------------------- Name Mangling -------------------------------- -import sighashes, modulegraphs -import strscans +import sighashes, modulegraphs, strscans import ../dist/checksums/src/checksums/md5 type @@ -488,30 +487,36 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr res.add(substr(frmt, start, i - 1)) frmt = res -proc genVirtualProcParams(m: BModule; t: PType, rettype, params: var string, +proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var string, check: var IntSet, declareEnvironment=true; weakDep=false;) = - if t[0] == nil or isInvalidReturnType(m.config, t): + let t = prc.typ + let isCtor = sfConstructor in prc.flags + if isCtor: + rettype = "" + elif t[0] == nil or isInvalidReturnType(m.config, t): rettype = "void" else: if rettype == "": rettype = getTypeDescAux(m, t[0], check, dkResult) else: rettype = runtimeFormat(rettype.replace("'0", "$1"), [getTypeDescAux(m, t[0], check, dkResult)]) - var this = t.n[1].sym - fillParamName(m, this) - fillLoc(this.loc, locParam, t.n[1], - this.paramStorageLoc) - if this.typ.kind == tyPtr: - this.loc.r = "this" - else: - this.loc.r = "(*this)" - - var types = @[getTypeDescWeak(m, this.typ, check, dkParam)] - var names = @[this.loc.r] + var types, names, args: seq[string] + if not isCtor: + var this = t.n[1].sym + fillParamName(m, this) + fillLoc(this.loc, locParam, t.n[1], + this.paramStorageLoc) + if this.typ.kind == tyPtr: + this.loc.r = "this" + else: + this.loc.r = "(*this)" + names.add this.loc.r + types.add getTypeDescWeak(m, this.typ, check, dkParam) - for i in 2.. -1 isOverride = afterParams.find("override") > -1 - discard scanf(afterParams, "->$s$* ", retType) + if isCtor: + discard scanf(afterParams, ":$s$*", superCall) + else: + discard scanf(afterParams, "->$s$* ", retType) + params = "(" & params & ")" -proc genVirtualProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl : bool = false) = - assert sfVirtual in prc.flags - # using static is needed for inline procs +proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl : bool = false) = + assert {sfVirtual, sfConstructor} * prc.flags != {} + let isCtor = sfConstructor in prc.flags + let isVirtual = not isCtor var check = initIntSet() fillBackendName(m, prc) fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown) - var typ = prc.typ.n[1].sym.typ - var memberOp = "#." + var memberOp = "#." #only virtual + var typ: PType + if isCtor: + typ = prc.typ.sons[0] + else: + typ = prc.typ.sons[1] if typ.kind == tyPtr: typ = typ[0] memberOp = "#->" var typDesc = getTypeDescWeak(m, typ, check, dkParam) let asPtrStr = rope(if asPtr: "_PTR" else: "") - var name, params, rettype: string + var name, params, rettype, superCall: string var isFnConst, isOverride: bool - parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, isFnConst, isOverride) - genVirtualProcParams(m, prc.typ, rettype, params, check, true, false) + parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isCtor) + genMemberProcParams(m, prc, superCall, rettype, params, check, true, false) var fnConst, override: string + if isCtor: + name = typDesc if isFnConst: fnConst = " const" if isFwdDecl: - rettype = "virtual " & rettype - if isOverride: - override = " override" - else: - prc.loc.r = "$1 $2 (@)" % [memberOp, name] + if isVirtual: + rettype = "virtual " & rettype + if isOverride: + override = " override" + superCall = "" + else: + if isVirtual: + prc.loc.r = "$1$2(@)" % [memberOp, name] + elif superCall != "": + superCall = " : " & superCall + name = "$1::$2" % [typDesc, name] - + result.add "N_LIB_PRIVATE " - result.addf("$1$2($3, $4)$5$6$7", + result.addf("$1$2($3, $4)$5$6$7$8", [rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name, - params, fnConst, override]) + params, fnConst, override, superCall]) proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false) = # using static is needed for inline procs diff --git a/compiler/cgen.nim b/compiler/cgen.nim index fe5c253dd0..e79081dc6d 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -640,9 +640,9 @@ proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) = else: decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r]) -proc genCppVarForConstructor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) +proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) -proc callGlobalVarCppConstructor(p: BProc; v: PSym; vn, value: PNode) = +proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) = let s = vn.sym fillBackendName(p.module, s) fillLoc(s.loc, locGlobalVar, vn, OnHeap) @@ -650,7 +650,7 @@ proc callGlobalVarCppConstructor(p: BProc; v: PSym; vn, value: PNode) = let td = getTypeDesc(p.module, vn.sym.typ, dkVar) genGlobalVarDecl(p, vn, td, "", decl) decl.add " " & $s.loc.r - genCppVarForConstructor(p, v, vn, value, decl) + genCppVarForCtor(p, v, vn, value, decl) p.module.s[cfsVars].add decl proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = @@ -1143,8 +1143,8 @@ proc isNoReturn(m: BModule; s: PSym): bool {.inline.} = proc genProcAux*(m: BModule, prc: PSym) = var p = newProc(prc, m) var header = newRopeAppender() - if m.config.backend == backendCpp and sfVirtual in prc.flags: - genVirtualProcHeader(m, prc, header) + if m.config.backend == backendCpp and {sfVirtual, sfConstructor} * prc.flags != {}: + genMemberProcHeader(m, prc, header) else: genProcHeader(m, prc, header) var returnStmt: Rope = "" @@ -1162,7 +1162,7 @@ proc genProcAux*(m: BModule, prc: PSym) = internalError(m.config, prc.info, "proc has no result symbol") let resNode = prc.ast[resultPos] let res = resNode.sym # get result symbol - if not isInvalidReturnType(m.config, prc.typ): + if not isInvalidReturnType(m.config, prc.typ) and sfConstructor notin prc.flags: if sfNoInit in prc.flags: incl(res.flags, sfNoInit) if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil): var decl = localVarDecl(p, resNode) @@ -1175,6 +1175,8 @@ proc genProcAux*(m: BModule, prc: PSym) = assert(res.loc.r != "") initLocalVar(p, res, immediateAsgn=false) returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)]) + elif sfConstructor in prc.flags: + fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap) else: fillResult(p.config, resNode, prc.typ) assignParam(p, res, prc.typ[0]) @@ -1252,7 +1254,7 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} = proc genProcPrototype(m: BModule, sym: PSym) = useHeader(m, sym) - if lfNoDecl in sym.loc.flags or sfVirtual in sym.flags: return + if lfNoDecl in sym.loc.flags or {sfVirtual, sfConstructor} * sym.flags != {}: return if lfDynamicLib in sym.loc.flags: if sym.itemId.module != m.module.position and not containsOrIncl(m.declaredThings, sym.id): diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index de97ced995..08cdbfd0db 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -79,7 +79,7 @@ type procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId. attachedOps*: array[TTypeAttachedOp, Table[ItemId, LazySym]] # Type ID, destructors, etc. methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods - virtualProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached virtual procs + memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual and ctor so far) enumToStringProcs*: Table[ItemId, LazySym] emittedTypeInfo*: Table[string, FileIndex] diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 11305db2a3..158e68eef8 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -971,8 +971,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, # only supported for backwards compat, doesn't do anything anymore noVal(c, it) of wConstructor: - noVal(c, it) incl(sym.flags, sfConstructor) + if sfImportc notin sym.flags: + sym.constraint = newEmptyStrNode(c, it, getOptionalStr(c, it, "")) + sym.constraint.strVal = sym.constraint.strVal + sym.flags.incl {sfExportc, sfMangleCpp} + sym.typ.callConv = ccNoConvention of wHeader: var lib = getLib(c, libHeader, getStrLitNode(c, it)) addToLib(lib, sym) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 6e2fb92528..6cf9c6f7ad 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1654,6 +1654,16 @@ proc swapResult(n: PNode, sRes: PSym, dNode: PNode) = n[i] = dNode swapResult(n[i], sRes, dNode) + +proc addThis(c: PContext, n: PNode, t: PType, owner: TSymKind) = + var s = newSym(skResult, getIdent(c.cache, "this"), c.idgen, + getCurrOwner(c), n.info) + s.typ = t + incl(s.flags, sfUsed) + c.p.resultSym = s + n.add newSymNode(c.p.resultSym) + addParamOrResult(c, c.p.resultSym, owner) + proc addResult(c: PContext, n: PNode, t: PType, owner: TSymKind) = template genResSym(s) = var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen, @@ -2189,24 +2199,33 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if sfBorrow in s.flags and c.config.cmd notin cmdDocLike: result[bodyPos] = c.graph.emptyNode - if sfVirtual in s.flags: + if {sfVirtual, sfConstructor} * s.flags != {} and sfImportc notin s.flags: + let isVirtual = sfVirtual in s.flags + let pragmaName = if isVirtual: "virtual" else: "constructor" if c.config.backend == backendCpp: + if s.typ.sons.len < 2 and isVirtual: + localError(c.config, n.info, "virtual must have at least one parameter") for son in s.typ.sons: if son!=nil and son.isMetaType: - localError(c.config, n.info, "virtual unsupported for generic routine") - - var typ = s.typ.sons[1] - if typ.kind == tyPtr: + localError(c.config, n.info, pragmaName & " unsupported for generic routine") + var typ: PType + if sfConstructor in s.flags: + typ = s.typ.sons[0] + if typ == nil or typ.kind != tyObject: + localError(c.config, n.info, "constructor must return an object") + else: + typ = s.typ.sons[1] + if typ.kind == tyPtr and isVirtual: typ = typ[0] if typ.kind != tyObject: - localError(c.config, n.info, "virtual must be a non ref object type") + localError(c.config, n.info, "virtual must be either ptr to object or object type.") if typ.owner.id == s.owner.id and c.module.id == s.owner.id: - c.graph.virtualProcsPerType.mgetOrPut(typ.itemId, @[]).add s + c.graph.memberProcsPerType.mgetOrPut(typ.itemId, @[]).add s else: localError(c.config, n.info, - "virtual procs must be defined in the same scope as the type they are virtual for and it must be a top level scope") + pragmaName & " procs must be defined in the same scope as the type they are virtual for and it must be a top level scope") else: - localError(c.config, n.info, "virtual procs are only supported in C++") + localError(c.config, n.info, pragmaName & " procs are only supported in C++") if n[bodyPos].kind != nkEmpty and sfError notin s.flags: # for DLL generation we allow sfImportc to have a body, for use in VM @@ -2232,15 +2251,19 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # Macros and Templates can have generic parameters, but they are only # used for overload resolution (there is no instantiation of the symbol) if s.kind notin {skMacro, skTemplate} and s.magic == mNone: paramsTypeCheck(c, s.typ) - - maybeAddResult(c, s, n) - let resultType = - if s.kind == skMacro: - sysTypeFromName(c.graph, n.info, "NimNode") - elif not isInlineIterator(s.typ): - s.typ[0] - else: - nil + var resultType: PType + if sfConstructor in s.flags: + resultType = makePtrType(c, s.typ[0]) + addThis(c, n, resultType, skProc) + else: + maybeAddResult(c, s, n) + resultType = + if s.kind == skMacro: + sysTypeFromName(c.graph, n.info, "NimNode") + elif not isInlineIterator(s.typ): + s.typ[0] + else: + nil # semantic checking also needed with importc in case used in VM s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos], resultType)) # unfortunately we cannot skip this step when in 'system.compiles' diff --git a/lib/std/private/dragonbox.nim b/lib/std/private/dragonbox.nim index 2ba22a7512..e39ffd9a3a 100644 --- a/lib/std/private/dragonbox.nim +++ b/lib/std/private/dragonbox.nim @@ -75,10 +75,10 @@ const const signMask*: BitsType = not (not BitsType(0) shr 1) -proc constructDouble*(bits: BitsType): Double {.constructor.} = +proc constructDouble*(bits: BitsType): Double = result.bits = bits -proc constructDouble*(value: ValueType): Double {.constructor.} = +proc constructDouble*(value: ValueType): Double = result.bits = cast[typeof(result.bits)](value) proc physicalSignificand*(this: Double): BitsType {.noSideEffect.} = diff --git a/lib/std/private/schubfach.nim b/lib/std/private/schubfach.nim index dad8363ba8..194fb4bfab 100644 --- a/lib/std/private/schubfach.nim +++ b/lib/std/private/schubfach.nim @@ -39,10 +39,10 @@ const exponentMask: BitsType = maxIeeeExponent shl (significandSize - 1) signMask: BitsType = not (not BitsType(0) shr 1) -proc constructSingle(bits: BitsType): Single {.constructor.} = +proc constructSingle(bits: BitsType): Single = result.bits = bits -proc constructSingle(value: ValueType): Single {.constructor.} = +proc constructSingle(value: ValueType): Single = result.bits = cast[typeof(result.bits)](value) proc physicalSignificand(this: Single): BitsType {.noSideEffect.} = diff --git a/tests/cpp/tconstructor.nim b/tests/cpp/tconstructor.nim index 8489c71d31..d4d6a7ccfa 100644 --- a/tests/cpp/tconstructor.nim +++ b/tests/cpp/tconstructor.nim @@ -1,6 +1,9 @@ discard """ targets: "cpp" cmd: "nim cpp $file" + output: ''' +1 +''' """ {.emit:"""/*TYPESECTION*/ @@ -15,10 +18,38 @@ struct CppClass { }; """.} -type CppClass* {.importcpp.} = object +type CppClass* {.importcpp, inheritable.} = object x: int32 y: int32 proc makeCppClass(x, y: int32): CppClass {.importcpp: "CppClass(@)", constructor.} +#test globals are init with the constructor call +var shouldCompile {.used.} = makeCppClass(1, 2) -var shouldCompile = makeCppClass(1, 2) +proc newCpp*[T](): ptr T {.importcpp:"new '*0()".} + +#creation +type NimClassNoNarent* = object + x: int32 + +proc makeNimClassNoParent(x:int32): NimClassNoNarent {. constructor.} = + this.x = x + discard + +let nimClassNoParent = makeNimClassNoParent(1) +echo nimClassNoParent.x #acess to this just fine. Notice the field will appear last because we are dealing with constructor calls here + +var nimClassNoParentDef {.used.}: NimClassNoNarent #test has a default constructor. + +#inheritance +type NimClass* = object of CppClass + +proc makeNimClass(x:int32): NimClass {. constructor:"NimClass('1 #1) : CppClass(0, #1) ".} = + this.x = x + +#optinially define the default constructor so we get rid of the cpp warn and we can declare the obj (note: default constructor of 'tyObject_NimClass__apRyyO8cfRsZtsldq1rjKA' is implicitly deleted because base class 'CppClass' has no default constructor) +proc makeCppClass(): NimClass {. constructor: "NimClass() : CppClass(0, 0) ".} = + this.x = 1 + +let nimClass = makeNimClass(1) +var nimClassDef {.used.}: NimClass #since we explictly defined the default constructor we can declare the obj \ No newline at end of file From bf9ee00998eaa3813c6893a9b9642a17b13196d7 Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Wed, 31 May 2023 06:26:51 +0200 Subject: [PATCH 167/489] Atlas: Use copyFileWithPermissions to copy nim executable (#21967) Use copyFileWithPermissions to copy nim executable Co-authored-by: SirOlaf <> --- tools/atlas/atlas.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index acc622dd43..51c024a121 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -891,7 +891,7 @@ proc setupNimEnv(c: var AtlasContext; nimVersion: string) = let nimExe0 = ".." / csourcesVersion / "bin" / "nim".addFileExt(ExeExt) withDir c, c.workspace / nimDest: let nimExe = "bin" / "nim".addFileExt(ExeExt) - copyFile nimExe0, nimExe + copyFileWithPermissions nimExe0, nimExe let dep = Dependency(name: toName(nimDest), rel: normal, commit: nimVersion) if not nimVersion.isDevel: let commit = versionToCommit(c, dep) From 086a3e42ebe1fbe8d8129168de3925688e495540 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Wed, 31 May 2023 11:00:35 -0300 Subject: [PATCH 168/489] Add GitHub Action Stale, remove Deprecated Probot Stale (#21943) * . * Add github action stale,remove deprecated stalebot * Add github action stale,remove deprecated stalebot * Update .github/workflows/stale.yml * Update .github/workflows/stale.yml --------- Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- .github/stale.yml | 69 ------------------------------------- .github/workflows/stale.yml | 23 +++++++++++++ 2 files changed, 23 insertions(+), 69 deletions(-) delete mode 100644 .github/stale.yml create mode 100644 .github/workflows/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index c175f64a0f..0000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,69 +0,0 @@ -# Configuration for probot-stale - https://github.com/probot/stale - -# Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 365 - -# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. -# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 30 - -# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) -onlyLabels: [] - -# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable -exemptLabels: - - ARC - - bounty - - Codegen - - Crash - - Generics - - High Priority - - Macros - - Next release - - Showstopper - - Static[T] - -# Set to true to ignore issues in a project (defaults to false) -exemptProjects: false - -# Set to true to ignore issues in a milestone (defaults to false) -exemptMilestones: false - -# Set to true to ignore issues with an assignee (defaults to false) -exemptAssignees: false - -# Label to use when marking as stale -staleLabel: stale - -# Comment to post when marking as stale. Set to `false` to disable -markComment: > - This pull request has been automatically marked as stale because it has not had - recent activity. - If you think it is still a valid PR, please rebase it on the latest devel; - otherwise it will be closed. Thank you for your contributions. - -# Comment to post when removing the stale label. -# unmarkComment: > -# Your comment here. - -# Comment to post when closing a stale Issue or Pull Request. -# closeComment: > -# Your comment here. - -# Limit the number of actions per hour, from 1-30. Default is 30 -limitPerRun: 20 - -# Limit to only `issues` or `pulls` -only: pulls - -# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': -# pulls: -# daysUntilStale: 30 -# markComment: > -# This pull request has been automatically marked as stale because it has not had -# recent activity. It will be closed if no further activity occurs. Thank you -# for your contributions. - -# issues: -# exemptLabels: -# - confirmed diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000..7283553d6f --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,23 @@ +# https://github.com/actions/stale#usage +name: Stale pull requests + +on: + schedule: + - cron: '0 0 * * *' # Midnight. + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v8 + with: + days-before-pr-stale: 365 + days-before-pr-close: 30 + exempt-pr-labels: "ARC,bounty,Codegen,Crash,Generics,High Priority,Macros,Next release,Showstopper,Static[T]" + exempt-issue-labels: "Showstopper,Severe,bounty,Compiler Crash,Medium Priority" + stale-pr-message: > + This pull request is stale because it has been open for 1 year with no activity. + Contribute more commits on the pull request and rebase it on the latest devel, + or it will be closed in 30 days. Thank you for your contributions. + close-pr-message: > + This pull request has been marked as stale and closed due to inactivity after 395 days. From 0e5c18a73a2d72067ba18211fa20e4782175fd40 Mon Sep 17 00:00:00 2001 From: heterodoxic <122719743+heterodoxic@users.noreply.github.com> Date: Wed, 31 May 2023 16:24:45 +0200 Subject: [PATCH 169/489] removal of seq spam in generated C/C++ code and Module.typeStack cleanup (#21964) * WIP: removal of seq spam in generated C/C++ output and Module.typeStack cleanup * removal of seq spam in generated C/C++ output and Module.typeStack cleanup --- compiler/ccgtypes.nim | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 9bcfa41eff..6423aa4877 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -408,12 +408,13 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet; kind: TypeDescKind m.typeCache[sig] = result #echo "adding ", sig, " ", typeToString(t), " ", m.module.name.s appcg(m, m.s[cfsTypes], - "struct $1 {$N" & - " NI len; $1_Content* p;$N" & - "};$N", [result]) + "struct $1 {\n" & + " NI len; $1_Content* p;\n" & + "};\n", [result]) + pushType(m, t) else: result = getTypeForward(m, t, sig) & seqStar(m) - pushType(m, t) + pushType(m, t) else: result = getTypeDescAux(m, t, check, kind) @@ -428,14 +429,9 @@ proc seqV2ContentType(m: BModule; t: PType; check: var IntSet) = if result == "": discard getTypeDescAux(m, t, check, dkVar) else: - # little hack for now to prevent multiple definitions of the same - # Seq_Content: - appcg(m, m.s[cfsTypes], """$N -$3ifndef $2_Content_PP -$3define $2_Content_PP -struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE];}; -$3endif$N - """, [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, dkVar), result, rope"#"]) + appcg(m, m.s[cfsTypes], """ +struct $2_Content { NI cap; $1 data[SEQ_DECL_SIZE]; }; +""", [getTypeDescAux(m, t.skipTypes(abstractInst)[0], check, dkVar), result]) proc paramStorageLoc(param: PSym): TStorageLoc = if param.typ.skipTypes({tyVar, tyLent, tyTypeDesc}).kind notin { @@ -1116,7 +1112,6 @@ proc finishTypeDescriptions(m: BModule) = inc(i) m.typeStack.setLen 0 - proc isReloadable(m: BModule; prc: PSym): bool = return m.hcrOn and sfNonReloadable notin prc.flags From b880cdff49576c0eb83a043cbae595d3587c95b4 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Wed, 31 May 2023 19:10:58 +0200 Subject: [PATCH 170/489] handle out of range value for `COLUMNS` / `LINES` (#21968) * handle out of range value for `COLUMNS` / `LINES` Querying terminal size may fail with a `ValueError` if size is too big. Return highest possible value instead. Note that `ValueError` is also reported on underflow (negative size) but that is out of POSIX specs. * `parseSaturatedNatural` --- lib/pure/terminal.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index de96293f8a..4177eb002a 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -305,7 +305,7 @@ else: var w: int var s = getEnv("COLUMNS") # Try standard env var - if len(s) > 0 and parseInt(s, w) > 0 and w > 0: + if len(s) > 0 and parseSaturatedNatural(s, w) > 0 and w > 0: return w w = terminalWidthIoctl([0, 1, 2]) # Try standard file descriptors if w > 0: return w @@ -339,7 +339,7 @@ else: var h: int var s = getEnv("LINES") # Try standard env var - if len(s) > 0 and parseInt(s, h) > 0 and h > 0: + if len(s) > 0 and parseSaturatedNatural(s, h) > 0 and h > 0: return h h = terminalHeightIoctl([0, 1, 2]) # Try standard file descriptors if h > 0: return h From 8f760080c546e10ce1cf01dfa1c6165a9b6f1845 Mon Sep 17 00:00:00 2001 From: metagn Date: Thu, 1 Jun 2023 06:20:08 +0300 Subject: [PATCH 171/489] privateAccess ignores non-objects (#21973) closes #21969 --- compiler/ast.nim | 2 +- compiler/semmagic.nim | 4 +++- compiler/suggest.nim | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index da9b3898e9..b27b16fe2c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -2008,7 +2008,7 @@ proc toObjectFromRefPtrGeneric*(typ: PType): PType = of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0] # automatic dereferencing is deep, refs #18298. else: break - assert result.sym != nil + # result does not have to be object type proc isImportedException*(t: PType; conf: ConfigRef): bool = assert t != nil diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index b47737beee..22c2fb57ef 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -524,7 +524,9 @@ proc semNewFinalize(c: PContext; n: PNode): PNode = proc semPrivateAccess(c: PContext, n: PNode): PNode = let t = n[1].typ[0].toObjectFromRefPtrGeneric - c.currentScope.allowPrivateAccess.add t.sym + if t.kind == tyObject: + assert t.sym != nil + c.currentScope.allowPrivateAccess.add t.sym result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid)) proc checkDefault(c: PContext, n: PNode): PNode = diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 8407670bac..f41f35519a 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -277,6 +277,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} = var symObj = f.owner if symObj.typ.skipTypes({tyGenericBody, tyGenericInst, tyGenericInvocation, tyAlias}).kind in {tyRef, tyPtr}: symObj = symObj.typ.toObjectFromRefPtrGeneric.sym + assert symObj != nil for scope in allScopes(c.currentScope): for sym in scope.allowPrivateAccess: if symObj.id == sym.id: return true From b3e1892eb7f4cb8b2090be7ad12286cc54506e91 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 1 Jun 2023 14:03:17 +0800 Subject: [PATCH 172/489] fixes #21977; add sideEffects to dirExists, fileExists and symlinkExists (#21978) --- lib/std/dirs.nim | 2 +- lib/std/files.nim | 2 +- lib/std/private/oscommon.nim | 6 +++--- lib/std/symlinks.nim | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/std/dirs.nim b/lib/std/dirs.nim index df6107c518..0b0366d441 100644 --- a/lib/std/dirs.nim +++ b/lib/std/dirs.nim @@ -8,7 +8,7 @@ from std/private/osdirs import dirExists, createDir, existsOrCreateDir, removeDi export PathComponent -proc dirExists*(dir: Path): bool {.inline, tags: [ReadDirEffect].} = +proc dirExists*(dir: Path): bool {.inline, tags: [ReadDirEffect], sideEffect.} = ## Returns true if the directory `dir` exists. If `dir` is a file, false ## is returned. Follows symlinks. result = dirExists(dir.string) diff --git a/lib/std/files.nim b/lib/std/files.nim index b2161218b6..b61b7dafda 100644 --- a/lib/std/files.nim +++ b/lib/std/files.nim @@ -9,7 +9,7 @@ from std/private/osfiles import fileExists, removeFile, moveFile -proc fileExists*(filename: Path): bool {.inline, tags: [ReadDirEffect].} = +proc fileExists*(filename: Path): bool {.inline, tags: [ReadDirEffect], sideEffect.} = ## Returns true if `filename` exists and is a regular file or symlink. ## ## Directories, device files, named pipes and sockets return false. diff --git a/lib/std/private/oscommon.nim b/lib/std/private/oscommon.nim index b747e33f18..c24db3f671 100644 --- a/lib/std/private/oscommon.nim +++ b/lib/std/private/oscommon.nim @@ -119,7 +119,7 @@ when not defined(windows): const maxSymlinkLen* = 1024 proc fileExists*(filename: string): bool {.rtl, extern: "nos$1", - tags: [ReadDirEffect], noNimJs.} = + tags: [ReadDirEffect], noNimJs, sideEffect.} = ## Returns true if `filename` exists and is a regular file or symlink. ## ## Directories, device files, named pipes and sockets return false. @@ -137,7 +137,7 @@ proc fileExists*(filename: string): bool {.rtl, extern: "nos$1", proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], - noNimJs.} = + noNimJs, sideEffect.} = ## Returns true if the directory `dir` exists. If `dir` is a file, false ## is returned. Follows symlinks. ## @@ -155,7 +155,7 @@ proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect] proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect], - noWeirdTarget.} = + noWeirdTarget, sideEffect.} = ## Returns true if the symlink `link` exists. Will return true ## regardless of whether the link points to a directory or file. ## diff --git a/lib/std/symlinks.nim b/lib/std/symlinks.nim index 54ab7b677f..60487740ca 100644 --- a/lib/std/symlinks.nim +++ b/lib/std/symlinks.nim @@ -6,7 +6,7 @@ from paths import Path, ReadDirEffect from std/private/ossymlinks import symlinkExists, createSymlink, expandSymlink -proc symlinkExists*(link: Path): bool {.inline, tags: [ReadDirEffect].} = +proc symlinkExists*(link: Path): bool {.inline, tags: [ReadDirEffect], sideEffect.} = ## Returns true if the symlink `link` exists. Will return true ## regardless of whether the link points to a directory or file. result = symlinkExists(link.string) From 8e35b3d577cb0a6b216b16668ff5f34a86cfbbab Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 2 Jun 2023 01:02:56 +0800 Subject: [PATCH 173/489] fixes #21974; fixes sameConstant fieldDefect (#21981) * fixes #21974; fixes sameConstant fieldDefect * add a test case --- compiler/injectdestructors.nim | 2 +- tests/arc/tarc_orc.nim | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 56ca8f605c..3275c1abc7 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -1016,7 +1016,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing proc sameLocation*(a, b: PNode): bool = proc sameConstant(a, b: PNode): bool = - a.kind in nkLiterals and a.intVal == b.intVal + a.kind in nkLiterals and b.kind in nkLiterals and a.intVal == b.intVal const nkEndPoint = {nkSym, nkDotExpr, nkCheckedFieldExpr, nkBracketExpr} if a.kind in nkEndPoint and b.kind in nkEndPoint: diff --git a/tests/arc/tarc_orc.nim b/tests/arc/tarc_orc.nim index 2fbb2e7921..387baa28f4 100644 --- a/tests/arc/tarc_orc.nim +++ b/tests/arc/tarc_orc.nim @@ -59,3 +59,33 @@ proc bug(): seq[Obj] = # bug #19990 let s = bug() doAssert s[0] == (value: 1, arr: @[1]) + +block: # bug #21974 + type Test[T] = ref object + values : seq[T] + counter: int + + proc newTest[T](): Test[T] = + result = new(Test[T]) + result.values = newSeq[T](16) + result.counter = 0 + + proc push[T](self: Test[T], value: T) = + self.counter += 1 + if self.counter >= self.values.len: + self.values.setLen(self.values.len * 2) + self.values[self.counter - 1] = value + + proc pop[T](self: Test[T]): T = + result = self.values[0] + self.values[0] = self.values[self.counter - 1] # <--- This line + self.counter -= 1 + + + type X = tuple + priority: int + value : string + + var a = newTest[X]() + a.push((1, "One")) + doAssert a.pop.value == "One" From c507ced51e19f530f39ee059e0c272638229a7b1 Mon Sep 17 00:00:00 2001 From: heterodoxic <122719743+heterodoxic@users.noreply.github.com> Date: Thu, 1 Jun 2023 19:37:01 +0200 Subject: [PATCH 174/489] partially fixes #20787 by having a char dummy member prepended to objs only containing an UncheckedArray (i.e. C FAM) (#21979) partial fix for #20787 --- compiler/ccgtypes.nim | 11 +++++++++-- tests/ccgbugs/t20787.nim | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/ccgbugs/t20787.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 6423aa4877..f808fa93ea 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -774,8 +774,15 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope, result = structOrUnion & " " & name result.add(getRecordDescAux(m, typ, name, baseType, check, hasField)) let desc = getRecordFields(m, typ, check) - if desc == "" and not hasField: - result.addf("char dummy;$n", []) + if not hasField: + if desc == "": + result.add("\tchar dummy;\n") + elif typ.len == 1 and typ.n[0].kind == nkSym: + let field = typ.n[0].sym + let fieldType = field.typ.skipTypes(abstractInst) + if fieldType.kind == tyUncheckedArray: + result.add("\tchar dummy;\n") + result.add(desc) else: result.add(desc) result.add("};\L") diff --git a/tests/ccgbugs/t20787.nim b/tests/ccgbugs/t20787.nim new file mode 100644 index 0000000000..c2d848c2cb --- /dev/null +++ b/tests/ccgbugs/t20787.nim @@ -0,0 +1,4 @@ +type + Obj = object + f: UncheckedArray[byte] +let o = new Obj \ No newline at end of file From ead7e20926b1f5ea1b06679947d3d16fcc085e68 Mon Sep 17 00:00:00 2001 From: Gruruya Date: Thu, 1 Jun 2023 23:02:40 -0400 Subject: [PATCH 175/489] Atlas: avoid segfault on failed Github search (#21980) * Atlas: avoid segfault on failed Github search * Return empty array on failed search instead of nil --- tools/atlas/packagesjson.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/atlas/packagesjson.nim b/tools/atlas/packagesjson.nim index 4c4d42595d..7e25c69343 100644 --- a/tools/atlas/packagesjson.nim +++ b/tools/atlas/packagesjson.nim @@ -79,7 +79,7 @@ proc singleGithubSearch(term: string): JsonNode = let x = client.getContent("https://api.github.com/search/repositories?q=" & encodeUrl(term) & "+language:nim") result = parseJson(x) except: - discard "it's a failed search, ignore" + result = parseJson("{\"items\": []}") finally: client.close() From 1133f20fe2c834d14454c32d7d9fc2cd1fe8ffa2 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 2 Jun 2023 22:03:32 +0800 Subject: [PATCH 176/489] lift the `=dup` hook (#21903) * fixes tests again * remove helper functions * fixes closures, owned refs * final cleanup --- compiler/ast.nim | 6 +- compiler/ccgexprs.nim | 10 -- compiler/injectdestructors.nim | 18 ++- compiler/liftdestructors.nim | 132 +++++++++++++++++----- lib/system.nim | 4 +- lib/system/arc.nim | 4 - testament/important_packages.nim | 2 +- tests/arc/tdup.nim | 7 +- tests/arc/topt_no_cursor.nim | 15 +-- tests/arc/topt_wasmoved_destroy_pairs.nim | 3 +- tests/destructor/tatomicptrs.nim | 10 +- tests/destructor/tmatrix.nim | 5 +- tests/destructor/tprevent_assign2.nim | 7 +- tests/destructor/tprevent_assign3.nim | 7 +- tests/destructor/tv2_cast.nim | 14 +-- 15 files changed, 151 insertions(+), 93 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index b27b16fe2c..2a5f18809e 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -944,10 +944,10 @@ type attachedWasMoved, attachedDestructor, attachedAsgn, + attachedDup, attachedSink, attachedTrace, - attachedDeepCopy, - attachedDup + attachedDeepCopy TType* {.acyclic.} = object of TIdObj # \ # types are identical iff they have the @@ -1518,7 +1518,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode, const AttachedOpToStr*: array[TTypeAttachedOp, string] = [ - "=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy", "=dup"] + "=wasMoved", "=destroy", "=copy", "=dup", "=sink", "=trace", "=deepcopy"] proc `$`*(s: PSym): string = if s != nil: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 6702c75370..a1c81599c6 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2359,11 +2359,6 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) = genAssignment(p, d, a, {}) resetLoc(p, a) -proc genDup(p: BProc; src: TLoc; d: var TLoc; n: PNode) = - if d.k == locNone: getTemp(p, n.typ, d) - linefmt(p, cpsStmts, "#nimDupRef((void**)$1, (void*)$2);$n", - [addrLoc(p.config, d), rdLoc(src)]) - proc genDestroy(p: BProc; n: PNode) = if optSeqDestructors in p.config.globalOptions: let arg = n[1].skipAddr @@ -2615,11 +2610,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mAccessTypeField: genAccessTypeField(p, e, d) of mSlice: genSlice(p, e, d) of mTrace: discard "no code to generate" - of mDup: - var a: TLoc - let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1] - initLocExpr(p, x, a) - genDup(p, a, d, e) else: when defined(debugMagics): echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 3275c1abc7..a03f85d025 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -188,7 +188,7 @@ template isUnpackedTuple(n: PNode): bool = proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) = var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">" - if (opname == "=" or opname == "=copy") and ri != nil: + if (opname == "=" or opname == "=copy" or opname == "=dup") and ri != nil: m.add "; requires a copy because it's not the last read of '" m.add renderTree(ri) m.add '\'' @@ -427,21 +427,17 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = if hasDestructor(c, n.typ): let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink}) let op = getAttachedOp(c.graph, typ, attachedDup) - if op != nil: + if op != nil and tfHasOwned notin typ.flags: + if sfError in op.flags: + c.checkForErrorPragma(n.typ, n, "=dup") let src = p(n, c, s, normal) - result.add newTreeI(nkFastAsgn, - src.info, tmp, - newTreeIT(nkCall, src.info, src.typ, + var newCall = newTreeIT(nkCall, src.info, src.typ, newSymNode(op), src) - ) - elif typ.kind == tyRef: - let src = p(n, c, s, normal) + c.finishCopy(newCall, n, isFromSink = true) result.add newTreeI(nkFastAsgn, src.info, tmp, - newTreeIT(nkCall, src.info, src.typ, - newSymNode(createMagic(c.graph, c.idgen, "`=dup`", mDup)), - src) + newCall ) else: result.add c.genWasMoved(tmp) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index e8db145690..e8f25f1a39 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -34,6 +34,7 @@ type template destructor*(t: PType): PSym = getAttachedOp(c.g, t, attachedDestructor) template assignment*(t: PType): PSym = getAttachedOp(c.g, t, attachedAsgn) +template dup*(t: PType): PSym = getAttachedOp(c.g, t, attachedDup) template asink*(t: PType): PSym = getAttachedOp(c.g, t, attachedSink) proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) @@ -82,7 +83,7 @@ proc genBuiltin(c: var TLiftCtx; magic: TMagic; name: string; i: PNode): PNode = result = genBuiltin(c.g, c.idgen, magic, name, i) proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = - if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}: + if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink, attachedDup}: body.add newAsgnStmt(x, y) elif c.kind == attachedDestructor and c.addMemReset: let call = genBuiltin(c, mDefault, "default", x) @@ -283,7 +284,7 @@ proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode = result.typ = getSysType(g, info, tyBool) proc getCycleParam(c: TLiftCtx): PNode = - assert c.kind == attachedAsgn + assert c.kind in {attachedAsgn, attachedDup} if c.fn.typ.len == 4: result = c.fn.typ.n.lastSon assert result.kind == nkSym @@ -322,6 +323,9 @@ proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode = proc newDeepCopyCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = result = newAsgnStmt(x, newOpCall(c, op, y)) +proc newDupCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = + result = newAsgnStmt(x, newOpCall(c, op, y)) + proc usesBuiltinArc(t: PType): bool = proc wrap(t: PType): bool {.nimcall.} = ast.isGCedMem(t) result = types.searchTypeFor(t, wrap) @@ -464,7 +468,18 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = result = true of attachedDup: - assert false, "cannot happen" + var op = getAttachedOp(c.g, t, attachedDup) + if op != nil and sfOverriden in op.flags: + + if op.ast.isGenericRoutine: + # patch generic destructor: + op = instantiateGeneric(c, op, t, t.typeInst) + setAttachedOp(c.g, c.idgen.module, t, attachedDup, op) + + #markUsed(c.g.config, c.info, op, c.g.usageSym) + onUse(c.info, op) + body.add newDupCall(c, op, x, y) + result = true proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info) @@ -526,6 +541,9 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind + of attachedDup: + body.add setLenSeqCall(c, t, x, y) + forallElements(c, t, body, x, y) of attachedAsgn, attachedDeepCopy: # we generate: # setLen(dest, y.len) @@ -549,15 +567,13 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # follow all elements: forallElements(c, t, body, x, y) of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) - of attachedDup: - assert false, "cannot happen" proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = createTypeBoundOps(c.g, c.c, t, body.info, c.idgen) # recursions are tricky, so we might need to forward the generated # operation here: var t = t - if t.assignment == nil or t.destructor == nil: + if t.assignment == nil or t.destructor == nil or t.dup == nil: let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct}) let canon = c.g.canonTypes.getOrDefault(h) if canon != nil: t = canon @@ -590,11 +606,15 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add newHookCall(c, op, x, y) of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) of attachedDup: - assert false, "cannot happen" + # XXX: replace these with assertions. + let op = getAttachedOp(c.g, t, c.kind) + if op == nil: + return # protect from recursion + body.add newDupCall(c, op, x, y) proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind - of attachedAsgn, attachedDeepCopy: + of attachedAsgn, attachedDeepCopy, attachedDup: body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y) of attachedSink: let moveCall = genBuiltin(c, mMove, "move", x) @@ -607,8 +627,6 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedTrace: discard "strings are atomic and have no inner elements that are to trace" of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) - of attachedDup: - assert false, "cannot happen" proc cyclicType*(g: ModuleGraph, t: PType): bool = case t.kind @@ -648,7 +666,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # dynamic Acyclic refs need to use dyn decRef let tmp = - if isCyclic and c.kind in {attachedAsgn, attachedSink}: + if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}: declareTempOf(c, body, x) else: x @@ -709,7 +727,14 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = #echo "can follow ", elemType, " static ", isFinal(elemType) of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) of attachedDup: - assert false, "cannot happen" + if isCyclic: + body.add newAsgnStmt(x, y) + body.add genIf(c, y, callCodegenProc(c.g, + "nimIncRefCyclic", c.info, y, getCycleParam(c))) + else: + body.add newAsgnStmt(x, y) + body.add genIf(c, y, callCodegenProc(c.g, + "nimIncRef", c.info, y)) proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = ## Closures are really like refs except they always use a virtual destructor @@ -719,7 +744,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let isCyclic = c.g.config.selectedGC == gcOrc let tmp = - if isCyclic and c.kind in {attachedAsgn, attachedSink}: + if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}: declareTempOf(c, body, xenv) else: xenv @@ -753,14 +778,21 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, cond, actions) body.add newAsgnStmt(x, y) + of attachedDup: + let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y) + yenv.typ = getSysType(c.g, c.info, tyPointer) + if isCyclic: + body.add newAsgnStmt(x, y) + body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c))) + else: + body.add newAsgnStmt(x, y) + body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv)) of attachedDestructor: body.add genIf(c, cond, actions) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y) of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) - of attachedDup: - assert false, "cannot happen" proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind @@ -773,6 +805,9 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y)) body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x)) body.add newAsgnStmt(x, y) + of attachedDup: + body.add newAsgnStmt(x, y) + body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y)) of attachedDestructor: # it's better to prepend the destruction of weak refs in order to # prevent wrong "dangling refs exist" problems: @@ -786,8 +821,6 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) - of attachedDup: - assert false, "cannot happen" proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = var actions = newNodeI(nkStmtList, c.info) @@ -809,13 +842,13 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedSink, attachedAsgn: body.add genIf(c, x, actions) body.add newAsgnStmt(x, y) + of attachedDup: + body.add newAsgnStmt(x, y) of attachedDestructor: body.add genIf(c, x, actions) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) - of attachedDup: - assert false, "cannot happen" proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = if c.kind == attachedDeepCopy: @@ -842,6 +875,11 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy)) body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx)) body.add newAsgnStmt(x, y) + of attachedDup: + let yy = genBuiltin(c, mAccessEnv, "accessEnv", y) + yy.typ = getSysType(c.g, c.info, tyPointer) + body.add newAsgnStmt(x, y) + body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy)) of attachedDestructor: let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx)) if body.len == 0: @@ -851,8 +889,6 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) - of attachedDup: - assert false, "cannot happen" proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let xx = genBuiltin(c, mAccessEnv, "accessEnv", x) @@ -864,13 +900,13 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedSink, attachedAsgn: body.add genIf(c, xx, actions) body.add newAsgnStmt(x, y) + of attachedDup: + body.add newAsgnStmt(x, y) of attachedDestructor: body.add genIf(c, xx, actions) of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: discard of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) - of attachedDup: - assert false, "cannot happen" proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind @@ -936,7 +972,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = if not considerUserDefinedOp(c, t, body, x, y): if t.sym != nil and sfImportc in t.sym.flags: case c.kind - of {attachedAsgn, attachedSink}: + of {attachedAsgn, attachedSink, attachedDup}: body.add newAsgnStmt(x, y) of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x) @@ -976,8 +1012,44 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; result = getAttachedOp(g, baseType, kind) setAttachedOp(g, idgen.module, typ, kind, result) +proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp; + info: TLineInfo; idgen: IdGenerator): PSym = + let procname = getIdent(g.cache, AttachedOpToStr[kind]) + result = newSym(skProc, procname, idgen, owner, info) + let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info) + let src = newSym(skParam, getIdent(g.cache, "src"), + idgen, result, info) + res.typ = typ + src.typ = typ + + result.typ = newType(tyProc, nextTypeId idgen, owner) + result.typ.n = newNodeI(nkFormalParams, info) + rawAddSon(result.typ, res.typ) + result.typ.n.add newNodeI(nkEffectList, info) + + result.typ.addParam src + + if g.config.selectedGC == gcOrc and + cyclicType(g, typ.skipTypes(abstractInst)): + let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"), + idgen, result, info) + cycleParam.typ = getSysType(g, info, tyBool) + result.typ.addParam cycleParam + + var n = newNodeI(nkProcDef, info, bodyPos+2) + for i in 0..
    +
    AnotherObject:
    anything:
    • testproject: proc anything()
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index d08a12544f..d2d3fef3fd 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -400,3 +400,11 @@ type # bug #21483 MyObject* = object someString*: string ## This is a string annotated* {.somePragma.}: string ## This is an annotated string + +type + AnotherObject* = object + case x*: bool + of true: + y*: proc (x: string) + of false: + hidden: string From f16b94a9d7011bd00ebb3966d76ef8b2c0dfc752 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 18 Jul 2023 22:05:05 +0800 Subject: [PATCH 325/489] extend the skipAddr for potential types for destructors (#22265) extend the skipAddr for potential types --- compiler/semmagic.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index e7057053b7..f94d8dc33e 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -610,8 +610,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, if op != nil: result[0] = newSymNode(op) - if op.typ != nil and op.typ.len == 2 and op.typ[1].kind != tyVar and - skipAddr(n[1]).typ.kind == tyDistinct: + if op.typ != nil and op.typ.len == 2 and op.typ[1].kind != tyVar: if n[1].kind == nkSym and n[1].sym.kind == skParam and n[1].typ.kind == tyVar: result[1] = genDeref(n[1]) From 14a9929464b9f658155ed429397216736fccc259 Mon Sep 17 00:00:00 2001 From: Anna Date: Tue, 18 Jul 2023 19:06:21 +0500 Subject: [PATCH 326/489] Fix #22281 (#22289) Respect `--gcc.exe` and similar options when `--genScript:on` is used. --- compiler/extccomp.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 832242456a..391f158f0c 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -580,7 +580,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile, compilePattern = joinPath(conf.cCompilerPath, exe) else: - compilePattern = getCompilerExe(conf, c, isCpp) + compilePattern = exe includeCmd.add(join([CC[c].includeCmd, quoteShell(conf.projectPath.string)])) From 1aff402998e6c17a3d72a8dc23fb655208d93fcb Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 19 Jul 2023 15:45:28 +0800 Subject: [PATCH 327/489] fixes #6499; disallow built-in procs used as procvars (#22291) --- compiler/sempass2.nim | 1 + tests/errmsgs/t6499.nim | 6 ++++++ tests/system/tmagics.nim | 4 ---- 3 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 tests/errmsgs/t6499.nim diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index b58d08a018..9747110471 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1223,6 +1223,7 @@ proc track(tracked: PEffects, n: PNode) = of nkTupleConstr: for i in 0.. Date: Wed, 19 Jul 2023 18:57:58 +0800 Subject: [PATCH 328/489] fixes #22268; fixes `move` codegen (#22288) --- compiler/ccgexprs.nim | 7 +++++++ compiler/liftdestructors.nim | 6 +++--- compiler/lowerings.nim | 13 ++----------- lib/system.nim | 28 ++++++++-------------------- 4 files changed, 20 insertions(+), 34 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 00781a31d8..2b9f4221f0 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2359,6 +2359,13 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) = if d.k == locNone: getTemp(p, n.typ, d) if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}: genAssignment(p, d, a, {}) + var op = getAttachedOp(p.module.g.graph, n.typ, attachedWasMoved) + if op == nil: + resetLoc(p, a) + else: + let addrExp = makeAddr(n[1], p.module.idgen) + let wasMovedCall = newTreeI(nkCall, n.info, newSymNode(op), addrExp) + genCall(p, wasMovedCall, d) else: let flags = if not canMove(p, n[1], d): {needToCopy} else: {} genAssignment(p, d, a, flags) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index eac2323aa9..11d483abb3 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -556,7 +556,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add setLenSeqCall(c, t, x, y) forallElements(c, t, body, x, y) of attachedSink: - let moveCall = genBuiltin(c, mMove, "internalMove", x) + let moveCall = genBuiltin(c, mMove, "move", x) moveCall.add y doAssert t.destructor != nil moveCall.add destructorCall(c, t.destructor, x) @@ -589,7 +589,7 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add newHookCall(c, t.assignment, x, y) of attachedSink: # we always inline the move for better performance: - let moveCall = genBuiltin(c, mMove, "internalMove", x) + let moveCall = genBuiltin(c, mMove, "move", x) moveCall.add y doAssert t.destructor != nil moveCall.add destructorCall(c, t.destructor, x) @@ -620,7 +620,7 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedAsgn, attachedDeepCopy, attachedDup: body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y) of attachedSink: - let moveCall = genBuiltin(c, mMove, "internalMove", x) + let moveCall = genBuiltin(c, mMove, "move", x) moveCall.add y doAssert t.destructor != nil moveCall.add destructorCall(c, t.destructor, x) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 3f67fc168e..d70c713a15 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -66,17 +66,8 @@ proc newFastMoveStmt*(g: ModuleGraph, le, ri: PNode): PNode = result = newNodeI(nkFastAsgn, le.info, 2) result[0] = le result[1] = newNodeIT(nkCall, ri.info, ri.typ) - if g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}: - result[1].add newSymNode(getCompilerProc(g, "internalMove")) - result[1].add ri - result = newTreeI(nkStmtList, le.info, result, - newTree(nkCall, newSymNode( - getSysMagic(g, ri.info, "=wasMoved", mWasMoved)), - ri - )) - else: - result[1].add newSymNode(getSysMagic(g, ri.info, "move", mMove)) - result[1].add ri + result[1].add newSymNode(getSysMagic(g, ri.info, "move", mMove)) + result[1].add ri proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode = assert n.kind == nkVarTuple diff --git a/lib/system.nim b/lib/system.nim index 50debcc895..858571d61b 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -151,26 +151,10 @@ proc wasMoved*[T](obj: var T) {.inline, noSideEffect.} = {.cast(raises: []), cast(tags: []).}: `=wasMoved`(obj) -const notJSnotNims = not defined(js) and not defined(nimscript) -const arcLikeMem = defined(gcArc) or defined(gcAtomicArc) or defined(gcOrc) - -when notJSnotNims and arcLikeMem: - proc internalMove[T](x: var T): T {.magic: "Move", noSideEffect, compilerproc.} = - result = x - - proc move*[T](x: var T): T {.noSideEffect, nodestroy.} = - {.cast(noSideEffect).}: - when nimvm: - result = internalMove(x) - else: - result = internalMove(x) - {.cast(raises: []), cast(tags: []).}: - `=wasMoved`(x) -else: - proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} = - result = x - {.cast(raises: []), cast(tags: []).}: - `=wasMoved`(x) +proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} = + result = x + {.cast(raises: []), cast(tags: []).}: + `=wasMoved`(x) type range*[T]{.magic: "Range".} ## Generic type to construct range types. @@ -369,6 +353,9 @@ proc arrGet[I: Ordinal;T](a: T; i: I): T {. proc arrPut[I: Ordinal;T,S](a: T; i: I; x: S) {.noSideEffect, magic: "ArrPut".} +const arcLikeMem = defined(gcArc) or defined(gcAtomicArc) or defined(gcOrc) + + when defined(nimAllowNonVarDestructor) and arcLikeMem: proc `=destroy`*(x: string) {.inline, magic: "Destroy".} = discard @@ -445,6 +432,7 @@ include "system/inclrtl" const NoFakeVars = defined(nimscript) ## `true` if the backend doesn't support \ ## "fake variables" like `var EBADF {.importc.}: cint`. +const notJSnotNims = not defined(js) and not defined(nimscript) when not defined(js) and not defined(nimSeqsV2): type From 0d3bde95f578576d2e84d422d5694ee0e0055cbc Mon Sep 17 00:00:00 2001 From: Ryan McConnell Date: Wed, 19 Jul 2023 09:04:14 -0400 Subject: [PATCH 329/489] Adding info to manual (#22252) * Adjustments * Moving example * typo * adding code example back and fix terms * Condensing --- doc/manual.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/doc/manual.md b/doc/manual.md index 1c3e668791..e3a036f0ca 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -2642,9 +2642,15 @@ of the argument. 6. Conversion match: `a` is convertible to `f`, possibly via a user defined `converter`. -These matching categories have a priority: An exact match is better than a -literal match and that is better than a generic match etc. In the following, -`count(p, m)` counts the number of matches of the matching category `m` + +There are two major methods of selecting the best matching candidate, namely +counting and disambiguation. Counting takes precedence to disambiguation. In counting, +each parameter is given a category and the number of parameters in each category is counted. +The categories are listed above and are in order of precedence. For example, if +a candidate with one exact match is compared to a candidate with multiple generic matches +and zero exact matches, the candidate with an exact match will win. + +In the following, `count(p, m)` counts the number of matches of the matching category `m` for the routine `p`. A routine `p` matches better than a routine `q` if the following @@ -2662,6 +2668,11 @@ algorithm returns true: return "ambiguous" ``` +When counting is ambiguous, disambiguation begins. Parameters are iterated +by position and these parameter pairs are compared for their type relation. The general goal +of this comparison is to determine which parameter is more specific. The types considered are +not of the inputs from the callsite, but of the competing candidates' parameters. + Some examples: @@ -5470,6 +5481,49 @@ The following example shows how a generic binary tree can be modeled: The `T` is called a `generic type parameter`:idx: or a `type variable`:idx:. + +Generic Procs +--------------- + +Let's consider the anatomy of a generic `proc` to agree on defined terminology. + +```nim +p[T: t](arg1: f): y +``` + +- `p`: Callee symbol +- `[...]`: Generic parameters +- `T: t`: Generic constraint +- `T`: Type variable +- `[T: t](arg1: f): y`: Formal signature +- `arg1: f`: Formal parameter +- `f`: Formal parameter type +- `y`: Formal return type + +The use of the word "formal" here is to denote the symbols as they are defined by the programmer, +not as they may be at compile time contextually. Since generics may be instantiated and +types bound, we have more than one entity to think about when generics are involved. + +The usage of a generic will resolve the formally defined expression into an instance of that +expression bound to only concrete types. This process is called "instantiation". + +Brackets at the site of a generic's formal definition specify the "constraints" as in: + +```nim +type Foo[T] = object +proc p[H;T: Foo[H]](param: T): H +``` + +A constraint definition may have more than one symbol defined by seperating each definition by +a `;`. Notice how `T` is composed of `H` and the return type of `p` is defined as `H`. When this +generic proc is instantiated `H` will be bound to a concrete type, thus making `T` concrete and +the return type of `p` will be bound to the same concrete type used to define `H`. + +Brackets at the site of usage can be used to supply concrete types to instantiate the generic in the same +order that the symbols are defined in the constraint. Alternatively, type bindings may be inferred by the compiler +in some situations, allowing for cleaner code. + + Is operator ----------- From 5ed44e1ec463b68180e17cfe59c8c68d8c55d406 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 19 Jul 2023 21:20:41 +0800 Subject: [PATCH 330/489] fixes #22254; fixes #22253; stricteffects bugs on recursive calls (#22294) --- lib/pure/json.nim | 5 +++-- tests/effects/tstrict_effects3.nim | 11 +++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 2e448dba70..fcb9eae41b 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -438,7 +438,7 @@ macro `%*`*(x: untyped): untyped = ## `%` for every element. result = toJsonImpl(x) -proc `==`*(a, b: JsonNode): bool {.noSideEffect.} = +proc `==`*(a, b: JsonNode): bool {.noSideEffect, raises: [].} = ## Check two nodes for equality if a.isNil: if b.isNil: return true @@ -458,7 +458,8 @@ proc `==`*(a, b: JsonNode): bool {.noSideEffect.} = of JNull: result = true of JArray: - result = a.elems == b.elems + {.cast(raises: []).}: # bug #19303 + result = a.elems == b.elems of JObject: # we cannot use OrderedTable's equality here as # the order does not matter for equality here. diff --git a/tests/effects/tstrict_effects3.nim b/tests/effects/tstrict_effects3.nim index 027b464741..0d98a0343d 100644 --- a/tests/effects/tstrict_effects3.nim +++ b/tests/effects/tstrict_effects3.nim @@ -44,3 +44,14 @@ proc fail() = discard f1() f2() +import std/json + +# bug #22254 +proc senri(a, b: seq[JsonNode]) {.raises: [].} = discard a == b + +# bug #22253 +proc serika() {.raises: [].} = discard default(JsonNode) == nil + +senri(@[newJBool(true)], @[newJBool(false)]) +serika() + From c1a82aa5c5ab68dfc2ab6f09779d9ab9bbf3758f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 19 Jul 2023 16:03:26 +0200 Subject: [PATCH 331/489] minor code improvement (#22293) --- compiler/closureiters.nim | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 3c5d3991be..ae4fde0f6a 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -1389,7 +1389,7 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode = discard c.finallys.pop() of nkWhileStmt, nkBlockStmt: - if n.hasYields == false: return n + if not n.hasYields: return n c.blocks.add((n, c.finallys.len)) for i in 0 ..< n.len: result[i] = preprocess(c, n[i]) @@ -1466,9 +1466,10 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n: result = ctx.transformStateAssignments(result) result = ctx.wrapIntoStateLoop(result) - # echo "TRANSFORM TO STATES: " - # echo renderTree(result) + when false: + echo "TRANSFORM TO STATES: " + echo renderTree(result) - # echo "exception table:" - # for i, e in ctx.exceptionTable: - # echo i, " -> ", e + echo "exception table:" + for i, e in ctx.exceptionTable: + echo i, " -> ", e From 3f9e16594fb26b78f812094a86d5e269093d8034 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Fri, 21 Jul 2023 03:56:04 +1000 Subject: [PATCH 332/489] fix `jsondoc` not getting `showNonExports` flag (#22267) Pass the config down so we can check if the `--showNonExports` flag is used --- compiler/docgen.nim | 17 ++++++++++------- compiler/docgen2.nim | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 958d804b34..829d86dfdc 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1145,13 +1145,16 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx if k == skType and nameNode.kind == nkSym: d.types.strTableAdd nameNode.sym -proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonItem = +proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): JsonItem = if not isVisible(d, nameNode): return var name = getNameEsc(d, nameNode) comm = genRecComment(d, n) r: TSrcGen - initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing}) + renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing} + if nonExports: + renderFlags.incl renderNonExportedFields + initTokRender(r, n, renderFlags) result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int, "col": %n.info.col} if comm != nil: @@ -1536,7 +1539,7 @@ proc finishGenerateDoc*(d: var PDoc) = proc add(d: PDoc; j: JsonItem) = if j.json != nil or j.rst != nil: d.jEntriesPre.add j -proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) = +proc generateJson*(d: PDoc, n: PNode, config: ConfigRef, includeComments: bool = true) = case n.kind of nkPragma: let doctypeNode = findPragma(n, wDoctype) @@ -1568,14 +1571,14 @@ proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) = if n[i].kind != nkCommentStmt: # order is always 'type var let const': d.add genJsonItem(d, n[i], n[i][0], - succ(skType, ord(n.kind)-ord(nkTypeSection))) + succ(skType, ord(n.kind)-ord(nkTypeSection)), optShowNonExportedFields in config.globalOptions) of nkStmtList: for i in 0.. Date: Thu, 20 Jul 2023 13:56:54 -0400 Subject: [PATCH 333/489] `infixArgument` fail in `renderer.nim` sometimes (#22264) * fixing minor typo * Adding err msg --- compiler/renderer.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index ac4ff2a77e..b9c3268c4c 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1038,7 +1038,7 @@ proc accentedName(g: var TSrcGen, n: PNode) = gsub(g, n) proc infixArgument(g: var TSrcGen, n: PNode, i: int) = - if i < 1 and i > 2: return + if i < 1 or i > 2: return var needsParenthesis = false let nNext = n[i].skipHiddenNodes if nNext.kind == nkInfix: @@ -1382,6 +1382,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = putWithSpace(g, tkColon, ":") gsub(g, n, 1) of nkInfix: + if n.len < 3: + var i = 0 + put(g, tkOpr, "Too few children for nkInfix") + return let oldLineLen = g.lineLen # we cache this because lineLen gets updated below infixArgument(g, n, 1) put(g, tkSpaces, Space) From 91987f8eb56b47bd88c3f27784818bde4fd05ce2 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 21 Jul 2023 11:40:11 +0800 Subject: [PATCH 334/489] fixes #22210; transform return future in try/finally properly (#22249) * wip; fixes #22210; transform return future in try/finally properly * add a test case for #22210 * minor * inserts a needsCompletion flag * uses copyNimNode --- lib/pure/asyncmacro.nim | 61 +++++++++++++++++++++++++++------ tests/async/t22210.nim | 41 ++++++++++++++++++++++ tests/async/t22210_2.nim | 73 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 11 deletions(-) create mode 100644 tests/async/t22210.nim create mode 100644 tests/async/t22210_2.nim diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index e41568b8c1..a026e159e8 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -11,6 +11,11 @@ import macros, strutils, asyncfutures +type + Context = ref object + inTry: int + hasRet: bool + # TODO: Ref https://github.com/nim-lang/Nim/issues/5617 # TODO: Add more line infos proc newCallWithLineInfo(fromNode: NimNode; theProc: NimNode, args: varargs[NimNode]): NimNode = @@ -63,7 +68,7 @@ proc createFutureVarCompletions(futureVarIdents: seq[NimNode], fromNode: NimNode ) ) -proc processBody(node, retFutureSym: NimNode, futureVarIdents: seq[NimNode]): NimNode = +proc processBody(ctx: Context; node, needsCompletionSym, retFutureSym: NimNode, futureVarIdents: seq[NimNode]): NimNode = result = node case node.kind of nnkReturnStmt: @@ -72,23 +77,53 @@ proc processBody(node, retFutureSym: NimNode, futureVarIdents: seq[NimNode]): Ni # As I've painfully found out, the order here really DOES matter. result.add createFutureVarCompletions(futureVarIdents, node) + ctx.hasRet = true if node[0].kind == nnkEmpty: - result.add newCall(newIdentNode("complete"), retFutureSym, newIdentNode("result")) - else: - let x = node[0].processBody(retFutureSym, futureVarIdents) - if x.kind == nnkYieldStmt: result.add x + if ctx.inTry == 0: + result.add newCallWithLineInfo(node, newIdentNode("complete"), retFutureSym, newIdentNode("result")) else: - result.add newCall(newIdentNode("complete"), retFutureSym, x) + result.add newAssignment(needsCompletionSym, newLit(true)) + else: + let x = processBody(ctx, node[0], needsCompletionSym, retFutureSym, futureVarIdents) + if x.kind == nnkYieldStmt: result.add x + elif ctx.inTry == 0: + result.add newCallWithLineInfo(node, newIdentNode("complete"), retFutureSym, x) + else: + result.add newAssignment(newIdentNode("result"), x) + result.add newAssignment(needsCompletionSym, newLit(true)) result.add newNimNode(nnkReturnStmt, node).add(newNilLit()) return # Don't process the children of this return stmt of RoutineNodes-{nnkTemplateDef}: # skip all the nested procedure definitions return - else: discard - - for i in 0 ..< result.len: - result[i] = processBody(result[i], retFutureSym, futureVarIdents) + of nnkTryStmt: + if result[^1].kind == nnkFinally: + inc ctx.inTry + result[0] = processBody(ctx, result[0], needsCompletionSym, retFutureSym, futureVarIdents) + dec ctx.inTry + for i in 1 ..< result.len: + result[i] = processBody(ctx, result[i], needsCompletionSym, retFutureSym, futureVarIdents) + if ctx.inTry == 0 and ctx.hasRet: + let finallyNode = copyNimNode(result[^1]) + let stmtNode = newNimNode(nnkStmtList) + for child in result[^1]: + stmtNode.add child + stmtNode.add newIfStmt( + ( needsCompletionSym, + newCallWithLineInfo(node, newIdentNode("complete"), retFutureSym, + newIdentNode("result") + ) + ) + ) + finallyNode.add stmtNode + result[^1] = finallyNode + else: + for i in 0 ..< result.len: + result[i] = processBody(ctx, result[i], needsCompletionSym, retFutureSym, futureVarIdents) + else: + for i in 0 ..< result.len: + result[i] = processBody(ctx, result[i], needsCompletionSym, retFutureSym, futureVarIdents) # echo result.repr @@ -213,7 +248,9 @@ proc asyncSingleProc(prc: NimNode): NimNode = # -> # -> complete(retFuture, result) var iteratorNameSym = genSym(nskIterator, $prcName & " (Async)") - var procBody = prc.body.processBody(retFutureSym, futureVarIdents) + var needsCompletionSym = genSym(nskVar, "needsCompletion") + var ctx = Context() + var procBody = processBody(ctx, prc.body, needsCompletionSym, retFutureSym, futureVarIdents) # don't do anything with forward bodies (empty) if procBody.kind != nnkEmpty: # fix #13899, defer should not escape its original scope @@ -234,6 +271,8 @@ proc asyncSingleProc(prc: NimNode): NimNode = else: var `resultIdent`: Future[void] {.pop.} + + var `needsCompletionSym` = false procBody.add quote do: complete(`retFutureSym`, `resultIdent`) diff --git a/tests/async/t22210.nim b/tests/async/t22210.nim new file mode 100644 index 0000000000..fcf9394725 --- /dev/null +++ b/tests/async/t22210.nim @@ -0,0 +1,41 @@ +discard """ +output: ''' +stage 1 +stage 2 +stage 3 +(status: 200, data: "SOMEDATA") +''' +""" + +import std/asyncdispatch + + +# bug #22210 +type + ClientResponse = object + status*: int + data*: string + +proc subFoo1(): Future[int] {.async.} = + await sleepAsync(100) + return 200 + +proc subFoo2(): Future[string] {.async.} = + await sleepAsync(100) + return "SOMEDATA" + +proc testFoo(): Future[ClientResponse] {.async.} = + try: + let status = await subFoo1() + doAssert(status == 200) + let data = await subFoo2() + return ClientResponse(status: status, data: data) + finally: + echo "stage 1" + await sleepAsync(100) + echo "stage 2" + await sleepAsync(200) + echo "stage 3" + +when isMainModule: + echo waitFor testFoo() \ No newline at end of file diff --git a/tests/async/t22210_2.nim b/tests/async/t22210_2.nim new file mode 100644 index 0000000000..9db664a32d --- /dev/null +++ b/tests/async/t22210_2.nim @@ -0,0 +1,73 @@ +import std/asyncdispatch + + +# bug #22210 +type + ClientResponse = object + status*: int + data*: string + +proc subFoo1(): Future[int] {.async.} = + await sleepAsync(100) + return 200 + +proc subFoo2(): Future[string] {.async.} = + await sleepAsync(100) + return "SOMEDATA" + + +proc testFoo2(): Future[ClientResponse] {.async.} = + var flag = 0 + try: + let status = await subFoo1() + doAssert(status == 200) + let data = await subFoo2() + result = ClientResponse(status: status, data: data) + finally: + inc flag + await sleepAsync(100) + inc flag + await sleepAsync(200) + inc flag + doAssert flag == 3 + +discard waitFor testFoo2() + +proc testFoo3(): Future[ClientResponse] {.async.} = + var flag = 0 + try: + let status = await subFoo1() + doAssert(status == 200) + let data = await subFoo2() + if false: + return ClientResponse(status: status, data: data) + finally: + inc flag + await sleepAsync(100) + inc flag + await sleepAsync(200) + inc flag + doAssert flag == 3 + +discard waitFor testFoo3() + + +proc testFoo4(): Future[ClientResponse] {.async.} = + var flag = 0 + try: + let status = await subFoo1() + doAssert(status == 200) + let data = await subFoo2() + if status == 200: + return ClientResponse(status: status, data: data) + else: + return ClientResponse() + finally: + inc flag + await sleepAsync(100) + inc flag + await sleepAsync(200) + inc flag + doAssert flag == 3 + +discard waitFor testFoo4() From 993fcf5bdac32964237b29e279ecf839095ac609 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 22 Jul 2023 11:31:01 +0800 Subject: [PATCH 335/489] fixes CI; disable SSL tests on osx for now (#22304) * test CI * disable osx --- tests/async/tasyncssl.nim | 1 + tests/misc/trunner_special.nim | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim index 222aaa3a18..57de3271d5 100644 --- a/tests/async/tasyncssl.nim +++ b/tests/async/tasyncssl.nim @@ -1,5 +1,6 @@ discard """ cmd: "nim $target --hints:on --define:ssl $options $file" + disabled: osx """ import asyncdispatch, asyncnet, net, strutils diff --git a/tests/misc/trunner_special.nim b/tests/misc/trunner_special.nim index 50a2e4d5ad..e138107226 100644 --- a/tests/misc/trunner_special.nim +++ b/tests/misc/trunner_special.nim @@ -1,6 +1,7 @@ discard """ targets: "c cpp" joinable: false + disabled: osx """ #[ From b02c1dd6ca96548b47d978f96278c67bf59e9d9e Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 22 Jul 2023 12:37:27 +0800 Subject: [PATCH 336/489] fixes #22297; return in the finally in the closure iterators (#22300) ref #22297; return in the finally in the closure iterators --- compiler/closureiters.nim | 4 +++- tests/closure/tclosure.nim | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index ae4fde0f6a..87c5b795eb 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -855,7 +855,9 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode = case n.kind of nkReturnStmt: # We're somewhere in try, transform to finally unrolling - assert(ctx.nearestFinally != 0) + if ctx.nearestFinally == 0: + # return is within the finally + return result = newNodeI(nkStmtList, n.info) diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim index fa1f79ffeb..401a71d400 100644 --- a/tests/closure/tclosure.nim +++ b/tests/closure/tclosure.nim @@ -491,3 +491,14 @@ block tnoclosure: row = zip(row & @[0], @[0] & row).mapIt(it[0] + it[1]) echo row pascal(10) + +block: # bug #22297 + iterator f: int {.closure.} = + try: + yield 12 + finally: + return 14 + + let s = f + doAssert s() == 12 + doAssert s() == 14 From 3ebe24977ce93ca3c347550c69dbfa7c9a7db507 Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Sat, 22 Jul 2023 19:09:39 +0200 Subject: [PATCH 337/489] Open scope for defer (#22315) Co-authored-by: SirOlaf <> --- compiler/semexprs.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 1d917f00d9..c6be3e833c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -3282,7 +3282,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType of nkDefer: if c.currentScope == c.topLevelScope: localError(c.config, n.info, "defer statement not supported at top level") + openScope(c) n[0] = semExpr(c, n[0]) + closeScope(c) if not n[0].typ.isEmptyType and not implicitlyDiscardable(n[0]): localError(c.config, n.info, "'defer' takes a 'void' expression") #localError(c.config, n.info, errGenerated, "'defer' not allowed in this context") From 576f4a73483a5d3b4c600f6d3d3c85394ffb43ee Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Sat, 22 Jul 2023 19:10:12 +0200 Subject: [PATCH 338/489] Fix doc comment rendering for concepts (#22312) --- compiler/docgen.nim | 2 +- tests/concepts/t20237.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 829d86dfdc..5120b52238 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -440,7 +440,7 @@ proc genRecCommentAux(d: PDoc, n: PNode): PRstNode = if n == nil: return nil result = genComment(d, n) if result == nil: - if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef, + if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef, nkTypeClassTy, nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkSinkAsgn, nkHiddenStdConv}: # notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}: for i in 0.. Date: Sat, 22 Jul 2023 21:11:08 +0200 Subject: [PATCH 339/489] Add test for #22309 (#22316) --- tests/defer/t22309.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/defer/t22309.nim diff --git a/tests/defer/t22309.nim b/tests/defer/t22309.nim new file mode 100644 index 0000000000..34ca4843b2 --- /dev/null +++ b/tests/defer/t22309.nim @@ -0,0 +1,11 @@ +block: + defer: + let a = 42 + doAssert not declared(a) + +proc lol() = + defer: + let a = 42 + doAssert not declared(a) + +lol() From e2ea9140ace56d9ed2d40cef5c63b4a271788214 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Sat, 22 Jul 2023 21:11:49 +0200 Subject: [PATCH 340/489] Document `cast` zeroing memory (#22313) --- doc/manual.md | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/doc/manual.md b/doc/manual.md index e3a036f0ca..45eb8fef56 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -2643,11 +2643,11 @@ of the argument. defined `converter`. -There are two major methods of selecting the best matching candidate, namely +There are two major methods of selecting the best matching candidate, namely counting and disambiguation. Counting takes precedence to disambiguation. In counting, each parameter is given a category and the number of parameters in each category is counted. The categories are listed above and are in order of precedence. For example, if -a candidate with one exact match is compared to a candidate with multiple generic matches +a candidate with one exact match is compared to a candidate with multiple generic matches and zero exact matches, the candidate with an exact match will win. In the following, `count(p, m)` counts the number of matches of the matching category `m` @@ -2668,9 +2668,9 @@ algorithm returns true: return "ambiguous" ``` -When counting is ambiguous, disambiguation begins. Parameters are iterated +When counting is ambiguous, disambiguation begins. Parameters are iterated by position and these parameter pairs are compared for their type relation. The general goal -of this comparison is to determine which parameter is more specific. The types considered are +of this comparison is to determine which parameter is more specific. The types considered are not of the inputs from the callsite, but of the competing candidates' parameters. @@ -3760,6 +3760,9 @@ bit pattern of the data being cast (aside from that the size of the target type may differ from the source type). Casting resembles *type punning* in other languages or C++'s `reinterpret_cast`:cpp: and `bit_cast`:cpp: features. +If the size of the target type is larger than the size of the source type, +the remaining memory is zeroed. + The addr operator ----------------- The `addr` operator returns the address of an l-value. If the type of the @@ -5500,7 +5503,7 @@ p[T: t](arg1: f): y - `f`: Formal parameter type - `y`: Formal return type -The use of the word "formal" here is to denote the symbols as they are defined by the programmer, +The use of the word "formal" here is to denote the symbols as they are defined by the programmer, not as they may be at compile time contextually. Since generics may be instantiated and types bound, we have more than one entity to think about when generics are involved. @@ -5514,9 +5517,9 @@ type Foo[T] = object proc p[H;T: Foo[H]](param: T): H ``` -A constraint definition may have more than one symbol defined by seperating each definition by -a `;`. Notice how `T` is composed of `H` and the return type of `p` is defined as `H`. When this -generic proc is instantiated `H` will be bound to a concrete type, thus making `T` concrete and +A constraint definition may have more than one symbol defined by seperating each definition by +a `;`. Notice how `T` is composed of `H` and the return type of `p` is defined as `H`. When this +generic proc is instantiated `H` will be bound to a concrete type, thus making `T` concrete and the return type of `p` will be bound to the same concrete type used to define `H`. Brackets at the site of usage can be used to supply concrete types to instantiate the generic in the same @@ -8538,18 +8541,18 @@ The `bycopy` pragma can be applied to an object or tuple type or a proc param. I x, y, z: float ``` -The Nim compiler automatically determines whether a parameter is passed by value or -by reference based on the parameter type's size. If a parameter must be passed by value -or by reference, (such as when interfacing with a C library) use the bycopy or byref pragmas. +The Nim compiler automatically determines whether a parameter is passed by value or +by reference based on the parameter type's size. If a parameter must be passed by value +or by reference, (such as when interfacing with a C library) use the bycopy or byref pragmas. Notice params marked as `byref` takes precedence over types marked as `bycopy`. Byref pragma ------------ The `byref` pragma can be applied to an object or tuple type or a proc param. -When applied to a type it instructs the compiler to pass the type by reference -(hidden pointer) to procs. When applied to a param it will take precedence, even -if the the type was marked as `bycopy`. When using the Cpp backend, params marked +When applied to a type it instructs the compiler to pass the type by reference +(hidden pointer) to procs. When applied to a param it will take precedence, even +if the the type was marked as `bycopy`. When using the Cpp backend, params marked as byref will translate to cpp references `&`. Varargs pragma From b10d3cd98d66b9fff20f9bf37d454c07ebbd42b2 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Sat, 22 Jul 2023 21:13:23 +0200 Subject: [PATCH 341/489] Update 2.0 changelog (#22311) --- changelogs/changelog_2_0_0.md | 73 +++++++------- changelogs/changelog_2_0_0_details.md | 137 ++++++++++++++------------ 2 files changed, 110 insertions(+), 100 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index 85a0753d00..d954c774ef 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -2,7 +2,7 @@ Version 2.0 is a big milestone with too many changes to list them all here. -For a full list see [details](changelog_2_0_0_details.html) +For a full list see [details](changelog_2_0_0_details.html). ## New features @@ -31,10 +31,9 @@ For example, code like the following now compiles: let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")] ``` - ### Forbidden Tags -[Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) supports the definition +[Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) now supports the definition of forbidden tags by the `.forbids` pragma which can be used to disable certain effects in proc types. For example: @@ -53,11 +52,11 @@ proc no_IO_please() {.forbids: [IO].} = ``` -### New standard libraries +### New standard library modules The famous `os` module got an overhaul. Several of its features are available under a new interface that introduces a `Path` abstraction. A `Path` is -a `distinct string` and improves the type safety when dealing with paths, files +a `distinct string`, which improves the type safety when dealing with paths, files and directories. Use: @@ -71,7 +70,6 @@ Use: - `std/appdirs` for accessing configuration/home/temp directories. - `std/cmdline` for reading command line parameters. - ### Consistent underscore handling The underscore identifier (`_`) is now generally not added to scope when @@ -127,47 +125,49 @@ old behavior is currently still supported with the command line option ## Docgen improvements -`Markdown` is now default markup language of doc comments (instead -of legacy `RstMarkdown` mode). In this release we begin to separate +`Markdown` is now the default markup language of doc comments (instead +of the legacy `RstMarkdown` mode). In this release we begin to separate RST and Markdown features to better follow specification of each language, with the focus on Markdown development. +See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html). -* So we added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to - select the markup language mode in the doc comments of current `.nim` +* Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to + select the markup language mode in the doc comments of the current `.nim` file for processing by `nim doc`: 1. `Markdown` (default) is basically CommonMark (standard Markdown) + some Pandoc Markdown features + some RST features that are missing in our current implementation of CommonMark and Pandoc Markdown. - 2. `RST` closely follows RST spec with few additional Nim features. + 2. `RST` closely follows the RST spec with few additional Nim features. 3. `RstMarkdown` is a maximum mix of RST and Markdown features, which is kept for the sake of compatibility and ease of migration. -* We added separate `md2html` and `rst2html` commands for processing - standalone `.md` and `.rst` files respectively (and also `md2tex/rst2tex`). +* Added separate `md2html` and `rst2html` commands for processing + standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`). -* We added Pandoc Markdown bracket syntax `[...]` for making anchor-less links. -* The docgen now supports concise syntax for referencing Nim symbols: +* Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links. +* Docgen now supports concise syntax for referencing Nim symbols: instead of specifying HTML anchors directly one can use original Nim symbol declarations (adding the aforementioned link brackets `[...]` around them). -* To use this feature across modules a new `importdoc` directive was added. - Using this feature for referencing also helps to ensure that links - (inside one module or the whole project) are not broken. -* We added support for RST & Markdown quote blocks (blocks starting from `>`). -* We added a popular Markdown definition lists extension. -* Markdown indented code blocks (blocks indented by >= 4 spaces) have been added. -* We added syntax for additional parameters to Markdown code blocks: + * To use this feature across modules, a new `importdoc` directive was added. + Using this feature for referencing also helps to ensure that links + (inside one module or the whole project) are not broken. +* Added support for RST & Markdown quote blocks (blocks starting with `>`). +* Added a popular Markdown definition lists extension. +* Added Markdown indented code blocks (blocks indented by >= 4 spaces). +* Added syntax for additional parameters to Markdown code blocks: ```nim test="nim c $1" ... ``` + ## C++ interop enhancements -Nim 2.0 takes C++ interop to the next level. With the new [virtual](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma and the extended [constructor](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma -Now one can define constructors and virtual that maps to C++ constructors and virtual methods. Allowing one to further customize -the interoperability. There is also extended support for the [codeGenDecl](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-codegendecl-pragma) pragma, so it works on types. +Nim 2.0 takes C++ interop to the next level. With the new [virtual](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma and the extended [constructor](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma. +Now one can define constructors and virtual procs that maps to C++ constructors and virtual methods, allowing one to further customize +the interoperability. There is also extended support for the [codeGenDecl](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-codegendecl-pragma) pragma, so that it works on types. It's a common pattern in C++ to use inheritance to extend a library. Some even use multiple inheritance as a mechanism to make interfaces. @@ -181,6 +181,7 @@ struct Base { someValue = inValue; }; }; + class IPrinter { public: virtual void print() = 0; @@ -200,11 +201,11 @@ const objTemplate = """ }; """; -type NimChild {.codegenDecl:objTemplate .} = object of Base +type NimChild {.codegenDecl: objTemplate .} = object of Base -proc makeNimChild(val: int32): NimChild {.constructor:"NimClass('1 #1) : Base(#1)".} = +proc makeNimChild(val: int32): NimChild {.constructor: "NimClass('1 #1) : Base(#1)".} = echo "It calls the base constructor passing " & $this.someValue - this.someValue = val * 2 #notice how we can access to this inside the constructor. it's of the type ptr NimChild + this.someValue = val * 2 # Notice how we can access `this` inside the constructor. It's of the type `ptr NimChild`. proc print*(self: NimChild) {.virtual.} = echo "Some value is " & $self.someValue @@ -223,7 +224,7 @@ Some value is 20 ## ARC/ORC refinements -With the release 2.0 the ARC/ORC model got refined once again and is now finally complete: +With the 2.0 release, the ARC/ORC model got refined once again and is now finally complete: 1. Programmers now have control over the "item was moved from" state as `=wasMoved` is overridable. 2. There is a new `=dup` hook which is more efficient than the old combination of `=wasMoved(tmp); =copy(tmp, x)` operations. @@ -238,13 +239,13 @@ providing a stable ABI it is important not to lose any efficiency in the calling ## Tool changes -- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop. +- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop. - nimgrep now offers the option `--inContext` (and `--notInContext`), which - allows to filter only matches with context block containing a given pattern. + allows to filter only matches with the context block containing a given pattern. - nimgrep: names of options containing "include/exclude" are deprecated, e.g. instead of `--includeFile` and `--excludeFile` we have `--filename` and `--notFilename` respectively. - Also the semantics become consistent for such positive/negative filters. + Also, the semantics are now consistent for such positive/negative filters. - Nim now ships with an alternative package manager called Atlas. More on this in upcoming versions. @@ -278,7 +279,7 @@ block maybePerformB: ### Strict funcs -The definition of "strictFuncs" was changed. +The definition of `"strictFuncs"` was changed. The old definition was roughly: "A store to a ref/ptr deref is forbidden unless it's coming from a `var T` parameter". The new definition is: "A store to a ref/ptr deref is forbidden." @@ -312,11 +313,9 @@ func create(s: string): Node = ``` - - ### Standard library -Several Standard libraries have been moved to nimble packages, use `nimble` or `atlas` to install them: +Several standard library modules have been moved to nimble packages, use `nimble` or `atlas` to install them: - `std/punycode` => `punycode` - `std/asyncftpclient` => `asyncftpclient` @@ -328,4 +327,4 @@ Several Standard libraries have been moved to nimble packages, use `nimble` or ` - `std/db_odbc` => `db_connector/db_odbc` - `std/md5` => `checksums/md5` - `std/sha1` => `checksums/sha1` - +- `std/sums` => `sums` diff --git a/changelogs/changelog_2_0_0_details.md b/changelogs/changelog_2_0_0_details.md index 0cdf3d326b..8f9e7afd0b 100644 --- a/changelogs/changelog_2_0_0_details.md +++ b/changelogs/changelog_2_0_0_details.md @@ -2,7 +2,13 @@ ## Changes affecting backward compatibility -- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response. It follows Apache's HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behaviors. Previously it raised `ValueError`. + +- ORC is now the default memory management strategy. Use + `--mm:refc` for a transition period. + +- The `threads:on` option is now the default. + +- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response. It follows Apache's `HttpClient` (Java), `http` (go) and .NET `HttpWebResponse` (C#) behaviors. Previously it raised a `ValueError`. - `addr` is now available for all addressable locations, `unsafeAddr` is now deprecated and an alias for `addr`. @@ -25,7 +31,7 @@ - Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated symbols in the `system` module: - - Aliases with `Error` suffix to exception types that have a `Defect` suffix + - Aliases with an `Error` suffix to exception types that have a `Defect` suffix (see [exceptions](https://nim-lang.github.io/Nim/exceptions.html)): `ArithmeticError`, `DivByZeroError`, `OverflowError`, `AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`, @@ -40,21 +46,19 @@ `ptr int32`, `ptr int64`, `ptr float32`, `ptr float64` - Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in - in the `system` module, which is replaced by [threading/channels](https://github.com/nim-lang/threading/blob/master/threading/channels.nim). Use the command "nimble install threading" and import `threading/channels`. + in the `system` module, which is replaced by [threading/channels](https://github.com/nim-lang/threading/blob/master/threading/channels.nim). Use the command `nimble install threading` and import `threading/channels`. -- Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore. +- Enabling `-d:nimPreviewCstringConversion` causes `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` to not support conversion to `cstring` anymore. -- Enabling `-d:nimPreviewProcConversion`, `proc` does not support conversion to - `pointer`. `cast` may be used instead. +- Enabling `-d:nimPreviewProcConversion` causes `proc` to not support conversion to + `pointer` anymore. `cast` may be used instead. - The `gc:v2` option is removed. - The `mainmodule` and `m` options are removed. -- The `threads:on` option is now the default. - -- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via - `experimental:flexibleOptionalParams`. +- Optional parameters in combination with `: body` syntax ([RFC #405](https://github.com/nim-lang/RFCs/issues/405)) + are now opt-in via `experimental:flexibleOptionalParams`. - Automatic dereferencing (experimental feature) is removed. @@ -81,7 +85,8 @@ var x: Foo = Foo(nil) ``` - Removed two type pragma syntaxes deprecated since 0.20, namely - `type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`. + `type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`. Instead, + use `type Foo[T] {.final.} = object`. - `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`. @@ -96,16 +101,13 @@ - Lock levels are deprecated, now a noop. -- ORC is now the default memory management strategy. Use - `--mm:refc` for a transition period. - - `strictEffects` are no longer experimental. Use `legacy:laxEffects` to keep backward compatibility. - The `gorge`/`staticExec` calls will now return a descriptive message in the output - if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`. + if the execution fails for whatever reason. To get back legacy behaviour, use `-d:nimLegacyGorgeErrors`. -- Pointer to `cstring` conversion now triggers a `[PtrToCstringConv]` warning. +- Pointer to `cstring` conversions now trigger a `[PtrToCstringConv]` warning. This warning will become an error in future versions! Use a `cast` operation like `cast[cstring](x)` instead. @@ -129,14 +131,21 @@ - `std/db_odbc` => `db_connector/db_odbc` - `std/md5` => `checksums/md5` - `std/sha1` => `checksums/sha1` + - `std/sums` => `std/sums` - Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of `foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`. This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead. -- When `--warning[BareExcept]:on` is enabled, if no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered. +- When `--warning[BareExcept]:on` is enabled, if an `except` specifies no exception or any exception not inheriting from `Defect` or `CatchableError`, a `warnBareExcept` warning will be triggered. For example, the following code will emit a warning: + ```nim + try: + discard + except: # Warning: The bare except clause is deprecated; use `except CatchableError:` instead [BareExcept] + discard + ``` -- The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection. +- The experimental `strictFuncs` feature now disallows a store to the heap via a `ref` or `ptr` indirection. - The underscore identifier (`_`) is now generally not added to scope when used as the name of a definition. While this was already the case for @@ -212,7 +221,7 @@ - The `proc` and `iterator` type classes now accept a calling convention pragma (i.e. `proc {.closure.}`) that must be shared by matching proc or iterator - types. Previously pragmas were parsed but discarded if no parameter list + types. Previously, pragmas were parsed but discarded if no parameter list was given. This is represented in the AST by an `nnkProcTy`/`nnkIteratorTy` node with @@ -225,14 +234,14 @@ - Signed integer literals in `set` literals now default to a range type of `0..255` instead of `0..65535` (the maximum size of sets). -- Case statements with else branches put before elif/of branches in macros +- `case` statements with `else` branches put before `elif`/`of` branches in macros are rejected with "invalid order of case branches". - Destructors now default to `.raises: []` (i.e. destructors must not raise unlisted exceptions) and explicitly raising destructors are implementation defined behavior. -- The very old, undocumented deprecated pragma statement syntax for +- The very old, undocumented `deprecated` pragma statement syntax for deprecated aliases is now a no-op. The regular deprecated pragma syntax is generally sufficient instead. @@ -254,7 +263,7 @@ declared when they are not available on the backend. Previously it would call `doAssert false` at runtime despite the condition being checkable at compile-time. -- Custom destructors now supports non-var parameters, e.g. `proc =destroy[T: object](x: T)` is valid. `proc =destroy[T: object](x: var T)` is deprecated. +- Custom destructors now supports non-var parameters, e.g. ``proc `=destroy`[T: object](x: T)`` is valid. ``proc `=destroy`[T: object](x: var T)`` is deprecated. - Relative imports will not resolve to searched paths anymore, e.g. `import ./tables` now reports an error properly. @@ -263,19 +272,19 @@ [//]: # "Changes:" - OpenSSL 3 is now supported. - `macros.parseExpr` and `macros.parseStmt` now accept an optional - filename argument for more informative errors. -- Module `colors` expanded with missing colors from the CSS color standard. + `filename` argument for more informative errors. +- The `colors` module is expanded with missing colors from the CSS color standard. `colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard. - Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)). - The `md5` module now works at compile time and in JavaScript. -- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef` to support `const` tables. +- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef`, to support `const` tables. - `strutils.find` now uses and defaults to `last = -1` for whole string searches, making limiting it to just the first char (`last = 0`) valid. -- `strutils.split` and `strutils.rsplit` now return a source string as a single element for an empty separator. +- `strutils.split` and `strutils.rsplit` now return the source string as a single element for an empty separator. - `random.rand` now works with `Ordinal`s. - Undeprecated `os.isvalidfilename`. -- `std/oids` now uses `int64` to store time internally (before it was int32). -- `std/uri.Uri` dollar `$` improved, precalculates the `string` result length from the `Uri`. +- `std/oids` now uses `int64` to store time internally (before, it was int32). +- `std/uri.Uri` dollar (`$`) improved, precalculates the `string` result length from the `Uri`. - `std/uri.Uri.isIpv6` is now exported. - `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2. @@ -283,9 +292,9 @@ - `std/jsfetch.newFetchOptions` now has default values for all parameters. - `std/jsformdata` now accepts the `Blob` data type. -- `std/sharedlist` and `std/sharedtables` are now deprecated, see RFC [#433](https://github.com/nim-lang/RFCs/issues/433). +- `std/sharedlist` and `std/sharedtables` are now deprecated, see [RFC #433](https://github.com/nim-lang/RFCs/issues/433). -- There is a new compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on Linux `getrandom` syscall. +- There is a new compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove the dependency on the Linux `getrandom` syscall. This compile flag only affects Linux builds and is necessary if either compiling on a Linux kernel version < 3.17, or if code built will be executing on kernel < 3.17. @@ -301,19 +310,20 @@ $ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall ``` - This is necessary to pass when building Nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for the stdlib (sysrand in particular). + This is necessary to pass when building Nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for the stdlib (`sysrand` in particular). [//]: # "Additions:" - Added ISO 8601 week date utilities in `times`: - Added `IsoWeekRange`, a range type for weeks in a week-based year. - Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year. - - Added a `initDateTime` overload to create a datetime from an ISO week date. + - Added an `initDateTime` overload to create a `DateTime` from an ISO week date. - Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime. - Added `getIsoWeeksInYear` to return the number of weeks in a week-based year. -- Added new modules which were part of `std/os`: - - Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling. - - Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`. +- Added new modules which were previously part of `std/os`: + - Added `std/oserrors` for OS error reporting. + - Added `std/envvars` for environment variables handling. - Added `std/cmdline` for reading command line parameters. + - Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`. - Added `sep` parameter in `std/uri` to specify the query separator. - Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`. - Added `complex.sgn` for obtaining the phase of complex numbers. @@ -322,14 +332,13 @@ `hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`, `replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`, `toggleAttribute`, and `matches` to `std/dom`. -- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices) -- Added `capacity` for `string` and `seq` to return the current capacity, see https://github.com/nim-lang/RFCs/issues/460 -- Added `openArray[char]` overloads for `std/parseutils` allowing for more code reuse. -- Added `openArray[char]` overloads for `std/unicode` allowing for more code reuse. -- Added `safe` parameter to `base64.encodeMime`. +- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices). +- Added `capacity` for `string` and `seq` to return the current capacity, see [RFC #460](https://github.com/nim-lang/RFCs/issues/460). +- Added `openArray[char]` overloads for `std/parseutils` and `std/unicode`, allowing for more code reuse. +- Added a `safe` parameter to `base64.encodeMime`. - Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes. - Added `minmax` to `sequtils`, as a more efficient `(min(_), max(_))` over sequences. -- `std/jscore` for JavaScript targets: +- `std/jscore` for the JavaScript target: + Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask). + Added `toDateString`, `toISOString`, `toJSON`, `toTimeString`, `toUTCString` converters for `DateTime`. @@ -339,7 +348,6 @@ [//]: # "Deprecations:" - Deprecated `selfExe` for Nimscript. -- Deprecated `std/sums`. - Deprecated `std/base64.encode` for collections of arbitrary integer element type. Now only `byte` and `char` are supported. @@ -354,7 +362,7 @@ - Removed deprecated `jsre.test` and `jsre.toString`. - Removed deprecated `math.c_frexp`. - Removed deprecated `` httpcore.`==` ``. -- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types. +- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that take wrong argument types. - Removed deprecated `osproc.poDemon`, symbol with typo. - Removed deprecated `tables.rightSize`. @@ -364,7 +372,7 @@ ## Language changes -- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) supports the definition of forbidden tags by the `.forbids` pragma +- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) now supports the definition of forbidden tags by the `.forbids` pragma which can be used to disable certain effects in proc types. - [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental, meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them. @@ -375,7 +383,7 @@ - Compile-time define changes: - `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`. In the command line, this is defined as `-d:a.b.c`. Older versions can - use accents as in ``defined(`a.b.c`)`` to access such defines. + use backticks as in ``defined(`a.b.c`)`` to access such defines. - [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas) now support a string argument for qualified define names. @@ -408,11 +416,13 @@ ```nim import macros + macro multiply(amount: static int, s: untyped): untyped = let name = $s[0].basename result = newNimNode(nnkTypeSection) for i in 1 .. amount: result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2])) + type Foo = object Bar {.multiply: 3.} = object @@ -446,7 +456,7 @@ - IBM Z architecture and macOS m1 arm64 architecture are supported. -- `=wasMoved` can be overridden by users. +- `=wasMoved` can now be overridden by users. - Tuple unpacking for variables is now treated as syntax sugar that directly expands into multiple assignments. Along with this, tuple unpacking for @@ -488,43 +498,44 @@ related functions produced on the backend. This prevents conflicts with other Nim static libraries. -- When compiling for Release the flag `-fno-math-errno` is used for GCC. +- When compiling for release, the flag `-fno-math-errno` is used for GCC. - Removed deprecated `LineTooLong` hint. -- Line numbers and filenames of source files work correctly inside templates for JavaScript targets. +- Line numbers and file names of source files work correctly inside templates for JavaScript targets. -- Removed support for LCC (Local C), Pelles C, Digital Mars, Watcom compilers. +- Removed support for LCC (Local C), Pelles C, Digital Mars and Watcom compilers. ## Docgen -- `Markdown` is now default markup language of doc comments (instead - of legacy `RstMarkdown` mode). In this release we begin to separate +- `Markdown` is now the default markup language of doc comments (instead + of the legacy `RstMarkdown` mode). In this release we begin to separate RST and Markdown features to better follow specification of each language, with the focus on Markdown development. + See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html). - * So we add `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to - select the markup language mode in the doc comments of current `.nim` + * Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to + select the markup language mode in the doc comments of the current `.nim` file for processing by `nim doc`: 1. `Markdown` (default) is basically CommonMark (standard Markdown) + some Pandoc Markdown features + some RST features that are missing in our current implementation of CommonMark and Pandoc Markdown. - 2. `RST` closely follows RST spec with few additional Nim features. + 2. `RST` closely follows the RST spec with few additional Nim features. 3. `RstMarkdown` is a maximum mix of RST and Markdown features, which is kept for the sake of compatibility and ease of migration. - * and we add separate `md2html` and `rst2html` commands for processing - standalone `.md` and `.rst` files respectively (and also `md2tex/rst2tex`). + * Added separate `md2html` and `rst2html` commands for processing + standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`). - Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links. - Docgen now supports concise syntax for referencing Nim symbols: instead of specifying HTML anchors directly one can use original Nim symbol declarations (adding the aforementioned link brackets `[...]` around them). - * to use this feature across modules a new `importdoc` directive is added. - Using this feature for referencing also helps to ensure that links - (inside one module or the whole project) are not broken. -- Added support for RST & Markdown quote blocks (blocks starting from `>`). + * To use this feature across modules, a new `importdoc` directive was added. + Using this feature for referencing also helps to ensure that links + (inside one module or the whole project) are not broken. +- Added support for RST & Markdown quote blocks (blocks starting with `>`). - Added a popular Markdown definition lists extension. - Added Markdown indented code blocks (blocks indented by >= 4 spaces). - Added syntax for additional parameters to Markdown code blocks: @@ -535,11 +546,11 @@ ## Tool changes -- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop. +- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop. - nimgrep added the option `--inContext` (and `--notInContext`), which - allows to filter only matches with context block containing a given pattern. + allows to filter only matches with the context block containing a given pattern. - nimgrep: names of options containing "include/exclude" are deprecated, e.g. instead of `--includeFile` and `--excludeFile` we have `--filename` and `--notFilename` respectively. - Also the semantics become consistent for such positive/negative filters. + Also the semantics are now consistent for such positive/negative filters. - koch now supports the `--skipIntegrityCheck` option. The command `koch --skipIntegrityCheck boot -d:release` always builds the compiler twice. From 62869a5c68e4dd91e00ee77b039f0175482ef4fa Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Sat, 22 Jul 2023 21:13:55 +0200 Subject: [PATCH 342/489] Check try block for endsInNoReturn (#22314) Co-authored-by: SirOlaf <> --- compiler/semstmts.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 836be6e4a9..5c1a363b4d 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -235,8 +235,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil) var typ = commonTypeBegin var expectedType = expectedType n[0] = semExprBranchScope(c, n[0], expectedType) - typ = commonType(c, typ, n[0].typ) if not endsInNoReturn(n[0]): + typ = commonType(c, typ, n[0].typ) expectedType = typ var last = n.len - 1 @@ -312,7 +312,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil) result.typ = c.enforceVoidContext else: if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags) - n[0] = fitNode(c, typ, n[0], n[0].info) + if not endsInNoReturn(n[0]): + n[0] = fitNode(c, typ, n[0], n[0].info) for i in 1..last: var it = n[i] let j = it.len-1 From be1844541c87a132ca076d8a8f741bec01825ba1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 23 Jul 2023 13:39:58 +0200 Subject: [PATCH 343/489] =?UTF-8?q?implemented=20'push=20quirky'=20switch?= =?UTF-8?q?=20for=20fine=20grained=20control=20over=20the=20ex=E2=80=A6=20?= =?UTF-8?q?(#22318)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * implemented 'push quirky' switch for fine grained control over the exception handling overhead * documentation --- changelogs/changelog_2_0_0_details.md | 3 + compiler/ccgstmts.nim | 7 ++- compiler/cgen.nim | 10 ++-- compiler/cgendata.nim | 18 +++--- compiler/condsyms.nim | 1 + compiler/options.nim | 1 + compiler/pragmas.nim | 7 ++- compiler/wordrecg.nim | 1 + doc/manual_experimental.md | 81 +++++++++++++++++++++++---- doc/nimc.md | 4 ++ 10 files changed, 102 insertions(+), 31 deletions(-) diff --git a/changelogs/changelog_2_0_0_details.md b/changelogs/changelog_2_0_0_details.md index 8f9e7afd0b..e3895639ad 100644 --- a/changelogs/changelog_2_0_0_details.md +++ b/changelogs/changelog_2_0_0_details.md @@ -458,6 +458,9 @@ - `=wasMoved` can now be overridden by users. +- There is a new pragma called [quirky](https://nim-lang.github.io/Nim/manual_experimental.html#quirky-routines) that can be used to affect the code + generation of goto based exception handling. It can improve the produced code size but its effects can be subtle so use it with care. + - Tuple unpacking for variables is now treated as syntax sugar that directly expands into multiple assignments. Along with this, tuple unpacking for variables can now be nested. diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index f536a82c13..3197389814 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -315,7 +315,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = var targetProc = p var valueAsRope = "" potentialValueInit(p, v, value, valueAsRope) - if sfGlobal in v.flags: + if sfGlobal in v.flags: if v.flags * {sfImportc, sfExportc} == {sfImportc} and value.kind == nkEmpty and v.loc.flags * {lfHeader, lfNoDecl} != {}: @@ -1050,7 +1050,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = expr(p, t[0], d) endBlock(p) - # First pass: handle Nim based exceptions: + # First pass: handle Nim based exceptions: lineCg(p, cpsStmts, "catch (#Exception* T$1_) {$n", [etmp+1]) genRestoreFrameAfterException(p) # an unhandled exception happened! @@ -1308,7 +1308,8 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" if optTinyRtti in p.config.globalOptions: let checkFor = $getObjDepth(t[i][j].typ) - appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))]) + appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", + [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))]) else: let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info) appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 0450625fcd..ed149ed0e5 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -619,7 +619,7 @@ proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool = # and s.owner.kind == skModule # owner isn't always a module (global pragma on local var) # and s.loc.k == locGlobalVar # loc isn't always initialized when this proc is used -proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) = +proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) = let s = n.sym if s.constraint.isNil: if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: @@ -640,7 +640,7 @@ proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) = else: decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r]) -proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) +proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) = let s = vn.sym @@ -701,7 +701,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = decl.addf(" $1 = $2;$n", [s.loc.r, value]) else: decl.addf(" $1;$n", [s.loc.r]) - + p.module.s[cfsVars].add(decl) if p.withinLoop > 0 and value == "": # fixes tests/run/tzeroarray: @@ -1134,7 +1134,7 @@ proc getProcTypeCast(m: BModule, prc: PSym): Rope = proc genProcBody(p: BProc; procBody: PNode) = genStmts(p, procBody) # modifies p.locals, p.init, etc. - if {nimErrorFlagAccessed, nimErrorFlagDeclared} * p.flags == {nimErrorFlagAccessed}: + if {nimErrorFlagAccessed, nimErrorFlagDeclared, nimErrorFlagDisabled} * p.flags == {nimErrorFlagAccessed}: p.flags.incl nimErrorFlagDeclared p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", [])) p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", [])) @@ -1178,7 +1178,7 @@ proc genProcAux*(m: BModule, prc: PSym) = initLocalVar(p, res, immediateAsgn=false) returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)]) elif sfConstructor in prc.flags: - fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap) + fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap) else: fillResult(p.config, resNode, prc.typ) assignParam(p, res, prc.typ[0]) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index e1309e0fdd..4d15cf131b 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -193,15 +193,15 @@ proc initBlock*(): TBlock = result.sections[i] = newRopeAppender() proc newProc*(prc: PSym, module: BModule): BProc = - new(result) - result.prc = prc - result.module = module - result.options = if prc != nil: prc.options - else: module.config.options - result.blocks = @[initBlock()] - result.nestedTryStmts = @[] - result.finallySafePoints = @[] - result.sigConflicts = initCountTable[string]() + result = BProc( + prc: prc, + module: module, + options: if prc != nil: prc.options + else: module.config.options, + blocks: @[initBlock()], + sigConflicts: initCountTable[string]()) + if optQuirky in result.options: + result.flags = {nimErrorFlagDisabled} proc newModuleList*(g: ModuleGraph): BModuleList = BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](), diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 12634248c3..c680504494 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -156,3 +156,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasChecksums") defineSymbol("nimHasSendable") defineSymbol("nimAllowNonVarDestructor") + defineSymbol("nimHasQuirky") diff --git a/compiler/options.nim b/compiler/options.nim index d3cf71d4f6..8286a575df 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -49,6 +49,7 @@ type # please make sure we have under 32 options optSinkInference # 'sink T' inference optCursorInference optImportHidden + optQuirky TOptions* = set[TOption] TGlobalOption* = enum diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 9e4a0052dd..0d95f596c5 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -34,7 +34,7 @@ const wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl, wGensym, wInject, wRaises, wEffectsOf, wTags, wForbids, wLocks, wDelegator, wGcSafe, wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy, - wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect, wVirtual} + wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect, wVirtual, wQuirky} converterPragmas* = procPragmas methodPragmas* = procPragmas+{wBase}-{wImportCpp} templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty, @@ -405,6 +405,7 @@ proc pragmaToOptions*(w: TSpecialWord): TOptions {.inline.} = of wImplicitStatic: {optImplicitStatic} of wPatterns, wTrMacros: {optTrMacros} of wSinkInference: {optSinkInference} + of wQuirky: {optQuirky} else: {} proc processExperimental(c: PContext; n: PNode) = @@ -1273,12 +1274,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, pragmaProposition(c, it) of wEnsures: pragmaEnsures(c, it) - of wEnforceNoRaises: + of wEnforceNoRaises, wQuirky: sym.flags.incl sfNeverRaises of wSystemRaisesDefect: sym.flags.incl sfSystemRaisesDefect of wVirtual: - processVirtual(c, it, sym) + processVirtual(c, it, sym) else: invalidPragma(c, it) elif comesFromPush and whichKeyword(ident) != wInvalid: diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 21b0970753..f784f0a754 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -89,6 +89,7 @@ type wGuard = "guard", wLocks = "locks", wPartial = "partial", wExplain = "explain", wLiftLocals = "liftlocals", wEnforceNoRaises = "enforceNoRaises", wSystemRaisesDefect = "systemRaisesDefect", wRedefine = "redefine", wCallsite = "callsite", + wQuirky = "quirky", wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char", wClass = "class", wCompl = "compl", wConstCast = "const_cast", wDefault = "default", diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 54354f92b9..602ca46a58 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -2009,6 +2009,65 @@ The field is within a `case` section of an `object`. is solid and it is expected that eventually this mode becomes the default in later versions. +Quirky routines +=============== + +The default code generation strategy of exceptions under the ARC/ORC model is the so called +`--exceptions:goto` implementation. This implementation inserts a check after every call that +can potentially raise an exception. A typical instruction sequence for this on +for a x86 64 bit machine looks like: + + ``` + cmp DWORD PTR [rbx], 0 + je .L1 + ``` + +This is a memory fetch followed by jump. (An ideal implementation would +use the carry flag and a single instruction like ``jc .L1``.) + +This overhead might not be desired and depending on the sematics of the routine may not be required +either. +So it can be disabled via a `.quirky` annotation: + + ```nim + proc wontRaise(x: int) {.quirky.} = + if x != 0: + # because of `quirky` this will continue even if `write` raised an IO exception: + write x + wontRaise(x-1) + + wontRaise 10 + + ``` + +If the used exception model is not `--exceptions:goto` then the `quirky` pragma has no effect and is +ignored. + +The `quirky` pragma can also be be pushed in order to affect a group of routines and whether +the compiler supports the pragma can be checked with `defined(nimHasQuirky)`: + + ```nim + when defined(nimHasQuirky): + {.push quirky: on.} + + proc doRaise() = raise newException(ValueError, "") + + proc f(): string = "abc" + + proc q(cond: bool) = + if cond: + doRaise() + echo f() + + q(true) + + when defined(nimHasQuirky): + {.pop.} + ``` + +**Warning**: The `quirky` pragma only affects code generation, no check for validity is performed! + + Threading under ARC/ORC ======================= @@ -2141,13 +2200,13 @@ Here's an example of how to use the virtual pragma: ```nim proc newCpp*[T](): ptr T {.importcpp: "new '*0()".} -type +type Foo = object of RootObj FooPtr = ptr Foo Boo = object of Foo BooPtr = ptr Boo -proc salute(self: FooPtr) {.virtual.} = +proc salute(self: FooPtr) {.virtual.} = echo "hello foo" proc salute(self: BooPtr) {.virtual.} = @@ -2177,13 +2236,13 @@ The return type can be referred to as `-> '0`, but this is optional and often no #include class CppPrinter { public: - + virtual void printConst(char* message) const { std::cout << "Const Message: " << message << std::endl; } virtual void printConstRef(char* message, const int& flag) const { std::cout << "Const Ref Message: " << message << std::endl; - } + } }; """.} @@ -2194,7 +2253,7 @@ type proc printConst(self: CppPrinter; message:cstring) {.importcpp.} CppPrinter().printConst(message) -# override is optional. +# override is optional. proc printConst(self: NimPrinter; message: cstring) {.virtual: "$1('2 #2) const override".} = echo "NimPrinter: " & $message @@ -2224,10 +2283,10 @@ proc makeFoo(x: int32): Foo {.constructor.} = ``` -It forward declares the constructor in the type definition. When the constructor has parameters, it also generates a default constructor. +It forward declares the constructor in the type definition. When the constructor has parameters, it also generates a default constructor. Notice, inside the body of the constructor one has access to `this` which is of the type `ptr Foo`. No `result` variable is available. -Like `virtual`, `constructor` also supports a syntax that allows to express C++ constraints. +Like `virtual`, `constructor` also supports a syntax that allows to express C++ constraints. For example: @@ -2242,11 +2301,11 @@ struct CppClass { this->x = inX; this->y = inY; } - //CppClass() = default; + //CppClass() = default; }; """.} -type +type CppClass* {.importcpp, inheritable.} = object x: int32 y: int32 @@ -2256,11 +2315,11 @@ proc makeNimClass(x: int32): NimClass {.constructor:"NimClass('1 #1) : CppClass( this.x = x # Optional: define the default constructor explicitly -proc makeCppClass(): NimClass {.constructor: "NimClass() : CppClass(0, 0)".} = +proc makeCppClass(): NimClass {.constructor: "NimClass() : CppClass(0, 0)".} = this.x = 1 ``` -In the example above `CppClass` has a deleted default constructor. Notice how by using the constructor syntax, one can call the appropiate constructor. +In the example above `CppClass` has a deleted default constructor. Notice how by using the constructor syntax, one can call the appropiate constructor. Notice when calling a constructor in the section of a global variable initialization, it will be called before `NimMain` meaning Nim is not fully initialized. diff --git a/doc/nimc.md b/doc/nimc.md index 7c42c7c1b7..9c6ea70330 100644 --- a/doc/nimc.md +++ b/doc/nimc.md @@ -481,9 +481,13 @@ They are: 5. nl_types. No headers for this. 6. As mmap is not supported, the nimAllocPagesViaMalloc option has to be used. + DLL generation ============== +**Note**: The same rules apply to `lib*.so` shared object files on UNIX. For better +readability only the DLL version is decribed here. + Nim supports the generation of DLLs. However, there must be only one instance of the GC per process/address space. This instance is contained in ``nimrtl.dll``. This means that every generated Nim DLL depends From 808c9c6c2a93e6076c17b6f9bbab367df4c27772 Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Sun, 23 Jul 2023 15:35:30 +0200 Subject: [PATCH 344/489] Testcase for #22008 (#22320) Testcase Co-authored-by: SirOlaf <> --- tests/exception/t22008.nim | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/exception/t22008.nim diff --git a/tests/exception/t22008.nim b/tests/exception/t22008.nim new file mode 100644 index 0000000000..c0758e7b45 --- /dev/null +++ b/tests/exception/t22008.nim @@ -0,0 +1,8 @@ +template detect(v: untyped) = + doAssert typeof(v) is int + +detect: + try: + raise (ref ValueError)() + except ValueError: + 42 \ No newline at end of file From 49a108b3027914eec18fab4bc47d9b4846eb362e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Sun, 23 Jul 2023 15:42:20 +0100 Subject: [PATCH 345/489] Expands codegenDecl to work in function params. fixes #22306 (#22307) * Expands codegenDecl to work in function params. fixes #22306 * makes the test more concrete so T{lit} params dont match * adds sfCodegenDecl --- compiler/ast.nim | 1 + compiler/ccgtypes.nim | 34 +++++++++++++++++++++------------- compiler/cgen.nim | 4 ++-- compiler/pragmas.nim | 3 ++- compiler/semtypes.nim | 4 +++- compiler/sigmatch.nim | 2 +- tests/cpp/tcodegendecl.nim | 17 +++++++++++++++++ 7 files changed, 47 insertions(+), 18 deletions(-) create mode 100644 tests/cpp/tcodegendecl.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 0be2603914..706c0d38fb 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -314,6 +314,7 @@ type # an infinite loop, this flag is used as a sentinel to stop it. sfVirtual # proc is a C++ virtual function sfByCopy # param is marked as pass bycopy + sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl TSymFlags* = set[TSymFlag] diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 307d1f2e0e..e4a0fe84bc 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -483,6 +483,9 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr res.add(substr(frmt, start, i - 1)) frmt = res +template cgDeclFrmt*(s: PSym): string = + s.constraint.strVal + proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var string, check: var IntSet, declareEnvironment=true; weakDep=false;) = @@ -535,7 +538,10 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var name = param.loc.r types.add typ names.add name - args.add types[^1] & " " & names[^1] + if sfCodegenDecl notin param.flags: + args.add types[^1] & " " & names[^1] + else: + args.add runtimeFormat(param.cgDeclFrmt, [types[^1], names[^1]]) multiFormat(params, @['\'', '#'], [types, names]) multiFormat(superCall, @['\'', '#'], [types, names]) @@ -570,19 +576,24 @@ proc genProcParams(m: BModule; t: PType, rettype, params: var Rope, fillParamName(m, param) fillLoc(param.loc, locParam, t.n[i], param.paramStorageLoc) + var typ: Rope if ccgIntroducedPtr(m.config, param, t[0]) and descKind == dkParam: - params.add(getTypeDescWeak(m, param.typ, check, descKind)) - params.add("*") + typ = (getTypeDescWeak(m, param.typ, check, descKind)) + typ.add("*") incl(param.loc.flags, lfIndirect) param.loc.storage = OnUnknown elif weakDep: - params.add(getTypeDescWeak(m, param.typ, check, descKind)) + typ = (getTypeDescWeak(m, param.typ, check, descKind)) else: - params.add(getTypeDescAux(m, param.typ, check, descKind)) - params.add(" ") + typ = (getTypeDescAux(m, param.typ, check, descKind)) + typ.add(" ") if sfNoalias in param.flags: - params.add("NIM_NOALIAS ") - params.add(param.loc.r) + typ.add("NIM_NOALIAS ") + if sfCodegenDecl notin param.flags: + params.add(typ) + params.add(param.loc.r) + else: + params.add runtimeFormat(param.cgDeclFrmt, [typ, param.loc.r]) # declare the len field for open arrays: var arr = param.typ.skipTypes({tyGenericInst}) if arr.kind in {tyVar, tyLent, tySink}: arr = arr.lastSon @@ -721,9 +732,6 @@ proc fillObjectFields*(m: BModule; typ: PType) = discard getRecordFields(m, typ, check) proc mangleDynLibProc(sym: PSym): Rope - -template cgDeclFrmt*(s: PSym): string = - s.constraint.strVal proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope, check: var IntSet, hasField:var bool): Rope = @@ -770,7 +778,7 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope, var baseType: string if typ[0] != nil: baseType = getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, dkField) - if typ.sym == nil or typ.sym.constraint == nil: + if typ.sym == nil or sfCodegenDecl notin typ.sym.flags: result = structOrUnion & " " & name result.add(getRecordDescAux(m, typ, name, baseType, check, hasField)) let desc = getRecordFields(m, typ, check) @@ -1198,7 +1206,7 @@ proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false) name.add("_actual") # careful here! don't access ``prc.ast`` as that could reload large parts of # the object graph! - if prc.constraint.isNil: + if sfCodegenDecl notin prc.flags: if lfExportLib in prc.loc.flags: if isHeaderFile in m.flags: result.add "N_LIB_IMPORT " diff --git a/compiler/cgen.nim b/compiler/cgen.nim index ed149ed0e5..0242ae2f70 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -590,7 +590,7 @@ proc localVarDecl(p: BProc; n: PNode): Rope = genCLineDir(result, p, n.info, p.config) result.add getTypeDesc(p.module, s.typ, dkVar) - if s.constraint.isNil: + if sfCodegenDecl notin s.flags: if sfRegister in s.flags: result.add(" register") #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: # decl.add(" GC_GUARD") @@ -621,7 +621,7 @@ proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool = proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) = let s = n.sym - if s.constraint.isNil: + if sfCodegenDecl notin s.flags: if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0: decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)] if p.hcrOn: decl.add("static ") diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 0d95f596c5..258836ca38 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -84,7 +84,7 @@ const wGensym, wInject, wIntDefine, wStrDefine, wBoolDefine, wDefine, wCompilerProc, wCore} - paramPragmas* = {wNoalias, wInject, wGensym, wByRef, wByCopy} + paramPragmas* = {wNoalias, wInject, wGensym, wByRef, wByCopy, wCodegenDecl} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect, wThread, wRaises, wEffectsOf, wLocks, wTags, wForbids, wGcSafe, @@ -253,6 +253,7 @@ proc processVirtual(c: PContext, n: PNode, s: PSym) = proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) = sym.constraint = getStrLitNode(c, n) + sym.flags.incl sfCodegenDecl proc processMagic(c: PContext, n: PNode, s: PSym) = #if sfSystemModule notin c.module.flags: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index aa5f0a79b4..60550de570 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1356,7 +1356,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, let finalType = if lifted != nil: lifted else: typ.skipIntLit(c.idgen) arg.typ = finalType arg.position = counter - arg.constraint = constraint + if constraint != nil: + #only replace the constraint when it has been set as arg could contain codegenDecl + arg.constraint = constraint inc(counter) if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index e90f1524b6..4aa51977ab 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -2432,7 +2432,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int return template checkConstraint(n: untyped) {.dirty.} = - if not formal.constraint.isNil: + if not formal.constraint.isNil and sfCodegenDecl notin formal.flags: if matchNodeKinds(formal.constraint, n): # better match over other routines with no such restriction: inc(m.genericMatches, 100) diff --git a/tests/cpp/tcodegendecl.nim b/tests/cpp/tcodegendecl.nim new file mode 100644 index 0000000000..e128c5eb7d --- /dev/null +++ b/tests/cpp/tcodegendecl.nim @@ -0,0 +1,17 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" + output: "3" +""" + +{.emit:"""/*TYPESECTION*/ + int operate(int x, int y, int (*func)(const int&, const int&)){ + return func(x, y); + }; +""".} + +proc operate(x, y: int32, fn: proc(x, y: int32 ): int32 {.cdecl.}): int32 {.importcpp:"$1(@)".} + +proc add(a {.codegenDecl:"const $#& $#".}, b {.codegenDecl:"const $# $#", byref.}: int32): int32 {.cdecl.} = a + b + +echo operate(1, 2, add) \ No newline at end of file From 8216d7dd4635db3c0566155c35bb6f339daedbe3 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 24 Jul 2023 23:22:50 +0800 Subject: [PATCH 346/489] fixes #22321; fixes building DLL with --noMain still produces a DllMain (#22323) * fixes #22321; Building DLL with --noMain produces an unexpected DllMain on devel branch * remove implicit nomain --- compiler/cgen.nim | 2 +- compiler/commands.nim | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 0242ae2f70..363bbce42e 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1636,7 +1636,7 @@ proc genMainProc(m: BModule) = appcg(m, m.s[cfsProcs], nimMain, [m.g.mainModInit, initStackBottomCall, m.labels, preMainCode, m.config.nimMainPrefix, isVolatile]) - if optNoMain notin m.config.globalOptions or optGenDynLib in m.config.globalOptions: + if optNoMain notin m.config.globalOptions: if m.config.cppCustomNamespace.len > 0: closeNamespaceNim(m.s[cfsProcs]) m.s[cfsProcs].add "using namespace " & m.config.cppCustomNamespace & ";\L" diff --git a/compiler/commands.nim b/compiler/commands.nim index 5396cbe0d3..f14c3d1d10 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -802,7 +802,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "consoleapp") of "lib": incl(conf.globalOptions, optGenDynLib) - incl(conf.globalOptions, optNoMain) excl(conf.globalOptions, optGenGuiApp) defineSymbol(conf.symbols, "library") defineSymbol(conf.symbols, "dll") From dce714b2598c41e36113a4339fb9fb14655bc090 Mon Sep 17 00:00:00 2001 From: Khaled Hammouda Date: Mon, 24 Jul 2023 13:48:41 -0400 Subject: [PATCH 347/489] Fix grammar top rule (#22325) change stmt to complexOrSimpleStmt in the top grammar rule --- compiler/parser.nim | 2 +- doc/grammar.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/parser.nim b/compiler/parser.nim index 1b8fd70a60..7d12c2a785 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -310,7 +310,7 @@ proc checkBinary(p: Parser) {.inline.} = if p.tok.spacing == {tsTrailing}: parMessage(p, warnInconsistentSpacing, prettyTok(p.tok)) -#| module = stmt ^* (';' / IND{=}) +#| module = complexOrSimpleStmt ^* (';' / IND{=}) #| #| comma = ',' COMMENT? #| semicolon = ';' COMMENT? diff --git a/doc/grammar.txt b/doc/grammar.txt index 458eeb54a6..3096eecb52 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -1,5 +1,5 @@ # This file is generated by compiler/parser.nim. -module = stmt ^* (';' / IND{=}) +module = complexOrSimpleStmt ^* (';' / IND{=}) comma = ',' COMMENT? semicolon = ';' COMMENT? colon = ':' COMMENT? From 1c2ccfad08191e936fadd52450b53dfea105a34d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 25 Jul 2023 18:08:32 +0800 Subject: [PATCH 348/489] fixes #22301; fixes #22324; rejects branch initialization with a runtime discriminator with defaults (#22303) * fixes #22301; rejects branch initialization with a runtime discriminator with defaults * undefault nimPreviewRangeDefault * fixes tests * use oldCheckDefault --- compiler/sem.nim | 34 +++++++++++++++++---------------- compiler/semmagic.nim | 4 ++-- compiler/semobjconstr.nim | 13 ++++++++++++- config/nim.cfg | 1 - tests/objects/t22301.nim | 17 +++++++++++++++++ tests/system/tfielditerator.nim | 16 +++++++++++++++- 6 files changed, 64 insertions(+), 21 deletions(-) create mode 100644 tests/objects/t22301.nim diff --git a/compiler/sem.nim b/compiler/sem.nim index f92853d9e3..3324da55c3 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -553,17 +553,17 @@ proc pickCaseBranchIndex(caseExpr, matched: PNode): int = if endsWithElse: return caseExpr.len - 1 -proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] -proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode -proc defaultNodeField(c: PContext, a: PNode): PNode +proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault: bool): seq[PNode] +proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): PNode +proc defaultNodeField(c: PContext, a: PNode, checkDefault: bool): PNode const defaultFieldsSkipTypes = {tyGenericInst, tyAlias, tySink} -proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): seq[PNode] = +proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool, checkDefault: bool): seq[PNode] = case recNode.kind of nkRecList: for field in recNode: - result.add defaultFieldsForTuple(c, field, hasDefault) + result.add defaultFieldsForTuple(c, field, hasDefault, checkDefault) of nkSym: let field = recNode.sym let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes) @@ -572,7 +572,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s result.add newTree(nkExprColonExpr, recNode, field.ast) else: if recType.kind in {tyObject, tyArray, tyTuple}: - let asgnExpr = defaultNodeField(c, recNode, recNode.typ) + let asgnExpr = defaultNodeField(c, recNode, recNode.typ, checkDefault) if asgnExpr != nil: hasDefault = true asgnExpr.flags.incl nfSkipFieldChecking @@ -591,11 +591,11 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool): s else: doAssert false -proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = +proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault: bool): seq[PNode] = case recNode.kind of nkRecList: for field in recNode: - result.add defaultFieldsForTheUninitialized(c, field) + result.add defaultFieldsForTheUninitialized(c, field, checkDefault) of nkRecCase: let discriminator = recNode[0] var selectedBranch: int @@ -604,19 +604,21 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = # None of the branches were explicitly selected by the user and no value # was given to the discrimator. We can assume that it will be initialized # to zero and this will select a particular branch as a result: + if checkDefault: # don't add defaults when checking whether a case branch has default fields + return defaultValue = newIntNode(nkIntLit#[c.graph]#, 0) defaultValue.typ = discriminator.typ selectedBranch = recNode.pickCaseBranchIndex defaultValue defaultValue.flags.incl nfSkipFieldChecking result.add newTree(nkExprColonExpr, discriminator, defaultValue) - result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1]) + result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1], checkDefault) of nkSym: let field = recNode.sym let recType = recNode.typ.skipTypes(defaultFieldsSkipTypes) if field.ast != nil: #Try to use default value result.add newTree(nkExprColonExpr, recNode, field.ast) elif recType.kind in {tyObject, tyArray, tyTuple}: - let asgnExpr = defaultNodeField(c, recNode, recNode.typ) + let asgnExpr = defaultNodeField(c, recNode, recNode.typ, checkDefault) if asgnExpr != nil: asgnExpr.typ = recNode.typ asgnExpr.flags.incl nfSkipFieldChecking @@ -624,17 +626,17 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode): seq[PNode] = else: doAssert false -proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode = +proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): PNode = let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes) if aTypSkip.kind == tyObject: - let child = defaultFieldsForTheUninitialized(c, aTypSkip.n) + let child = defaultFieldsForTheUninitialized(c, aTypSkip.n, checkDefault) if child.len > 0: var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a.info, aTyp)) asgnExpr.typ = aTyp asgnExpr.sons.add child result = semExpr(c, asgnExpr) elif aTypSkip.kind == tyArray: - let child = defaultNodeField(c, a, aTypSkip[1]) + let child = defaultNodeField(c, a, aTypSkip[1], checkDefault) if child != nil: let node = newNode(nkIntLit) @@ -647,15 +649,15 @@ proc defaultNodeField(c: PContext, a: PNode, aTyp: PType): PNode = elif aTypSkip.kind == tyTuple: var hasDefault = false if aTypSkip.n != nil: - let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault) + let children = defaultFieldsForTuple(c, aTypSkip.n, hasDefault, checkDefault) if hasDefault and children.len > 0: result = newNodeI(nkTupleConstr, a.info) result.typ = aTyp result.sons.add children result = semExpr(c, result) -proc defaultNodeField(c: PContext, a: PNode): PNode = - result = defaultNodeField(c, a, a.typ) +proc defaultNodeField(c: PContext, a: PNode, checkDefault: bool): PNode = + result = defaultNodeField(c, a, a.typ, checkDefault) include semtempl, semgnrc, semstmts, semexprs diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index f94d8dc33e..ad7e9821b7 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -21,7 +21,7 @@ proc addDefaultFieldForNew(c: PContext, n: PNode): PNode = asgnExpr.typ = typ var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0] while true: - asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n) + asgnExpr.sons.add defaultFieldsForTheUninitialized(c, t.n, false) let base = t[0] if base == nil: break @@ -647,7 +647,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, of mDefault: result = checkDefault(c, n) let typ = result[^1].typ.skipTypes({tyTypeDesc}) - let defaultExpr = defaultNodeField(c, result[^1], typ) + let defaultExpr = defaultNodeField(c, result[^1], typ, false) if defaultExpr != nil: result = defaultExpr of mZeroDefault: diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index d4eba2112c..9b17676ee7 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -21,6 +21,7 @@ type # set this to true while visiting # parent types. missingFields: seq[PSym] # Fields that the user failed to specify + checkDefault: bool # Checking defaults InitStatus = enum # This indicates the result of object construction initUnknown @@ -342,6 +343,16 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, # All bets are off. If any of the branches has a mandatory # fields we must produce an error: for i in 1.. 0: + localError(c.config, discriminatorVal.info, "branch initialization " & + "with a runtime discriminator is not supported " & + "for a branch whose fields have default values.") discard collectMissingCaseFields(c, n[i], constrCtx, @[]) of nkSym: let field = n.sym @@ -353,7 +364,7 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext, result.defaults.add newTree(nkExprColonExpr, n, field.ast) else: if efWantNoDefaults notin flags: # cannot compute defaults at the typeRightPass - let defaultExpr = defaultNodeField(c, n) + let defaultExpr = defaultNodeField(c, n, constrCtx.checkDefault) if defaultExpr != nil: result.status = initUnknown result.defaults.add newTree(nkExprColonExpr, n, defaultExpr) diff --git a/config/nim.cfg b/config/nim.cfg index efb0581218..1470de7805 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -21,7 +21,6 @@ cc = gcc #hint[XDeclaredButNotUsed]=off threads:on -define:nimPreviewRangeDefault # Examples of how to setup a cross-compiler: # Nim can target architectures and OSes different than the local host diff --git a/tests/objects/t22301.nim b/tests/objects/t22301.nim new file mode 100644 index 0000000000..8746bf584d --- /dev/null +++ b/tests/objects/t22301.nim @@ -0,0 +1,17 @@ +discard """ + errormsg: "branch initialization with a runtime discriminator is not supported for a branch whose fields have default values." +""" + +# bug #22301 +type + Enum = enum A, B + Object = object + case a: Enum + of A: + integer: int = 200 + of B: + time: string + +let x = A +let s = Object(a: x) +echo s \ No newline at end of file diff --git a/tests/system/tfielditerator.nim b/tests/system/tfielditerator.nim index d1fbf02f95..7e063c6cf8 100644 --- a/tests/system/tfielditerator.nim +++ b/tests/system/tfielditerator.nim @@ -109,4 +109,18 @@ block titerator2: echo key, ": ", val for val in fields(co): - echo val \ No newline at end of file + echo val + +block: + type + Enum = enum A, B + Object = object + case a: Enum + of A: + integer: int + of B: + time: string + + let x = A + let s = Object(a: x) + doAssert s.integer == 0 From c0994c2dbdaaa6276b91c206d3377d68789f49ec Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Tue, 25 Jul 2023 17:56:14 +0200 Subject: [PATCH 349/489] [JS] Fix casting to ints (#22327) * [JS] Fix casting to ints * Simplify `genCast` by using `asUintN`/`asIntN` --- compiler/jsgen.nim | 26 +++++++------------------- tests/cast/tcast.nim | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 tests/cast/tcast.nim diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 1fbf6c74c7..4a62cbf9eb 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2727,26 +2727,14 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) = let fromInt = (src.kind in tyInt..tyInt32) let fromUint = (src.kind in tyUInt..tyUInt32) - if toUint and (fromInt or fromUint): - let trimmer = unsignedTrimmer(dest.size) - r.res = "($1 $2)" % [r.res, trimmer] - elif toUint and src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: - r.res = "Number(BigInt.asUintN($1, $2))" % [$(dest.size * 8), r.res] + if toUint: + if fromInt or fromUint: + r.res = "Number(BigInt.asUintN($1, BigInt($2)))" % [$(dest.size * 8), r.res] + elif src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "Number(BigInt.asUintN($1, $2))" % [$(dest.size * 8), r.res] elif toInt: - if fromInt: - return - elif fromUint: - if src.size == 4 and dest.size == 4: - # XXX prevent multi evaluations - r.res = "($1 | 0)" % [r.res] - else: - let trimmer = unsignedTrimmer(dest.size) - let minuend = case dest.size - of 1: "0xfe" - of 2: "0xfffe" - of 4: "0xfffffffe" - else: "" - r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer] + if fromInt or fromUint: + r.res = "Number(BigInt.asIntN($1, BigInt($2)))" % [$(dest.size * 8), r.res] elif src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: r.res = "Number(BigInt.asIntN($1, $2))" % [$(dest.size * 8), r.res] elif dest.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: diff --git a/tests/cast/tcast.nim b/tests/cast/tcast.nim new file mode 100644 index 0000000000..205444ea3a --- /dev/null +++ b/tests/cast/tcast.nim @@ -0,0 +1,21 @@ +discard """ + targets: "c cpp js" +""" + +proc main() = + block: # bug #16806 + let + a = 42u16 + b = cast[int16](a) + doAssert a.int16 == 42 + doAssert b in int16.low..int16.high + + block: # bug #16808 + doAssert cast[int8](cast[uint8](int8(-12))) == int8(-12) + doAssert cast[int16](cast[uint16](int16(-12))) == int16(-12) + doAssert cast[int32](cast[uint32](int32(-12))) == int32(-12) + + doAssert cast[int8](int16.high) == -1 + +static: main() +main() From 11c8dfc9b3199a12e5aadadd1491f63894b489ec Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 26 Jul 2023 10:04:34 +0800 Subject: [PATCH 350/489] fixes docs (#22331) --- lib/system.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system.nim b/lib/system.nim index 858571d61b..fc8476b40d 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -914,7 +914,7 @@ proc default*[T](_: typedesc[T]): T {.magic: "Default", noSideEffect.} = ## See also: ## * `zeroDefault <#zeroDefault,typedesc[T]>`_ ## - runnableExamples: + runnableExamples("-d:nimPreviewRangeDefault"): assert (int, float).default == (0, 0.0) type Foo = object a: range[2..6] From db77c984714aeafdb61aba092f54fd22a482deed Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Thu, 27 Jul 2023 23:06:30 +0200 Subject: [PATCH 351/489] [JS] Fix bitwise ops & shifts (#22340) * [JS] Fix bitwise ops & shifts * Test `int64` & `uint64` only with `jsbigint64` --- compiler/jsgen.nim | 83 +++++++++++++++++++++++++++++---------------- tests/int/tints.nim | 49 +++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 31 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 4a62cbf9eb..ce1fdb1a5e 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -556,16 +556,16 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string, r.res = frmt % [a, b, tmp, tmp2] r.kind = resExpr -proc unsignedTrimmerJS(size: BiggestInt): Rope = +proc unsignedTrimmer(size: BiggestInt): string = case size - of 1: rope"& 0xff" - of 2: rope"& 0xffff" - of 4: rope">>> 0" - else: rope"" + of 1: "& 0xff" + of 2: "& 0xffff" + of 4: ">>> 0" + else: "" - -template unsignedTrimmer(size: BiggestInt): Rope = - size.unsignedTrimmerJS +proc signedTrimmer(size: BiggestInt): string = + # sign extension is done by shifting to the left and then back to the right + "<< $1 >> $1" % [$(32 - size * 8)] proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, reassign: static[bool] = false) = @@ -626,6 +626,13 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = template applyFormat(frmtA, frmtB) = if i == 0: applyFormat(frmtA) else: applyFormat(frmtB) + template bitwiseExpr(op: string) = + let typ = n[1].typ.skipTypes(abstractVarRange) + if typ.kind in {tyUInt, tyUInt32}: + r.res = "(($1 $2 $3) >>> 0)" % [xLoc, op, yLoc] + else: + r.res = "($1 $2 $3)" % [xLoc, op, yLoc] + case op of mAddI: if i == 0: @@ -672,7 +679,19 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mSubF64: applyFormat("($1 - $2)", "($1 - $2)") of mMulF64: applyFormat("($1 * $2)", "($1 * $2)") of mDivF64: applyFormat("($1 / $2)", "($1 / $2)") - of mShrI: applyFormat("", "") + of mShrI: + let typ = n[1].typ.skipTypes(abstractVarRange) + if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + applyFormat("BigInt.asIntN(64, BigInt.asUintN(64, $1) >> BigInt($2))") + elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: + applyFormat("($1 >> BigInt($2))") + else: + if typ.kind in {tyInt..tyInt32}: + let trimmerU = unsignedTrimmer(typ.size) + let trimmerS = signedTrimmer(typ.size) + r.res = "((($1 $2) >>> $3) $4)" % [xLoc, trimmerU, yLoc, trimmerS] + else: + applyFormat("($1 >>> $2)") of mShlI: let typ = n[1].typ.skipTypes(abstractVarRange) if typ.size == 8: @@ -683,21 +702,27 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = else: applyFormat("($1 * Math.pow(2, $2))") else: - applyFormat("($1 << $2)", "($1 << $2)") + if typ.kind in {tyUInt..tyUInt32}: + let trimmer = unsignedTrimmer(typ.size) + r.res = "(($1 << $2) $3)" % [xLoc, yLoc, trimmer] + else: + let trimmer = signedTrimmer(typ.size) + r.res = "(($1 << $2) $3)" % [xLoc, yLoc, trimmer] of mAshrI: let typ = n[1].typ.skipTypes(abstractVarRange) if typ.size == 8: - if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: - applyFormat("BigInt.asIntN(64, $1 >> BigInt($2))") - elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: - applyFormat("BigInt.asUintN(64, $1 >> BigInt($2))") + if optJsBigInt64 in p.config.globalOptions: + applyFormat("($1 >> BigInt($2))") else: applyFormat("Math.floor($1 / Math.pow(2, $2))") else: - applyFormat("($1 >> $2)", "($1 >> $2)") - of mBitandI: applyFormat("($1 & $2)", "($1 & $2)") - of mBitorI: applyFormat("($1 | $2)", "($1 | $2)") - of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)") + if typ.kind in {tyUInt..tyUInt32}: + applyFormat("($1 >>> $2)") + else: + applyFormat("($1 >> $2)") + of mBitandI: bitwiseExpr("&") + of mBitorI: bitwiseExpr("|") + of mBitxorI: bitwiseExpr("^") of mMinI: applyFormat("nimMin($1, $2)", "nimMin($1, $2)") of mMaxI: applyFormat("nimMax($1, $2)", "nimMax($1, $2)") of mAddU: applyFormat("", "") @@ -733,7 +758,16 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = of mAbsI: applyFormat("absInt($1)", "Math.abs($1)") of mNot: applyFormat("!($1)", "!($1)") of mUnaryPlusI: applyFormat("+($1)", "+($1)") - of mBitnotI: applyFormat("~($1)", "~($1)") + of mBitnotI: + let typ = n[1].typ.skipTypes(abstractVarRange) + if typ.kind in {tyUInt..tyUInt64}: + if typ.size == 8 and optJsBigInt64 in p.config.globalOptions: + applyFormat("BigInt.asUintN(64, ~($1))") + else: + let trimmer = unsignedTrimmer(typ.size) + r.res = "(~($1) $2)" % [xLoc, trimmer] + else: + applyFormat("~($1)") of mUnaryPlusF64: applyFormat("+($1)", "+($1)") of mUnaryMinusF64: applyFormat("-($1)", "-($1)") of mCharToStr: applyFormat("nimCharToStr($1)", "nimCharToStr($1)") @@ -760,17 +794,6 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = arithAux(p, n, r, op) of mModI: arithAux(p, n, r, op) - of mShrI: - var x, y: TCompRes - gen(p, n[1], x) - gen(p, n[2], y) - let typ = n[1].typ.skipTypes(abstractVarRange) - if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: - r.res = "BigInt.asIntN(64, BigInt.asUintN(64, $1) >> BigInt($2))" % [x.rdLoc, y.rdLoc] - elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions: - r.res = "($1 >> BigInt($2))" % [x.rdLoc, y.rdLoc] - else: - r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc] of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr: arithAux(p, n, r, op) of mEqRef: diff --git a/tests/int/tints.nim b/tests/int/tints.nim index cb77d4d896..a7d27d7369 100644 --- a/tests/int/tints.nim +++ b/tests/int/tints.nim @@ -92,6 +92,53 @@ block: # Casts to uint # issue #7174 let c = 1'u let val = c > 0 -doAssert val +doAssert val + +block: # bug #6752 + when not defined(js) or (defined(js) and compileOption("jsbigint64")): + let x = 711127'i64 + doAssert x * 86400'i64 == 61441372800'i64 + +block: # bug #17604 + let a = 2147483648'u + doAssert (a and a) == a + doAssert (a or 0) == a + +block: # bitwise not + let + z8 = 0'u8 + z16 = 0'u16 + z32 = 0'u32 + z64 = 0'u64 + doAssert (not z8) == uint8.high + doAssert (not z16) == uint16.high + doAssert (not z32) == uint32.high + when not defined(js) or (defined(js) and compileOption("jsbigint64")): + doAssert (not z64) == uint64.high + +block: # shl + let i8 = int8.high + let i16 = int16.high + let i32 = int32.high + let i64 = int64.high + doAssert i8 shl 1 == -2 + doAssert i8 shl 2 == -4 + doAssert i16 shl 1 == -2 + doAssert i16 shl 2 == -4 + doAssert i32 shl 1 == -2 + doAssert i32 shl 2 == -4 + when not defined(js) or (defined(js) and compileOption("jsbigint64")): + doAssert i64 shl 1 == -2 + doAssert i64 shl 2 == -4 + + let u8 = uint8.high + let u16 = uint16.high + let u32 = uint32.high + let u64 = uint64.high + doAssert u8 shl 1 == u8 - 1 + doAssert u16 shl 1 == u16 - 1 + doAssert u32 shl 1 == u32 - 1 + when not defined(js) or (defined(js) and compileOption("jsbigint64")): + doAssert u64 shl 1 == u64 - 1 echo("Success") #OUT Success From f1ac979184ad7fa0d8c44415e781181a00a0095f Mon Sep 17 00:00:00 2001 From: "Eric N. Vander Weele" Date: Thu, 27 Jul 2023 17:07:03 -0400 Subject: [PATCH 352/489] Remove declared and not used variable in packedsets.bitincl (#22334) When compiling code that uses PackedSet with warnings enabled, `var ret` in `bitincl` emits a "XDeclaredButNotUsed" warning. --- lib/std/packedsets.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index e8e03af9e3..04fa78ada9 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -109,7 +109,6 @@ proc intSetPut[A](t: var PackedSet[A], key: int): Trunk = t.data[h] = result proc bitincl[A](s: var PackedSet[A], key: int) {.inline.} = - var ret: Trunk var t = intSetPut(s, key shr TrunkShift) var u = key and TrunkMask t.bits[u shr IntShift] = t.bits[u shr IntShift] or From f0f3904ff04a46bae6f876b0326162354466f415 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 29 Jul 2023 16:57:03 +0800 Subject: [PATCH 353/489] implement `ensureMove` (#22339) * implement `ensureMove` * use an additional flag * improve some logics * progress: fixes discard ensureMove * forbids nested expressions * improve error messages * checkpoint * fixes cursor * ADD MORE TESTS * fixes cursorinference again * tiny cleanup * improve error messages * fixes docs * implement comments add more tests * fixes js --- compiler/ast.nim | 2 +- compiler/ccgexprs.nim | 2 + compiler/condsyms.nim | 1 + compiler/injectdestructors.nim | 41 ++++++++++- compiler/jsgen.nim | 2 + compiler/lineinfos.nim | 2 + compiler/semmagic.nim | 4 + compiler/varpartitions.nim | 4 + compiler/vmgen.nim | 2 + lib/system.nim | 10 +++ tests/system/tensuremove.nim | 130 +++++++++++++++++++++++++++++++++ tests/system/tensuremove1.nim | 16 ++++ tests/system/tensuremove2.nim | 15 ++++ tests/system/tensuremove3.nim | 28 +++++++ 14 files changed, 255 insertions(+), 4 deletions(-) create mode 100644 tests/system/tensuremove.nim create mode 100644 tests/system/tensuremove1.nim create mode 100644 tests/system/tensuremove2.nim create mode 100644 tests/system/tensuremove3.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 706c0d38fb..539b6e9547 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -690,7 +690,7 @@ type mIsPartOf, mAstToStr, mParallel, mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq, mNewString, mNewStringOfCap, mParseBiggestFloat, - mMove, mWasMoved, mDup, mDestroy, mTrace, + mMove, mEnsureMove, mWasMoved, mDup, mDestroy, mTrace, mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 2b9f4221f0..712b874d93 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2622,6 +2622,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mAccessTypeField: genAccessTypeField(p, e, d) of mSlice: genSlice(p, e, d) of mTrace: discard "no code to generate" + of mEnsureMove: + expr(p, e[1], d) else: when defined(debugMagics): echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index c680504494..1146bed146 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -157,3 +157,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasSendable") defineSymbol("nimAllowNonVarDestructor") defineSymbol("nimHasQuirky") + defineSymbol("nimHasEnsureMove") diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index d7f4e38d2c..590012806c 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -36,6 +36,7 @@ type body: PNode otherUsage: TLineInfo inUncheckedAssignSection: int + inEnsureMove: int Scope = object # we do scope-based memory management. # a scope is comparable to an nkStmtListExpr like @@ -332,6 +333,9 @@ proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode = assert ri.typ != nil proc genCopy(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag]): PNode = + if c.inEnsureMove > 0: + localError(c.graph.config, ri.info, errFailedMove, "cannot move '" & $ri & + "', which introduces an implicit copy") let t = dest.typ if tfHasOwned in t.flags and ri.kind != nkNilLit: # try to improve the error message here: @@ -400,7 +404,7 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode = proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = # generate: (let tmp = v; reset(v); tmp) - if not hasDestructor(c, n.typ): + if (not hasDestructor(c, n.typ)) and c.inEnsureMove == 0: assert n.kind != nkSym or not hasDestructor(c, n.sym.typ) result = copyTree(n) else: @@ -419,7 +423,8 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = result.add v let nn = skipConv(n) - c.genMarkCyclic(result, nn) + if hasDestructor(c, n.typ): + c.genMarkCyclic(result, nn) let wasMovedCall = c.genWasMoved(nn) result.add wasMovedCall result.add tempAsNode @@ -462,6 +467,9 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = message(c.graph.config, n.info, hintPerformance, ("passing '$1' to a sink parameter introduces an implicit copy; " & "if possible, rearrange your program's control flow to prevent it") % $n) + if c.inEnsureMove > 0: + localError(c.graph.config, n.info, errFailedMove, + ("cannot move '$1', passing '$1' to a sink parameter introduces an implicit copy") % $n) else: if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: assert(not containsManagedMemory(n.typ)) @@ -765,7 +773,15 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing result = passCopyToSink(n, c, s) elif n.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure, nkNilLit} + nkCallKinds + nkLiterals: - result = p(n, c, s, consumed) + if n.kind in nkCallKinds and n[0].kind == nkSym: + if n[0].sym.magic == mEnsureMove: + inc c.inEnsureMove + result = p(n[1], c, s, sinkArg) + dec c.inEnsureMove + else: + result = p(n, c, s, consumed) + else: + result = p(n, c, s, consumed) elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and isLastRead(n, c, s) and not (n.kind == nkSym and isCursor(n)): # Sinked params can be consumed only once. We need to reset the memory @@ -837,6 +853,12 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing if mode == normal and isRefConstr: result = ensureDestruction(result, n, c, s) of nkCallKinds: + if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove: + inc c.inEnsureMove + result = p(n[1], c, s, sinkArg) + dec c.inEnsureMove + return + let inSpawn = c.inSpawn if n[0].kind == nkSym and n[0].sym.magic == mSpawn: c.inSpawn.inc @@ -1069,6 +1091,11 @@ proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags: result = newTree(nkStmtList, v, snk, c.genWasMoved(newAccess)) proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopyFlag] = {}): PNode = + var ri = ri + var isEnsureMove = 0 + if ri.kind in nkCallKinds and ri[0].kind == nkSym and ri[0].sym.magic == mEnsureMove: + ri = ri[1] + isEnsureMove = 1 if sameLocation(dest, ri): # rule (self-assignment-removal): result = newNodeI(nkEmpty, dest.info) @@ -1103,13 +1130,17 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy else: result = c.genSink(s, dest, destructiveMoveVar(ri, c, s), flags) else: + inc c.inEnsureMove, isEnsureMove result = c.genCopy(dest, ri, flags) + dec c.inEnsureMove, isEnsureMove result.add p(ri, c, s, consumed) c.finishCopy(result, dest, isFromSink = false) of nkBracket: # array constructor if ri.len > 0 and isDangerousSeq(ri.typ): + inc c.inEnsureMove, isEnsureMove result = c.genCopy(dest, ri, flags) + dec c.inEnsureMove, isEnsureMove result.add p(ri, c, s, consumed) c.finishCopy(result, dest, isFromSink = false) else: @@ -1127,7 +1158,9 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy let snk = c.genSink(s, dest, ri, flags) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) else: + inc c.inEnsureMove, isEnsureMove result = c.genCopy(dest, ri, flags) + dec c.inEnsureMove, isEnsureMove result.add p(ri, c, s, consumed) c.finishCopy(result, dest, isFromSink = false) of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast: @@ -1145,7 +1178,9 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy let snk = c.genSink(s, dest, ri, flags) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) else: + inc c.inEnsureMove, isEnsureMove result = c.genCopy(dest, ri, flags) + dec c.inEnsureMove, isEnsureMove result.add p(ri, c, s, consumed) c.finishCopy(result, dest, isFromSink = false) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index ce1fdb1a5e..8be4d9d075 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -2405,6 +2405,8 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = genMove(p, n, r) of mDup: genDup(p, n, r) + of mEnsureMove: + gen(p, n[1], r) else: genCall(p, n, r) #else internalError(p.config, e.info, 'genMagic: ' + magicToStr[op]); diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 37adc5660e..785b101972 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -44,6 +44,7 @@ type errRstSandboxedDirective, errProveInit, # deadcode errGenerated, + errFailedMove, errUser, # warnings warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape", @@ -128,6 +129,7 @@ const errRstSandboxedDirective: "disabled directive: '$1'", errProveInit: "Cannot prove that '$1' is initialized.", # deadcode errGenerated: "$1", + errFailedMove: "$1", errUser: "$1", warnCannotOpenFile: "cannot open '$1'", warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored", diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index ad7e9821b7..97a3207744 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -666,5 +666,9 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result = n if result.typ != nil and expectedType != nil and result.typ.kind == tySequence and expectedType.kind == tySequence and result.typ[0].kind == tyEmpty: result.typ = expectedType # type inference for empty sequence # bug #21377 + of mEnsureMove: + result = n + if isAssignable(c, n[1]) notin {arLValue, arLocalLValue}: + localError(c.config, n.info, "'" & $n[1] & "'" & " is not a mutable location; it cannot be moved") else: result = n diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 6598ef508b..6290b311fb 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -707,6 +707,10 @@ proc traverse(c: var Partitions; n: PNode) = let L = if parameters != nil: parameters.len else: 0 let m = getMagic(n) + if m == mEnsureMove and n[1].kind == nkSym: + # we know that it must be moved so it cannot be a cursor + noCursor(c, n[1].sym) + for i in 1.. Date: Sat, 29 Jul 2023 17:05:31 +0100 Subject: [PATCH 354/489] fixes an issue where byref wasnt properly handled when using it in a generic param (#22337) * fixes an issue where byref wasnt properly handled when using it in a generic param * removes unreachable check --- compiler/ccgtypes.nim | 13 ++++++++++--- tests/cpp/tpassbypragmas.nim | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 tests/cpp/tpassbypragmas.nim diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index e4a0fe84bc..2aa92c130e 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -18,6 +18,7 @@ type TypeDescKind = enum dkParam #skParam dkRefParam #param passed by ref when {.byref.} is used. Cpp only. C goes straight to dkParam and is handled as a regular pointer + dkRefGenericParam #param passed by ref when {.byref.} is used that is also a generic. Cpp only. C goes straight to dkParam and is handled as a regular pointer dkVar #skVar dkField #skField dkResult #skResult @@ -519,7 +520,10 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var var param = t.n[i].sym var descKind = dkParam if optByRef in param.options: - descKind = dkRefParam + if param.typ.kind == tyGenericInst: + descKind = dkRefGenericParam + else: + descKind = dkRefParam var typ, name : string fillParamName(m, param) fillLoc(param.loc, locParam, t.n[i], @@ -570,7 +574,10 @@ proc genProcParams(m: BModule; t: PType, rettype, params: var Rope, var param = t.n[i].sym var descKind = dkParam if m.config.backend == backendCpp and optByRef in param.options: - descKind = dkRefParam + if param.typ.kind == tyGenericInst: + descKind = dkRefGenericParam + else: + descKind = dkRefParam if isCompileTimeOnly(param.typ): continue if params != "(": params.add(", ") fillParamName(m, param) @@ -873,7 +880,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes result = getTypePre(m, t, sig) if result != "" and t.kind != tyOpenArray: excl(check, t.id) - if kind == dkRefParam: + if kind == dkRefParam or kind == dkRefGenericParam and origTyp.kind == tyGenericInst: result.add("&") return case t.kind diff --git a/tests/cpp/tpassbypragmas.nim b/tests/cpp/tpassbypragmas.nim new file mode 100644 index 0000000000..f4301656af --- /dev/null +++ b/tests/cpp/tpassbypragmas.nim @@ -0,0 +1,27 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" +""" +{.emit:"""/*TYPESECTION*/ + + template + struct Box { + T first; + }; + struct Foo { + void test(void (*func)(Box& another)){ + + }; + }; +""".} + +type + Foo {.importcpp.} = object + Box[T] {.importcpp:"Box<'0>".} = object + first: T + +proc test(self: Foo, fn: proc(another {.byref.}: Box[Foo]) {.cdecl.}) {.importcpp.} + +proc fn(another {.byref.} : Box[Foo]) {.cdecl.} = discard + +Foo().test(fn) \ No newline at end of file From 19d1fe7af3ac728327732f3d54f0a3333d0b3328 Mon Sep 17 00:00:00 2001 From: Juan Carlos Date: Sun, 30 Jul 2023 02:21:22 -0300 Subject: [PATCH 355/489] Add Valgrind (#22346) * . * Add Valgrind for Bisect bot in GitHub Actions --- .github/workflows/bisects.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/bisects.yml b/.github/workflows/bisects.yml index c755ef5a27..a8200c1f96 100644 --- a/.github/workflows/bisects.yml +++ b/.github/workflows/bisects.yml @@ -15,6 +15,9 @@ jobs: with: nim-version: 'devel' + - name: Install Dependencies + run: sudo apt-get install --no-install-recommends -yq valgrind + - uses: juancarlospaco/nimrun-action@nim with: github-token: ${{ secrets.GITHUB_TOKEN }} From 281016a8022b8e8308e3e578b2c2daa6df4a66a1 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 31 Jul 2023 02:43:52 +0800 Subject: [PATCH 356/489] add a changelog for `ensureMove` (#22347) * add a changelog for `ensureMove` * Update changelogs/changelog_2_0_0_details.md --------- Co-authored-by: Andreas Rumpf --- changelogs/changelog_2_0_0_details.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelogs/changelog_2_0_0_details.md b/changelogs/changelog_2_0_0_details.md index e3895639ad..f6393b2db7 100644 --- a/changelogs/changelog_2_0_0_details.md +++ b/changelogs/changelog_2_0_0_details.md @@ -344,6 +344,7 @@ + Added `toDateString`, `toISOString`, `toJSON`, `toTimeString`, `toUTCString` converters for `DateTime`. - Added `BackwardsIndex` overload for `CacheSeq`. - Added support for nested `with` blocks in `std/with`. +- Added `ensureMove` to the system module. It ensures that the passed argument is moved, otherwise an error is given at the compile time. [//]: # "Deprecations:" From d51bc084fd6277dfe2ebd6040f0dd6c281c83b6d Mon Sep 17 00:00:00 2001 From: Bung Date: Mon, 31 Jul 2023 16:58:59 +0800 Subject: [PATCH 357/489] remove thread duplicated code (#22348) --- lib/system/threadimpl.nim | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/system/threadimpl.nim b/lib/system/threadimpl.nim index 94db233365..285b8f5e7f 100644 --- a/lib/system/threadimpl.nim +++ b/lib/system/threadimpl.nim @@ -20,13 +20,8 @@ when not defined(useNimRtl): threadType = ThreadType.NimThread when defined(gcDestructors): - proc allocThreadStorage(size: int): pointer = - result = c_malloc(csize_t size) - zeroMem(result, size) - proc deallocThreadStorage(p: pointer) = c_free(p) else: - template allocThreadStorage(size: untyped): untyped = allocShared0(size) template deallocThreadStorage(p: pointer) = deallocShared(p) template afterThreadRuns() = From 569ccc50ff9f4f48272a00c82556a495c0f721b9 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 31 Jul 2023 21:37:24 +0800 Subject: [PATCH 358/489] fixes #22174; fixes destructor examples (#22349) * fixes #22174; fixes destructor examples * Update doc/destructors.md Co-authored-by: Andreas Rumpf --------- Co-authored-by: Andreas Rumpf --- doc/destructors.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/destructors.md b/doc/destructors.md index 12def00537..3121335145 100644 --- a/doc/destructors.md +++ b/doc/destructors.md @@ -30,7 +30,7 @@ Motivating example With the language mechanisms described here, a custom seq could be written as: - ```nim + ```nim test type myseq*[T] = object len, cap: int @@ -570,7 +570,7 @@ that the pointer does not outlive its origin. No destructor call is injected for expressions of type `lent T` or of type `var T`. - ```nim + ```nim test type Tree = object kids: seq[Tree] @@ -584,7 +584,7 @@ for expressions of type `lent T` or of type `var T`. proc `[]`*(x: Tree; i: int): lent Tree = result = x.kids[i] # borrows from 'x', this is transformed into: - result = addr x.kids[i] + # result = addr x.kids[i] # This means 'lent' is like 'var T' a hidden pointer. # Unlike 'var' this hidden pointer cannot be used to mutate the object. @@ -715,7 +715,7 @@ The experimental `nodestroy`:idx: pragma inhibits hook injections. This can be used to specialize the object traversal in order to avoid deep recursions: - ```nim + ```nim test type Node = ref object x, y: int32 left, right: Node @@ -730,8 +730,8 @@ used to specialize the object traversal in order to avoid deep recursions: let x = s.pop if x.left != nil: s.add(x.left) if x.right != nil: s.add(x.right) - # free the memory explicit: - dispose(x) + # free the memory explicitly: + `=dispose`(x) # notice how even the destructor for 's' is not called implicitly # anymore thanks to .nodestroy, so we have to call it on our own: `=destroy`(s) From b56df5c07f7dc9ac9d718ca47c10b0683a9b916f Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 31 Jul 2023 22:02:52 +0800 Subject: [PATCH 359/489] fixes #22246; generate `__builtin_unreachable` hints for case defaults (#22350) * fixes #22246; generate `__builtin_unreachable` hints * use elif * indentation * fixes holy enums in sim --- compiler/ccgstmts.nim | 7 +++++-- compiler/extccomp.nim | 5 +++-- testament/important_packages.nim | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 3197389814..448a437db7 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -971,8 +971,11 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) = hasDefault = true exprBlock(p, branch.lastSon, d) lineF(p, cpsStmts, "break;$n", []) - if (hasAssume in CC[p.config.cCompiler].props) and not hasDefault: - lineF(p, cpsStmts, "default: __assume(0);$n", []) + if not hasDefault: + if hasBuiltinUnreachable in CC[p.config.cCompiler].props: + lineF(p, cpsStmts, "default: __builtin_unreachable();$n", []) + elif hasAssume in CC[p.config.cCompiler].props: + lineF(p, cpsStmts, "default: __assume(0);$n", []) lineF(p, cpsStmts, "}$n", []) if lend != "": fixLabel(p, lend) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 391f158f0c..3605d1dd27 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -33,6 +33,7 @@ type hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax hasDeclspec, # CC has __declspec(X) hasAttribute, # CC has __attribute__((X)) + hasBuiltinUnreachable # CC has __builtin_unreachable TInfoCCProps* = set[TInfoCCProp] TInfoCC* = tuple[ name: string, # the short name of the compiler @@ -95,7 +96,7 @@ compiler gcc: produceAsm: gnuAsmListing, cppXsupport: "-std=gnu++17 -funsigned-char", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, - hasAttribute}) + hasAttribute, hasBuiltinUnreachable}) # GNU C and C++ Compiler compiler nintendoSwitchGCC: @@ -122,7 +123,7 @@ compiler nintendoSwitchGCC: produceAsm: gnuAsmListing, cppXsupport: "-std=gnu++17 -funsigned-char", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, - hasAttribute}) + hasAttribute, hasBuiltinUnreachable}) # LLVM Frontend for GCC/G++ compiler llvmGcc: diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 9016a0d3dc..c632256efe 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -146,7 +146,7 @@ pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim" pkg "sdl1", "nim c -r src/sdl.nim" pkg "sdl2_nim", "nim c -r sdl2/sdl.nim" pkg "sigv4", "nim c --gc:arc -r sigv4.nim", "https://github.com/disruptek/sigv4" -pkg "sim" +pkg "sim", url = "https://github.com/nim-lang/sim.nim" pkg "smtp", "nimble compileExample" pkg "snip", "nimble test", "https://github.com/genotrance/snip" pkg "ssostrings" From 0b3ddd4e47e12dda043a48ac24a8db823846d3da Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 31 Jul 2023 22:14:15 +0800 Subject: [PATCH 360/489] Revert "fixes #22246; generate `__builtin_unreachable` hints for case defaults" (#22351) Revert "fixes #22246; generate `__builtin_unreachable` hints for case defaults (#22350)" This reverts commit b56df5c07f7dc9ac9d718ca47c10b0683a9b916f. --- compiler/ccgstmts.nim | 7 ++----- compiler/extccomp.nim | 5 ++--- testament/important_packages.nim | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 448a437db7..3197389814 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -971,11 +971,8 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) = hasDefault = true exprBlock(p, branch.lastSon, d) lineF(p, cpsStmts, "break;$n", []) - if not hasDefault: - if hasBuiltinUnreachable in CC[p.config.cCompiler].props: - lineF(p, cpsStmts, "default: __builtin_unreachable();$n", []) - elif hasAssume in CC[p.config.cCompiler].props: - lineF(p, cpsStmts, "default: __assume(0);$n", []) + if (hasAssume in CC[p.config.cCompiler].props) and not hasDefault: + lineF(p, cpsStmts, "default: __assume(0);$n", []) lineF(p, cpsStmts, "}$n", []) if lend != "": fixLabel(p, lend) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 3605d1dd27..391f158f0c 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -33,7 +33,6 @@ type hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax hasDeclspec, # CC has __declspec(X) hasAttribute, # CC has __attribute__((X)) - hasBuiltinUnreachable # CC has __builtin_unreachable TInfoCCProps* = set[TInfoCCProp] TInfoCC* = tuple[ name: string, # the short name of the compiler @@ -96,7 +95,7 @@ compiler gcc: produceAsm: gnuAsmListing, cppXsupport: "-std=gnu++17 -funsigned-char", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, - hasAttribute, hasBuiltinUnreachable}) + hasAttribute}) # GNU C and C++ Compiler compiler nintendoSwitchGCC: @@ -123,7 +122,7 @@ compiler nintendoSwitchGCC: produceAsm: gnuAsmListing, cppXsupport: "-std=gnu++17 -funsigned-char", props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm, - hasAttribute, hasBuiltinUnreachable}) + hasAttribute}) # LLVM Frontend for GCC/G++ compiler llvmGcc: diff --git a/testament/important_packages.nim b/testament/important_packages.nim index c632256efe..9016a0d3dc 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -146,7 +146,7 @@ pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim" pkg "sdl1", "nim c -r src/sdl.nim" pkg "sdl2_nim", "nim c -r sdl2/sdl.nim" pkg "sigv4", "nim c --gc:arc -r sigv4.nim", "https://github.com/disruptek/sigv4" -pkg "sim", url = "https://github.com/nim-lang/sim.nim" +pkg "sim" pkg "smtp", "nimble compileExample" pkg "snip", "nimble test", "https://github.com/genotrance/snip" pkg "ssostrings" From 35ff70f36c0025018de3a8c5c993249d11b98292 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 31 Jul 2023 20:19:18 +0200 Subject: [PATCH 361/489] Tomorrow is the release. I hope. (#22353) --- changelogs/changelog_2_0_0.md | 2 +- changelogs/changelog_2_0_0_details.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelogs/changelog_2_0_0.md b/changelogs/changelog_2_0_0.md index d954c774ef..457cc62a6b 100644 --- a/changelogs/changelog_2_0_0.md +++ b/changelogs/changelog_2_0_0.md @@ -1,4 +1,4 @@ -# v2.0.0 - 2023-07-dd +# v2.0.0 - 2023-08-01 Version 2.0 is a big milestone with too many changes to list them all here. diff --git a/changelogs/changelog_2_0_0_details.md b/changelogs/changelog_2_0_0_details.md index f6393b2db7..a38f2b40b7 100644 --- a/changelogs/changelog_2_0_0_details.md +++ b/changelogs/changelog_2_0_0_details.md @@ -1,4 +1,4 @@ -# v2.0.0 - yyyy-mm-dd +# v2.0.0 - 2023-08-01 ## Changes affecting backward compatibility From a23e53b4902d227353886d97ef50609709519dd9 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 1 Aug 2023 21:18:08 +0800 Subject: [PATCH 362/489] fixes #22262; fixes `-d:useMalloc` broken with `--mm:none` and `--threads on` (#22355) * fixes #22262; -d:useMalloc broken with --mm:none and threads on * fixes --- lib/system/mm/malloc.nim | 2 +- tests/system/tgcnone.nim | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/system/mm/malloc.nim b/lib/system/mm/malloc.nim index b24b6f1e0c..47f1a95ae4 100644 --- a/lib/system/mm/malloc.nim +++ b/lib/system/mm/malloc.nim @@ -88,7 +88,7 @@ type proc alloc(r: var MemRegion, size: int): pointer = result = alloc(size) -proc alloc0Impl(r: var MemRegion, size: int): pointer = +proc alloc0(r: var MemRegion, size: int): pointer = result = alloc0Impl(size) proc dealloc(r: var MemRegion, p: pointer) = dealloc(p) proc deallocOsPages(r: var MemRegion) = discard diff --git a/tests/system/tgcnone.nim b/tests/system/tgcnone.nim index 47c6c60145..1ccb9e29c5 100644 --- a/tests/system/tgcnone.nim +++ b/tests/system/tgcnone.nim @@ -1,6 +1,7 @@ discard """ - matrix: "--gc:none -d:useMalloc --threads:off" + matrix: "--mm:none -d:useMalloc" """ # bug #15617 +# bug #22262 let x = 4 doAssert x == 4 From 1d2c27d2e67149240f97de48f721d95539c543e4 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 1 Aug 2023 22:48:52 +0800 Subject: [PATCH 363/489] bump the devel version to 211 (#22356) --- lib/system/compilation.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/system/compilation.nim b/lib/system/compilation.nim index ba47c1f692..c36bd98319 100644 --- a/lib/system/compilation.nim +++ b/lib/system/compilation.nim @@ -1,16 +1,16 @@ const - NimMajor* {.intdefine.}: int = 1 + NimMajor* {.intdefine.}: int = 2 ## is the major number of Nim's version. Example: ## ``` ## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard ## ``` # see also std/private/since - NimMinor* {.intdefine.}: int = 9 + NimMinor* {.intdefine.}: int = 1 ## is the minor number of Nim's version. ## Odd for devel, even for releases. - NimPatch* {.intdefine.}: int = 5 + NimPatch* {.intdefine.}: int = 1 ## is the patch number of Nim's version. ## Odd for devel, even for releases. From da368885da8850c0c87e6b9dcff64393985aff27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mar=C5=A1=C3=A1lek?= Date: Tue, 1 Aug 2023 20:56:38 +0200 Subject: [PATCH 364/489] Fix the position of "Grey" in colors.nim (#22358) Update the position of "Grey" --- lib/pure/colors.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index b688fad544..685b68b360 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -200,8 +200,8 @@ const colGoldenRod* = Color(0xDAA520) colGray* = Color(0x808080) colGreen* = Color(0x008000) - colGrey* = Color(0x808080) colGreenYellow* = Color(0xADFF2F) + colGrey* = Color(0x808080) colHoneyDew* = Color(0xF0FFF0) colHotPink* = Color(0xFF69B4) colIndianRed* = Color(0xCD5C5C) @@ -350,8 +350,8 @@ const "goldenrod": colGoldenRod, "gray": colGray, "green": colGreen, - "grey": colGrey, "greenyellow": colGreenYellow, + "grey": colGrey, "honeydew": colHoneyDew, "hotpink": colHotPink, "indianred": colIndianRed, From f3a7622514f24740c6b33f0c37ebe6339ad5b70d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:58:29 +0800 Subject: [PATCH 365/489] fixes #22360; compare with the half of randMax (#22361) * fixes #22360; compare with the half of randMax * add a test --- lib/pure/random.nim | 5 +---- tests/stdlib/trandom.nim | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 422f42a8b8..88616594b1 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -381,10 +381,7 @@ proc rand*[T: Ordinal](r: var Rand; t: typedesc[T]): T {.since: (1, 7, 1).} = when T is range or T is enum: result = rand(r, low(T)..high(T)) elif T is bool: - whenJsNoBigInt64: - result = (r.next or 0) < 0 - do: - result = cast[int64](r.next) < 0 + result = r.next < randMax div 2 else: whenJsNoBigInt64: result = cast[T](r.next shr (sizeof(uint)*8 - sizeof(T)*8)) diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim index 8784b33ee4..920d429d4f 100644 --- a/tests/stdlib/trandom.nim +++ b/tests/stdlib/trandom.nim @@ -282,3 +282,21 @@ block: # bug #17898 for j in 0.. Date: Wed, 2 Aug 2023 17:00:34 +0800 Subject: [PATCH 366/489] fixes #22362; Compiler crashes with staticBoundsCheck on (#22363) --- compiler/cgendata.nim | 2 ++ compiler/jsgen.nim | 4 ++++ tests/pragmas/tpush.nim | 13 +++++++++++++ 3 files changed, 19 insertions(+) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 4d15cf131b..9cc146c4db 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -196,6 +196,8 @@ proc newProc*(prc: PSym, module: BModule): BProc = result = BProc( prc: prc, module: module, + optionsStack: if module.initProc != nil: module.initProc.optionsStack + else: @[], options: if prc != nil: prc.options else: module.config.options, blocks: @[initBlock()], diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 8be4d9d075..a5f4d29b27 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -50,6 +50,7 @@ type graph: ModuleGraph config: ConfigRef sigConflicts: CountTable[SigHash] + initProc: PProc BModule = ref TJSGen TJSTypeKind = enum # necessary JS "types" @@ -158,6 +159,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode, options: TOptions): PProc = result = PProc( blocks: @[], + optionsStack: if module.initProc != nil: module.initProc.optionsStack + else: @[], options: options, module: module, procDef: procDef, @@ -3036,6 +3039,7 @@ proc processJSCodeGen*(b: PPassContext, n: PNode): PNode = if m.module == nil: internalError(m.config, n.info, "myProcess") let globals = PGlobals(m.graph.backend) var p = newInitProc(globals, m) + m.initProc = p p.unique = globals.unique genModule(p, n) p.g.code.add(p.locals) diff --git a/tests/pragmas/tpush.nim b/tests/pragmas/tpush.nim index f2779ea70f..6d7eade91f 100644 --- a/tests/pragmas/tpush.nim +++ b/tests/pragmas/tpush.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c js" +""" + # test the new pragmas {.push warnings: off, hints: off.} @@ -25,3 +29,12 @@ proc foo(x: string, y: int, res: int) = foo("", 0, 48) foo("abc", 40, 51) + +# bug #22362 +{.push staticBoundChecks: on.} +proc main(): void = + {.pop.} + discard + {.push staticBoundChecks: on.} + +main() From b40da812f7aa590ed16df54a492684c228320549 Mon Sep 17 00:00:00 2001 From: Bung Date: Wed, 2 Aug 2023 20:08:51 +0800 Subject: [PATCH 367/489] fix #22173 `sink` paramers not moved into closure (refc) (#22359) * use genRefAssign when assign to sink string * add test case --- compiler/ccgexprs.nim | 15 +++++++++------ tests/gc/t22173.nim | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 tests/gc/t22173.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 712b874d93..8874f54ae3 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -342,12 +342,15 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config): linefmt(p, cpsStmts, "$1 = #copyString($2);$n", [dest.rdLoc, src.rdLoc]) elif dest.storage == OnHeap: - # we use a temporary to care for the dreaded self assignment: - var tmp: TLoc - getTemp(p, ty, tmp) - linefmt(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);$n", - [dest.rdLoc, src.rdLoc, tmp.rdLoc]) - linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", [tmp.rdLoc]) + if dest.lode.typ.kind == tySink: + genRefAssign(p, dest, src) + else: + # we use a temporary to care for the dreaded self assignment: + var tmp: TLoc + getTemp(p, ty, tmp) + linefmt(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);$n", + [dest.rdLoc, src.rdLoc, tmp.rdLoc]) + linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", [tmp.rdLoc]) else: linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n", [addrLoc(p.config, dest), rdLoc(src)]) diff --git a/tests/gc/t22173.nim b/tests/gc/t22173.nim new file mode 100644 index 0000000000..3fa3cc5038 --- /dev/null +++ b/tests/gc/t22173.nim @@ -0,0 +1,20 @@ +discard """ + cmd: '''nim c --gc:refc -r $file''' +""" +const Memo = 100 * 1024 + +proc fff(v: sink string): iterator(): char = + return iterator(): char = + for c in v: + yield c + +var tmp = newString(Memo) + +let iter = fff(move(tmp)) + +while true: + let v = iter() + if finished(iter): + break + +doAssert getOccupiedMem() < Memo * 3 From 6b913b4741df8c80b2d930643f6dc01300fc1e1e Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 4 Aug 2023 01:56:05 +0800 Subject: [PATCH 368/489] =?UTF-8?q?Revert=20"fix=20#22173=20`sink`=20param?= =?UTF-8?q?ers=20not=20moved=20into=20closure=20(refc)=20(#22=E2=80=A6=20(?= =?UTF-8?q?#22376)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert "fix #22173 `sink` paramers not moved into closure (refc) (#22359)" This reverts commit b40da812f7aa590ed16df54a492684c228320549. --- compiler/ccgexprs.nim | 15 ++++++--------- tests/gc/t22173.nim | 20 -------------------- 2 files changed, 6 insertions(+), 29 deletions(-) delete mode 100644 tests/gc/t22173.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 8874f54ae3..712b874d93 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -342,15 +342,12 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config): linefmt(p, cpsStmts, "$1 = #copyString($2);$n", [dest.rdLoc, src.rdLoc]) elif dest.storage == OnHeap: - if dest.lode.typ.kind == tySink: - genRefAssign(p, dest, src) - else: - # we use a temporary to care for the dreaded self assignment: - var tmp: TLoc - getTemp(p, ty, tmp) - linefmt(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);$n", - [dest.rdLoc, src.rdLoc, tmp.rdLoc]) - linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", [tmp.rdLoc]) + # we use a temporary to care for the dreaded self assignment: + var tmp: TLoc + getTemp(p, ty, tmp) + linefmt(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);$n", + [dest.rdLoc, src.rdLoc, tmp.rdLoc]) + linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", [tmp.rdLoc]) else: linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n", [addrLoc(p.config, dest), rdLoc(src)]) diff --git a/tests/gc/t22173.nim b/tests/gc/t22173.nim deleted file mode 100644 index 3fa3cc5038..0000000000 --- a/tests/gc/t22173.nim +++ /dev/null @@ -1,20 +0,0 @@ -discard """ - cmd: '''nim c --gc:refc -r $file''' -""" -const Memo = 100 * 1024 - -proc fff(v: sink string): iterator(): char = - return iterator(): char = - for c in v: - yield c - -var tmp = newString(Memo) - -let iter = fff(move(tmp)) - -while true: - let v = iter() - if finished(iter): - break - -doAssert getOccupiedMem() < Memo * 3 From 8d8d75706cddc40ff00b163ebd9aa2728afdf7ef Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Thu, 3 Aug 2023 22:49:52 +0200 Subject: [PATCH 369/489] Add experimental inferGenericTypes switch (#22317) * Infer generic bindings * Simple test * Add t * Allow it to work for templates too * Fix some builds by putting bindings in a template * Fix builtins * Slightly more exotic seq test * Test value-based generics using array * Pass expectedType into buildBindings * Put buildBindings into a proc * Manual entry * Remove leftover ` * Improve language used in the manual * Experimental flag and fix basic constructors * Tiny commend cleanup * Move to experimental manual * Use 'kind' so tuples continue to fail like before * Explicitly disallow tuples * Table test and document tuples * Test type reduction * Disable inferGenericTypes check for CI tests * Remove tuple info in manual * Always reduce types. Testing CI * Fixes * Ignore tyGenericInst * Prevent binding already bound generic params * tyUncheckedArray * Few more types * Update manual and check for flag again * Update tests/generics/treturn_inference.nim * var candidate, remove flag check again for CI * Enable check once more --------- Co-authored-by: SirOlaf <> Co-authored-by: Andreas Rumpf --- compiler/options.nim | 3 +- compiler/semcall.nim | 64 +++++++++++- compiler/semdata.nim | 2 +- compiler/semexprs.nim | 10 +- doc/manual_experimental.md | 81 ++++++++++++++++ tests/generics/treturn_inference.nim | 139 +++++++++++++++++++++++++++ 6 files changed, 288 insertions(+), 11 deletions(-) create mode 100644 tests/generics/treturn_inference.nim diff --git a/compiler/options.nim b/compiler/options.nim index 8286a575df..5b61cb049c 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -220,7 +220,8 @@ type unicodeOperators, # deadcode flexibleOptionalParams, strictDefs, - strictCaseObjects + strictCaseObjects, + inferGenericTypes LegacyFeature* = enum allowSemcheckedAstModification, diff --git a/compiler/semcall.nim b/compiler/semcall.nim index d2460ab06d..f0d0f648a6 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -562,8 +562,61 @@ proc getCallLineInfo(n: PNode): TLineInfo = discard result = n.info -proc semResolvedCall(c: PContext, x: TCandidate, - n: PNode, flags: TExprFlags): PNode = +proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) = + ## Helper proc to inherit bound generic parameters from expectedType into x. + ## Does nothing if 'inferGenericTypes' isn't in c.features + if inferGenericTypes notin c.features: return + if expectedType == nil or x.callee[0] == nil: return # required for inference + + var + flatUnbound: seq[PType] + flatBound: seq[PType] + # seq[(result type, expected type)] + var typeStack = newSeq[(PType, PType)]() + + template stackPut(a, b) = + ## skips types and puts the skipped version on stack + # It might make sense to skip here one by one. It's not part of the main + # type reduction because the right side normally won't be skipped + const toSkip = { tyVar, tyLent, tyStatic, tyCompositeTypeClass } + let + x = a.skipTypes(toSkip) + y = if a.kind notin toSkip: b + else: b.skipTypes(toSkip) + typeStack.add((x, y)) + + stackPut(x.callee[0], expectedType) + + while typeStack.len() > 0: + let (t, u) = typeStack.pop() + if t == u or t == nil or u == nil or t.kind == tyAnything or u.kind == tyAnything: + continue + case t.kind + of ConcreteTypes, tyGenericInvocation, tyUncheckedArray: + # nested, add all the types to stack + let + startIdx = if u.kind in ConcreteTypes: 0 else: 1 + endIdx = min(u.sons.len() - startIdx, t.sons.len()) + + for i in startIdx ..< endIdx: + # early exit with current impl + if t[i] == nil or u[i] == nil: return + stackPut(t[i], u[i]) + of tyGenericParam: + if x.bindings.idTableGet(t) != nil: return + + # fully reduced generic param, bind it + if t notin flatUnbound: + flatUnbound.add(t) + flatBound.add(u) + else: + discard + for i in 0 ..< flatUnbound.len(): + x.bindings.idTablePut(flatUnbound[i], flatBound[i]) + +proc semResolvedCall(c: PContext, x: var TCandidate, + n: PNode, flags: TExprFlags; + expectedType: PType = nil): PNode = assert x.state == csMatch var finalCallee = x.calleeSym let info = getCallLineInfo(n) @@ -583,10 +636,12 @@ proc semResolvedCall(c: PContext, x: TCandidate, if x.calleeSym.magic in {mArrGet, mArrPut}: finalCallee = x.calleeSym else: + c.inheritBindings(x, expectedType) finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info) else: # For macros and templates, the resolved generic params # are added as normal params. + c.inheritBindings(x, expectedType) for s in instantiateGenericParamList(c, gp, x.bindings): case s.kind of skConst: @@ -615,7 +670,8 @@ proc tryDeref(n: PNode): PNode = result.add n proc semOverloadedCall(c: PContext, n, nOrig: PNode, - filter: TSymKinds, flags: TExprFlags): PNode = + filter: TSymKinds, flags: TExprFlags; + expectedType: PType = nil): PNode = 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: @@ -625,7 +681,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, message(c.config, n.info, hintUserRaw, "Non-matching candidates for " & renderTree(n) & "\n" & candidates) - result = semResolvedCall(c, r, n, flags) + result = semResolvedCall(c, r, n, flags, expectedType) else: if efDetermineType in flags and c.inGenericContext > 0 and c.matchedConcept == nil: result = semGenericStmt(c, n) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index ddd8d33efd..a85f8e6387 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -135,7 +135,7 @@ type semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.} semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, - filter: TSymKinds, flags: TExprFlags): PNode {.nimcall.} + filter: TSymKinds, flags: TExprFlags, expectedType: PType = nil): PNode {.nimcall.} semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.} semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable, diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c6be3e833c..398424bbf4 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -952,17 +952,17 @@ proc semStaticExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode = result = fixupTypeAfterEval(c, result, a) proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, - flags: TExprFlags): PNode = + flags: TExprFlags; expectedType: PType = nil): PNode = if flags*{efInTypeof, efWantIterator, efWantIterable} != {}: # consider: 'for x in pReturningArray()' --> we don't want the restriction # to 'skIterator' anymore; skIterator is preferred in sigmatch already # for typeof support. # for ``typeof(countup(1,3))``, see ``tests/ttoseq``. result = semOverloadedCall(c, n, nOrig, - {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate, skIterator}, flags) + {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate, skIterator}, flags, expectedType) else: result = semOverloadedCall(c, n, nOrig, - {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}, flags) + {skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}, flags, expectedType) if result != nil: if result[0].kind != nkSym: @@ -1138,7 +1138,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = # this seems to be a hotspot in the compiler! let nOrig = n.copyTree #semLazyOpAux(c, n) - result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) + result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags, expectedType) if result != nil: result = afterCallActions(c, result, nOrig, flags, expectedType) else: result = errorNode(c, n) @@ -3120,7 +3120,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType elif s.magic == mNone: result = semDirectOp(c, n, flags, expectedType) else: result = semMagic(c, n, s, flags, expectedType) of skProc, skFunc, skMethod, skConverter, skIterator: - if s.magic == mNone: result = semDirectOp(c, n, flags) + if s.magic == mNone: result = semDirectOp(c, n, flags, expectedType) else: result = semMagic(c, n, s, flags, expectedType) else: #liMessage(n.info, warnUser, renderTree(n)); diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 602ca46a58..4ee035b65d 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -124,6 +124,87 @@ would not match the type of the variable, and an error would be given. The extent of this varies, but there are some notable special cases. + +Inferred generic parameters +--------------------------- + +In expressions making use of generic procs or templates, the expected +(unbound) types are often able to be inferred based on context. +This feature has to be enabled via `{.experimental: "inferGenericTypes".}` + + ```nim test = "nim c $1" + {.experimental: "inferGenericTypes".} + + import std/options + + var x = newSeq[int](1) + # Do some work on 'x'... + + # Works! + # 'x' is 'seq[int]' so 'newSeq[int]' is implied + x = newSeq(10) + + # Works! + # 'T' of 'none' is bound to the 'T' of 'noneProducer', passing it along. + # Effectively 'none.T = noneProducer.T' + proc noneProducer[T](): Option[T] = none() + let myNone = noneProducer[int]() + + # Also works + # 'myOtherNone' binds its 'T' to 'float' and 'noneProducer' inherits it + # noneProducer.T = myOtherNone.T + let myOtherNone: Option[float] = noneProducer() + + # Works as well + # none.T = myOtherOtherNone.T + let myOtherOtherNone: Option[int] = none() + ``` + +This is achieved by reducing the types on the lhs and rhs until the *lhs* is left with only types such as `T`. +While lhs and rhs are reduced together, this does *not* mean that the *rhs* will also only be left +with a flat type `Z`, it may be of the form `MyType[Z]`. + +After the types have been reduced, the types `T` are bound to the types that are left on the rhs. + +If bindings *cannot be inferred*, compilation will fail and manual specification is required. + +An example for *failing inference* can be found when passing a generic expression +to a function/template call: + + ```nim test = "nim c $1" status = 1 + {.experimental: "inferGenericTypes".} + + proc myProc[T](a, b: T) = discard + + # Fails! Unable to infer that 'T' is supposed to be 'int' + myProc(newSeq[int](), newSeq(1)) + + # Works! Manual specification of 'T' as 'int' necessary + myProc(newSeq[int](), newSeq[int](1)) + ``` + +Combination of generic inference with the `auto` type is also unsupported: + + ```nim test = "nim c $1" status = 1 + {.experimental: "inferGenericTypes".} + + proc produceValue[T]: auto = default(T) + let a: int = produceValue() # 'auto' cannot be inferred here + ``` + +**Note**: The described inference does not permit the creation of overrides based on +the return type of a procedure. It is a mapping mechanism that does not attempt to +perform deeper inference, nor does it modify what is a valid override. + + ```nim test = "nim c $1" status = 1 + # Doesn't affect the following code, it is invalid either way + {.experimental: "inferGenericTypes".} + + proc a: int = 0 + proc a: float = 1.0 # Fails! Invalid code and not recommended + ``` + + Sequence literals ----------------- diff --git a/tests/generics/treturn_inference.nim b/tests/generics/treturn_inference.nim new file mode 100644 index 0000000000..05d38cef48 --- /dev/null +++ b/tests/generics/treturn_inference.nim @@ -0,0 +1,139 @@ + +{.experimental: "inferGenericTypes".} + +import std/tables + +block: + type + MyOption[T, Z] = object + x: T + y: Z + + proc none[T, Z](): MyOption[T, Z] = + when T is int: + result.x = 22 + when Z is float: + result.y = 12.0 + + proc myGenericProc[T, Z](): MyOption[T, Z] = + none() # implied by return type + + let a = myGenericProc[int, float]() + doAssert a.x == 22 + doAssert a.y == 12.0 + + let b: MyOption[int, float] = none() # implied by type of b + doAssert b.x == 22 + doAssert b.y == 12.0 + +# Simple template based result with inferred type for errors +block: + type + ResultKind {.pure.} = enum + Ok + Err + + Result[T] = object + case kind: ResultKind + of Ok: + data: T + of Err: + errmsg: cstring + + template err[T](msg: static cstring): Result[T] = + Result[T](kind : ResultKind.Err, errmsg : msg) + + proc testproc(): Result[int] = + err("Inferred error!") # implied by proc return + let r = testproc() + doAssert r.kind == ResultKind.Err + doAssert r.errmsg == "Inferred error!" + +# Builtin seq +block: + let x: seq[int] = newSeq(1) + doAssert x is seq[int] + doAssert x.len() == 1 + + type + MyType[T, Z] = object + x: T + y: Z + + let y: seq[MyType[int, float]] = newSeq(2) + doAssert y is seq[MyType[int, float]] + doAssert y.len() == 2 + + let z = MyType[seq[float], string]( + x : newSeq(3), + y : "test" + ) + doAssert z.x is seq[float] + doAssert z.x.len() == 3 + doAssert z.y is string + doAssert z.y == "test" + +# array +block: + proc giveArray[N, T](): array[N, T] = + for i in 0 .. N.high: + result[i] = i + var x: array[2, int] = giveArray() + doAssert x == [0, 1] + +# tuples +block: + proc giveTuple[T, Z]: (T, Z, T) = discard + let x: (int, float, int) = giveTuple() + doAssert x is (int, float, int) + doAssert x == (0, 0.0, 0) + + proc giveNamedTuple[T, Z]: tuple[a: T, b: Z] = discard + let y: tuple[a: int, b: float] = giveNamedTuple() + doAssert y is (int, float) + doAssert y is tuple[a: int, b: float] + doAssert y == (0, 0.0) + + proc giveNestedTuple[T, Z]: ((T, Z), Z) = discard + let z: ((int, float), float) = giveNestedTuple() + doAssert z is ((int, float), float) + doAssert z == ((0, 0.0), 0.0) + + # nesting inside a generic type + type MyType[T] = object + x: T + let a = MyType[(int, MyType[float])](x : giveNamedTuple()) + doAssert a.x is (int, MyType[float]) + + +# basic constructors +block: + type MyType[T] = object + x: T + + proc giveValue[T](): T = + when T is int: + 12 + else: + default(T) + + let x = MyType[int](x : giveValue()) + doAssert x.x is int + doAssert x.x == 12 + + let y = MyType[MyType[float]](x : MyType[float](x : giveValue())) + doAssert y.x is MyType[float] + doAssert y.x.x is float + doAssert y.x.x == 0.0 + + # 'MyType[float]' is bound to 'T' directly + # instead of mapping 'T' to 'float' + let z = MyType[MyType[float]](x : giveValue()) + doAssert z.x is MyType[float] + doAssert z.x.x == 0.0 + + type Foo = object + x: Table[int, float] + + let a = Foo(x: initTable()) + doAssert a.x is Table[int, float] \ No newline at end of file From 14bc3f32683c87f971bf23ae30d500dc89cdebb8 Mon Sep 17 00:00:00 2001 From: awr1 <41453959+awr1@users.noreply.github.com> Date: Thu, 3 Aug 2023 14:06:30 -0700 Subject: [PATCH 370/489] Allow `libffi` to work via `koch boot` (#22322) * Divert libffi from nimble path, impl into koch * Typo in koch * Update options.nim comment * Fix CI Test * Update changelog * Clarify libffi nimble comment * Future pending changelog --------- Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- changelogs/changelog_2_2_0.md | 14 ++++++++++++ compiler/evalffi.nim | 2 +- compiler/options.nim | 2 +- koch.nim | 42 ++++++++++++++++++++++++----------- 4 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 changelogs/changelog_2_2_0.md diff --git a/changelogs/changelog_2_2_0.md b/changelogs/changelog_2_2_0.md new file mode 100644 index 0000000000..97b9e6c052 --- /dev/null +++ b/changelogs/changelog_2_2_0.md @@ -0,0 +1,14 @@ +# v2.2.1 - 2023-mm-dd + +## Changes affecting backward compatibility + +## Standard library additions and changes + +## Language changes + +## Compiler changes + +## Tool changes + +- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package in tow. + diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index 0577619b89..0112aebb91 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -11,7 +11,7 @@ import ast, types, options, tables, dynlib, msgs, lineinfos from os import getAppFilename -import pkg/libffi +import libffi/libffi when defined(windows): const libcDll = "msvcrt.dll" diff --git a/compiler/options.nim b/compiler/options.nim index 5b61cb049c..5a862ca4b0 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -209,7 +209,7 @@ type codeReordering, compiletimeFFI, ## This requires building nim with `-d:nimHasLibFFI` - ## which itself requires `nimble install libffi`, see #10150 + ## which itself requires `koch installdeps libffi`, see #10150 ## Note: this feature can't be localized with {.push.} vmopsDanger, strictFuncs, diff --git a/koch.nim b/koch.nim index a10e01dbbe..8e94b51507 100644 --- a/koch.nim +++ b/koch.nim @@ -85,6 +85,9 @@ Boot options: -d:leanCompiler produce a compiler without JS codegen or documentation generator in order to use less RAM for bootstrapping + -d:nimHasLibFFI adds FFI support for allowing compile-time VM to + interface with native functions (experimental, + requires prior `koch installdeps libffi`) Commands for core developers: runCI runs continuous integration (CI), e.g. from Github Actions @@ -278,6 +281,22 @@ proc install(args: string) = geninstall() exec("sh ./install.sh $#" % args) +proc installDeps(dep: string, commit = "") = + # the hashes/urls are version controlled here, so can be changed seamlessly + # and tied to a nim release (mimicking git submodules) + var commit = commit + case dep + of "tinyc": + if commit.len == 0: commit = "916cc2f94818a8a382dd8d4b8420978816c1dfb3" + cloneDependency(distDir, "https://github.com/timotheecour/nim-tinyc-archive", commit) + of "libffi": + # technically a nimble package, however to play nicely with --noNimblePath, + # let's just clone it wholesale: + if commit.len == 0: commit = "bb2bdaf1a29a4bff6fbd8ae4695877cbb3ec783e" + cloneDependency(distDir, "https://github.com/Araq/libffi", commit) + else: doAssert false, "unsupported: " & dep + # xxx: also add linenoise, niminst etc, refs https://github.com/nim-lang/RFCs/issues/206 + # -------------- boot --------------------------------------------------------- proc findStartNim: string = @@ -323,6 +342,10 @@ proc boot(args: string, skipIntegrityCheck: bool) = if not dirExists("dist/checksums"): bundleChecksums(false) + let usingLibFFI = "nimHasLibFFI" in args + if usingLibFFI and not dirExists("dist/libffi"): + installDeps("libffi") + let nimStart = findStartNim().quoteShell() let times = 2 - ord(skipIntegrityCheck) for i in 0..times: @@ -334,6 +357,10 @@ proc boot(args: string, skipIntegrityCheck: bool) = if i == 0: nimi = nimStart extraOption.add " --skipUserCfg --skipParentCfg -d:nimKochBootstrap" + + # --noNimblePath precludes nimble packages as dependencies to the compiler, + # so libffi is not "installed as a nimble package" + if usingLibFFI: extraOption.add " --path:./dist" # The configs are skipped for bootstrap # (1st iteration) to prevent newer flags from breaking bootstrap phase. let ret = execCmdEx(nimStart & " --version") @@ -548,17 +575,6 @@ proc hostInfo(): string = "hostOS: $1, hostCPU: $2, int: $3, float: $4, cpuEndian: $5, cwd: $6" % [hostOS, hostCPU, $int.sizeof, $float.sizeof, $cpuEndian, getCurrentDir()] -proc installDeps(dep: string, commit = "") = - # the hashes/urls are version controlled here, so can be changed seamlessly - # and tied to a nim release (mimicking git submodules) - var commit = commit - case dep - of "tinyc": - if commit.len == 0: commit = "916cc2f94818a8a382dd8d4b8420978816c1dfb3" - cloneDependency(distDir, "https://github.com/timotheecour/nim-tinyc-archive", commit) - else: doAssert false, "unsupported: " & dep - # xxx: also add linenoise, niminst etc, refs https://github.com/nim-lang/RFCs/issues/206 - proc runCI(cmd: string) = doAssert cmd.len == 0, cmd # avoid silently ignoring echo "runCI: ", cmd @@ -602,11 +618,11 @@ proc runCI(cmd: string) = block: # nimHasLibFFI: when defined(posix): # windows can be handled in future PR's - execFold("nimble install -y libffi", "nimble install -y libffi") + installDeps("libffi") const nimFFI = "bin/nim.ctffi" # no need to bootstrap with koch boot (would be slower) let backend = if doUseCpp(): "cpp" else: "c" - execFold("build with -d:nimHasLibFFI", "nim $1 -d:release -d:nimHasLibFFI -o:$2 compiler/nim.nim" % [backend, nimFFI]) + execFold("build with -d:nimHasLibFFI", "nim $1 -d:release --noNimblePath -d:nimHasLibFFI --path:./dist -o:$2 compiler/nim.nim" % [backend, nimFFI]) execFold("test with -d:nimHasLibFFI", "$1 $2 -r testament/testament --nim:$1 r tests/misc/trunner.nim -d:nimTrunnerFfi" % [nimFFI, backend]) execFold("Run nimdoc tests", "nim r nimdoc/tester") From d37b620757c0a4987ee349f246df30def8613b9b Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Fri, 4 Aug 2023 05:29:48 +0200 Subject: [PATCH 371/489] Make `repr(HSlice)` always available (#22332) Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- lib/system.nim | 10 ++++++++++ lib/system/repr_v2.nim | 10 ---------- tests/stdlib/trepr.nim | 6 ++++-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 25133fca50..1bf1c5ccb4 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2405,6 +2405,16 @@ when defined(nimV2): import system/repr_v2 export repr_v2 +proc repr*[T, U](x: HSlice[T, U]): string = + ## Generic `repr` operator for slices that is lifted from the components + ## of `x`. Example: + ## + ## .. code-block:: Nim + ## $(1 .. 5) == "1 .. 5" + result = repr(x.a) + result.add(" .. ") + result.add(repr(x.b)) + when hasAlloc or defined(nimscript): proc insert*(x: var string, item: string, i = 0.Natural) {.noSideEffect.} = ## Inserts `item` into `x` at position `i`. diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index e9a6596fd3..3a40ac5ad7 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -177,16 +177,6 @@ proc repr*[T](x: seq[T]): string = ## $(@[23, 45]) == "@[23, 45]" collectionToRepr(x, "@[", ", ", "]") -proc repr*[T, U](x: HSlice[T, U]): string = - ## Generic `repr` operator for slices that is lifted from the components - ## of `x`. Example: - ## - ## .. code-block:: Nim - ## $(1 .. 5) == "1 .. 5" - result = repr(x.a) - result.add(" .. ") - result.add(repr(x.b)) - proc repr*[T, IDX](x: array[IDX, T]): string = ## Generic `repr` operator for arrays that is lifted from the components. collectionToRepr(x, "[", ", ", "]") diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim index a8c62ea55b..3956b98f95 100644 --- a/tests/stdlib/trepr.nim +++ b/tests/stdlib/trepr.nim @@ -40,7 +40,7 @@ template main() = #[ BUG: --gc:arc returns `"abc"` - regular gc returns with address, e.g. 0x1068aae60"abc", but only + regular gc returns with address, e.g. 0x1068aae60"abc", but only for c,cpp backends (not js, vm) ]# block: @@ -293,7 +293,7 @@ func fn2(): int = *a: b do: c - + doAssert a == """foo(a, b, (c, d)): e f @@ -322,5 +322,7 @@ else: do: c""" + doAssert repr(1..2) == "1 .. 2" + static: main() main() From fb7acd66001a5f1bc018e1e1e9b1ebc792462e50 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 4 Aug 2023 15:08:41 +0800 Subject: [PATCH 372/489] follow up #22322; fixes changelog (#22381) --- changelog.md | 4 ++-- changelogs/changelog_2_2_0.md | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 100d12fd72..b4b8ca532d 100644 --- a/changelog.md +++ b/changelog.md @@ -24,7 +24,7 @@ ## Compiler changes - - ## Tool changes +- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package in tow. + diff --git a/changelogs/changelog_2_2_0.md b/changelogs/changelog_2_2_0.md index 97b9e6c052..341f41045a 100644 --- a/changelogs/changelog_2_2_0.md +++ b/changelogs/changelog_2_2_0.md @@ -10,5 +10,3 @@ ## Tool changes -- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package in tow. - From 7c2a2c8dc810a837b93ee0e8bcaf6d8969f5a54a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:00:00 +0800 Subject: [PATCH 373/489] fixes a typo in the manual (#22383) ref https://github.com/nim-lang/Nim/commit/0d3bde95f578576d2e84d422d5694ee0e0055cbc#commitcomment-122093273 --- doc/manual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.md b/doc/manual.md index 45eb8fef56..fba905bb9c 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -5517,7 +5517,7 @@ type Foo[T] = object proc p[H;T: Foo[H]](param: T): H ``` -A constraint definition may have more than one symbol defined by seperating each definition by +A constraint definition may have more than one symbol defined by separating each definition by a `;`. Notice how `T` is composed of `H` and the return type of `p` is defined as `H`. When this generic proc is instantiated `H` will be bound to a concrete type, thus making `T` concrete and the return type of `p` will be bound to the same concrete type used to define `H`. From 3efabd3ec669914ad2bb42a614f7277caf662562 Mon Sep 17 00:00:00 2001 From: Jake Leahy Date: Fri, 4 Aug 2023 20:21:36 +1000 Subject: [PATCH 374/489] Fix crash when using uninstantiated generic (#22379) * Add test case * Add in a bounds check when accessing generic types Removes idnex out of bounds exception when comparing a generic that isn't fully instantiated --- compiler/sigmatch.nim | 2 ++ tests/generics/tuninstantiated_failure.nim | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/generics/tuninstantiated_failure.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 4aa51977ab..d1b3b5dfb4 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1536,6 +1536,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if x.kind == tyGenericInvocation: if f[0] == x[0]: for i in 1..= x.len: return let tr = typeRel(c, f[i], x[i], flags) if tr <= isSubtype: return result = isGeneric diff --git a/tests/generics/tuninstantiated_failure.nim b/tests/generics/tuninstantiated_failure.nim new file mode 100644 index 0000000000..f09b115d65 --- /dev/null +++ b/tests/generics/tuninstantiated_failure.nim @@ -0,0 +1,16 @@ +discard """ +cmd: "nim check $file" +""" + +type + Test[T, K] = object + name: string + Something = Test[int] + +func `[]`[T, K](x: var Test[T, K], idx: int): var Test[T, K] = + x + +var b: Something +# Should give a type-mismatch since Something isn't a valid Test +b[0].name = "Test" #[tt.Error + ^ type mismatch]# From 26f183043f9e58eb4954d50a5d130d8684909936 Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 4 Aug 2023 19:35:43 +0800 Subject: [PATCH 375/489] fix #20883 Unspecified generic on default value segfaults the compiler (#21172) * fix #20883 Unspecified generic on default value segfaults the compiler * fallback to isGeneric * change to closer error * Update t20883.nim --- compiler/semexprs.nim | 3 +++ compiler/sigmatch.nim | 5 +++++ tests/misc/t20883.nim | 12 ++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 tests/misc/t20883.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 398424bbf4..b7fc7a9bd8 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -238,6 +238,9 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus = result = convNotInRange else: # we use d, s here to speed up that operation a bit: + if d.kind == tyFromExpr: + result = convNotLegal + return case cmpTypes(c, d, s) of isNone, isGeneric: if not compareTypes(targetTyp.skipTypes(abstractVar), srcTyp.skipTypes({tyOwned}), dcEqIgnoreDistinct): diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index d1b3b5dfb4..12cc1fcb12 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -819,6 +819,8 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode, # This proc is used to evaluate such static expressions. let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil, allowMetaTypes = allowUnresolved) + if instantiated.kind in nkCallKinds: + return nil result = c.c.semExpr(c.c, instantiated) proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool = @@ -1887,6 +1889,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # fix the expression, so it contains the already instantiated types if f.n == nil or f.n.kind == nkEmpty: return isGeneric let reevaluated = tryResolvingStaticExpr(c, f.n) + if reevaluated == nil: + result = isNone + return case reevaluated.typ.kind of tyTypeDesc: result = typeRel(c, a, reevaluated.typ.base, flags) diff --git a/tests/misc/t20883.nim b/tests/misc/t20883.nim new file mode 100644 index 0000000000..d98feaa141 --- /dev/null +++ b/tests/misc/t20883.nim @@ -0,0 +1,12 @@ +discard """ + action: reject + errormsg: "type mismatch: got but expected 'typeof(U(0.000001))'" + line: 8 + column: 22 +""" + +proc foo*[U](x: U = U(1e-6)) = + echo x + +foo[float]() +foo() From 73a29d72e347817a239f097c8185842e5bdca149 Mon Sep 17 00:00:00 2001 From: norrath-hero-cn <73905273+norrath-hero-cn@users.noreply.github.com> Date: Sat, 5 Aug 2023 01:59:05 +0800 Subject: [PATCH 376/489] fixes AddressSanitizer: global-buffer-overflow in getAppFilename on windows 10 (#22380) fixes AddressSanitizer: global-buffer-overflow --- lib/pure/os.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 434fc3a26e..13c6d6113a 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -638,14 +638,14 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW # /proc//path/a.out (complete pathname) when defined(windows): var bufsize = int32(MAX_PATH) - var buf = newWideCString("", bufsize) + var buf = newWideCString(bufsize) while true: var L = getModuleFileNameW(0, buf, bufsize) if L == 0'i32: result = "" # error! break elif L > bufsize: - buf = newWideCString("", L) + buf = newWideCString(L) bufsize = L else: result = buf$L From db435a4a797adbbd4dd42edf89267902c0b2e34f Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Sat, 5 Aug 2023 03:00:43 +0900 Subject: [PATCH 377/489] Fix searchExtPos so that it returns -1 when the path is not a file ext (#22245) * Fix searchExtPos so that it returns -1 when the path is not a file ext * fix comparision expression * Remove splitDrive from searchExtPos --- lib/std/private/ospaths2.nim | 21 +++++++++++++++++---- tests/stdlib/tos.nim | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/lib/std/private/ospaths2.nim b/lib/std/private/ospaths2.nim index 612003023c..18a01b1049 100644 --- a/lib/std/private/ospaths2.nim +++ b/lib/std/private/ospaths2.nim @@ -584,15 +584,28 @@ proc searchExtPos*(path: string): int = assert searchExtPos("c.nim") == 1 assert searchExtPos("a/b/c.nim") == 5 assert searchExtPos("a.b.c.nim") == 5 + assert searchExtPos(".nim") == -1 + assert searchExtPos("..nim") == -1 + assert searchExtPos("a..nim") == 2 - # BUGFIX: do not search until 0! .DS_Store is no file extension! + # Unless there is any char that is not `ExtSep` before last `ExtSep` in the file name, + # it is not a file extension. + const DirSeps = when doslikeFileSystem: {DirSep, AltSep, ':'} else: {DirSep, AltSep} result = -1 - for i in countdown(len(path)-1, 1): + var i = path.high + while i >= 1: if path[i] == ExtSep: + break + elif path[i] in DirSeps: + return -1 # do not skip over path + dec i + + for j in countdown(i - 1, 0): + if path[j] in DirSeps: + return -1 + elif path[j] != ExtSep: result = i break - elif path[i] in {DirSep, AltSep}: - break # do not skip over path proc splitFile*(path: string): tuple[dir, name, ext: string] {. noSideEffect, rtl, extern: "nos$1".} = diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index c2822d2707..ad34e479a9 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -830,3 +830,35 @@ block: # isValidFilename doAssert isValidFilename("ux.bat") doAssert isValidFilename("nim.nim") doAssert isValidFilename("foo.log") + +block: # searchExtPos + doAssert "foo.nim".searchExtPos == 3 + doAssert "/foo.nim".searchExtPos == 4 + doAssert "".searchExtPos == -1 + doAssert "/".searchExtPos == -1 + doAssert "a.b/foo".searchExtPos == -1 + doAssert ".".searchExtPos == -1 + doAssert "foo.".searchExtPos == 3 + doAssert "foo..".searchExtPos == 4 + doAssert "..".searchExtPos == -1 + doAssert "...".searchExtPos == -1 + doAssert "./".searchExtPos == -1 + doAssert "../".searchExtPos == -1 + doAssert "/.".searchExtPos == -1 + doAssert "/..".searchExtPos == -1 + doAssert ".b".searchExtPos == -1 + doAssert "..b".searchExtPos == -1 + doAssert "/.b".searchExtPos == -1 + doAssert "a/.b".searchExtPos == -1 + doAssert ".a.b".searchExtPos == 2 + doAssert "a/.b.c".searchExtPos == 4 + doAssert "a/..b".searchExtPos == -1 + doAssert "a/b..c".searchExtPos == 4 + + when doslikeFileSystem: + doAssert "c:a.b".searchExtPos == 3 + doAssert "c:.a".searchExtPos == -1 + doAssert r"c:\.a".searchExtPos == -1 + doAssert "c:..a".searchExtPos == -1 + doAssert r"c:\..a".searchExtPos == -1 + doAssert "c:.a.b".searchExtPos == 4 From 873eaa3f65f9ef96f3dc4430e8938d273f04f8e9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 4 Aug 2023 22:52:31 +0200 Subject: [PATCH 378/489] compiler/llstream: modern code for llstream (#22385) --- compiler/llstream.nim | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 004d990faf..bad28eb12c 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -40,33 +40,22 @@ type PLLStream* = ref TLLStream -proc llStreamOpen*(data: string): PLLStream = - new(result) - result.s = data - result.kind = llsString +proc llStreamOpen*(data: sink string): PLLStream = + PLLStream(kind: llsString, s: data) proc llStreamOpen*(f: File): PLLStream = - new(result) - result.f = f - result.kind = llsFile + PLLStream(kind: llsFile, f: f) proc llStreamOpen*(filename: AbsoluteFile, mode: FileMode): PLLStream = - new(result) - result.kind = llsFile + result = PLLStream(kind: llsFile) if not open(result.f, filename.string, mode): result = nil proc llStreamOpen*(): PLLStream = - new(result) - result.kind = llsNone + PLLStream(kind: llsNone) proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int proc llStreamOpenStdIn*(r: TLLRepl = llReadFromStdin, onPrompt: OnPrompt = nil): PLLStream = - new(result) - result.kind = llsStdIn - result.s = "" - result.lineOffset = -1 - result.repl = r - result.onPrompt = onPrompt + PLLStream(kind: llsStdIn, s: "", lineOffset: -1, repl: r, onPrompt: onPrompt) proc llStreamClose*(s: PLLStream) = case s.kind From e15e19308ea3f85ee746cd2946f9acde94b71e34 Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Sat, 5 Aug 2023 18:38:46 +0200 Subject: [PATCH 379/489] Revert adding generic `V: Ordinal` parameter to `succ`, `pred`, `inc`, `dec` (#22328) * Use `int` in `digitsutils`, `dragonbox`, `schubfach` * Fix error message --- lib/std/private/digitsutils.nim | 4 ++-- lib/std/private/dragonbox.nim | 10 +++++----- lib/std/private/schubfach.nim | 8 ++++---- lib/system/arithmetics.nim | 10 +++++----- tests/varres/tprevent_forloopvar_mutations.nim | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim index e051e52183..55ace35001 100644 --- a/lib/std/private/digitsutils.nim +++ b/lib/std/private/digitsutils.nim @@ -33,8 +33,8 @@ proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} buf[pos+1] = digits100[2 * digits + 1] #copyMem(buf, unsafeAddr(digits100[2 * digits]), 2 * sizeof((char))) -proc trailingZeros2Digits*(digits: uint32): int32 {.inline.} = - return trailingZeros100[digits.int8] +proc trailingZeros2Digits*(digits: uint32): int {.inline.} = + trailingZeros100[digits] when defined(js): proc numToString(a: SomeInteger): cstring {.importjs: "((#) + \"\")".} diff --git a/lib/std/private/dragonbox.nim b/lib/std/private/dragonbox.nim index e39ffd9a3a..85ffea84a2 100644 --- a/lib/std/private/dragonbox.nim +++ b/lib/std/private/dragonbox.nim @@ -1052,7 +1052,7 @@ when false: proc memset(x: cstring; ch: char; L: int) {.importc, nodecl.} proc memmove(a, b: cstring; L: int) {.importc, nodecl.} -proc utoa8DigitsSkipTrailingZeros*(buf: var openArray[char]; pos: int; digits: uint32): int32 {.inline.} = +proc utoa8DigitsSkipTrailingZeros*(buf: var openArray[char]; pos: int; digits: uint32): int {.inline.} = dragonbox_Assert(digits >= 1) dragonbox_Assert(digits <= 99999999'u32) let q: uint32 = digits div 10000 @@ -1070,12 +1070,12 @@ proc utoa8DigitsSkipTrailingZeros*(buf: var openArray[char]; pos: int; digits: u utoa2Digits(buf, pos + 6, rL) return trailingZeros2Digits(if rL == 0: rH else: rL) + (if rL == 0: 2 else: 0) -proc printDecimalDigitsBackwards*(buf: var openArray[char]; pos: int; output64: uint64): int32 {.inline.} = +proc printDecimalDigitsBackwards*(buf: var openArray[char]; pos: int; output64: uint64): int {.inline.} = var pos = pos var output64 = output64 - var tz: int32 = 0 + var tz = 0 ## number of trailing zeros removed. - var nd: int32 = 0 + var nd = 0 ## number of decimal digits processed. ## At most 17 digits remaining if output64 >= 100000000'u64: @@ -1220,7 +1220,7 @@ proc formatDigits*[T: Ordinal](buffer: var openArray[char]; pos: T; digits: uint ## dE+123 or d.igitsE+123 decimalDigitsPosition = 1 var digitsEnd = pos + int(decimalDigitsPosition + numDigits) - let tz: int32 = printDecimalDigitsBackwards(buffer, digitsEnd, digits) + let tz = printDecimalDigitsBackwards(buffer, digitsEnd, digits) dec(digitsEnd, tz) dec(numDigits, tz) ## decimal_exponent += tz; // => decimal_point unchanged. diff --git a/lib/std/private/schubfach.nim b/lib/std/private/schubfach.nim index 194fb4bfab..b8c85d2bc7 100644 --- a/lib/std/private/schubfach.nim +++ b/lib/std/private/schubfach.nim @@ -244,12 +244,12 @@ proc toDecimal32(ieeeSignificand: uint32; ieeeExponent: uint32): FloatingDecimal ## ToChars ## ================================================================================================== -proc printDecimalDigitsBackwards[T: Ordinal](buf: var openArray[char]; pos: T; output: uint32): int32 {.inline.} = +proc printDecimalDigitsBackwards[T: Ordinal](buf: var openArray[char]; pos: T; output: uint32): int {.inline.} = var output = output var pos = pos - var tz: int32 = 0 + var tz = 0 ## number of trailing zeros removed. - var nd: int32 = 0 + var nd = 0 ## number of decimal digits processed. ## At most 9 digits remaining if output >= 10000: @@ -355,7 +355,7 @@ proc formatDigits[T: Ordinal](buffer: var openArray[char]; pos: T; digits: uint3 ## dE+123 or d.igitsE+123 decimalDigitsPosition = 1 var digitsEnd = pos + decimalDigitsPosition + numDigits - let tz: int32 = printDecimalDigitsBackwards(buffer, digitsEnd, digits) + let tz = printDecimalDigitsBackwards(buffer, digitsEnd, digits) dec(digitsEnd, tz) dec(numDigits, tz) ## decimal_exponent += tz; // => decimal_point unchanged. diff --git a/lib/system/arithmetics.nim b/lib/system/arithmetics.nim index a1cb935ce0..fa7ca784d7 100644 --- a/lib/system/arithmetics.nim +++ b/lib/system/arithmetics.nim @@ -1,4 +1,4 @@ -proc succ*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Succ", noSideEffect.} = +proc succ*[T: Ordinal](x: T, y: int = 1): T {.magic: "Succ", noSideEffect.} = ## Returns the `y`-th successor (default: 1) of the value `x`. ## ## If such a value does not exist, `OverflowDefect` is raised @@ -7,7 +7,7 @@ proc succ*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Succ", noSideEffect.} = assert succ(5) == 6 assert succ(5, 3) == 8 -proc pred*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Pred", noSideEffect.} = +proc pred*[T: Ordinal](x: T, y: int = 1): T {.magic: "Pred", noSideEffect.} = ## Returns the `y`-th predecessor (default: 1) of the value `x`. ## ## If such a value does not exist, `OverflowDefect` is raised @@ -16,7 +16,7 @@ proc pred*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Pred", noSideEffect.} = assert pred(5) == 4 assert pred(5, 3) == 2 -proc inc*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Inc", noSideEffect.} = +proc inc*[T: Ordinal](x: var T, y: int = 1) {.magic: "Inc", noSideEffect.} = ## Increments the ordinal `x` by `y`. ## ## If such a value does not exist, `OverflowDefect` is raised or a compile @@ -28,7 +28,7 @@ proc inc*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Inc", noSideEffect.} = inc(i, 3) assert i == 6 -proc dec*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Dec", noSideEffect.} = +proc dec*[T: Ordinal](x: var T, y: int = 1) {.magic: "Dec", noSideEffect.} = ## Decrements the ordinal `x` by `y`. ## ## If such a value does not exist, `OverflowDefect` is raised or a compile @@ -93,7 +93,7 @@ proc `*`*(x, y: int16): int16 {.magic: "MulI", noSideEffect.} proc `*`*(x, y: int32): int32 {.magic: "MulI", noSideEffect.} proc `*`*(x, y: int64): int64 {.magic: "MulI", noSideEffect.} -proc `div`*(x, y: int): int {.magic: "DivI", noSideEffect.} = +proc `div`*(x, y: int): int {.magic: "DivI", noSideEffect.} = ## Computes the integer division. ## ## This is roughly the same as `math.trunc(x/y).int`. diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim index c9aeb94d8f..b27c327a93 100644 --- a/tests/varres/tprevent_forloopvar_mutations.nim +++ b/tests/varres/tprevent_forloopvar_mutations.nim @@ -2,7 +2,7 @@ discard """ errormsg: "type mismatch: got " nimout: '''tprevent_forloopvar_mutations.nim(16, 3) Error: type mismatch: got but expected one of: -proc inc[T, V: Ordinal](x: var T; y: V = 1) +proc inc[T: Ordinal](x: var T; y: int = 1) first type mismatch at position: 1 required type for x: var T: Ordinal but expression 'i' is immutable, not 'var' From 9872453365f0782277aa93045e4c2461d1b7585a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 5 Aug 2023 19:35:37 +0200 Subject: [PATCH 380/489] destructors: better docs [backport:2.0] (#22391) --- doc/destructors.md | 85 +++++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/doc/destructors.md b/doc/destructors.md index 3121335145..e192fd362c 100644 --- a/doc/destructors.md +++ b/doc/destructors.md @@ -41,6 +41,9 @@ written as: for i in 0.. Date: Sun, 6 Aug 2023 01:38:32 +0800 Subject: [PATCH 381/489] Prevent early destruction of gFuns, fixes AddressSanitizer: heap-use-after-free (#22386) Prevent destruction of gFuns before callClosures --- lib/std/exitprocs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim index c44eb30d65..e42397c4cf 100644 --- a/lib/std/exitprocs.nim +++ b/lib/std/exitprocs.nim @@ -22,7 +22,7 @@ type var gFunsLock: Lock - gFuns: seq[Fun] + gFuns {.cursor.}: seq[Fun] #Intentionally use the cursor to break up the lifetime trace and make it compatible with JS. initLock(gFunsLock) From 7bf7496557d939331193069f56c3faa91d81d9d3 Mon Sep 17 00:00:00 2001 From: Daniel Belmes <3631206+DanielBelmes@users.noreply.github.com> Date: Sat, 5 Aug 2023 11:50:47 -0700 Subject: [PATCH 382/489] fix server caching issue causing Theme failures (#22378) * fix server caching issue causing Theme failures * Fix tester to ignore version cache param * fix case of people using -d:nimTestsNimdocFixup * rsttester needed the same fix --- compiler/docgen.nim | 4 ++-- config/nimdoc.cfg | 4 ++-- nimdoc/rsttester.nim | 6 ++++-- nimdoc/tester.nim | 6 ++++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 5120b52238..b25a82e4c4 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1723,7 +1723,7 @@ proc genOutFile(d: PDoc, groupedToc = false): string = "moduledesc", d.modDescFinal, "date", getDateStr(), "time", getClockStr(), "content", content, "author", d.meta[metaAuthor], "version", esc(d.target, d.meta[metaVersion]), "analytics", d.analytics, - "deprecationMsg", d.modDeprecationMsg] + "deprecationMsg", d.modDeprecationMsg, "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch] else: code = content result = code @@ -1907,7 +1907,7 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") "title", "Index", "subtitle", "", "tableofcontents", "", "moduledesc", "", "date", getDateStr(), "time", getClockStr(), - "content", content, "author", "", "version", "", "analytics", ""] + "content", content, "author", "", "version", "", "analytics", "", "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch] # no analytics because context is not available try: diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index abe039738f..9f36e7d1c2 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -237,10 +237,10 @@ doc.file = """ - + - +
      diff --git a/nimdoc/rsttester.nim b/nimdoc/rsttester.nim index a0bdfca1e1..be2b56c678 100644 --- a/nimdoc/rsttester.nim +++ b/nimdoc/rsttester.nim @@ -24,11 +24,13 @@ proc testRst2Html(fixup = false) = let sourceFile = expectedHtml.replace('\\', '/').replace("/expected/", "/source/").replace(".html", ".rst") exec("$1 rst2html $2" % [nimExe, sourceFile]) let producedHtml = expectedHtml.replace('\\', '/').replace("/expected/", "/source/htmldocs/") - if readFile(expectedHtml) != readFile(producedHtml): + let versionCacheParam = "?v=" & $NimMajor & "." & $NimMinor & "." & $NimPatch + let producedFile = readFile(producedHtml).replace(versionCacheParam,"") #remove version cache param used for cache invalidation + if readFile(expectedHtml) != producedFile: echo diffFiles(expectedHtml, producedHtml).output inc failures if fixup: - copyFile(producedHtml, expectedHtml) + writeFile(expectedHtml, producedFile) else: echo "SUCCESS: files identical: ", producedHtml if failures == 0: diff --git a/nimdoc/tester.nim b/nimdoc/tester.nim index e94caae7cb..0c0be36999 100644 --- a/nimdoc/tester.nim +++ b/nimdoc/tester.nim @@ -59,16 +59,18 @@ proc testNimDoc(prjDir, docsDir: string; switches: NimSwitches; fixup = false) = echo("$1 buildIndex $2" % [nimExe, nimBuildIndexSwitches]) for expected in walkDirRec(prjDir / "expected/", checkDir=true): + let versionCacheParam = "?v=" & $NimMajor & "." & $NimMinor & "." & $NimPatch let produced = expected.replace('\\', '/').replace("/expected/", "/$1/" % [docsDir]) if not fileExists(produced): echo "FAILURE: files not found: ", produced inc failures - elif readFile(expected) != readFile(produced): + let producedFile = readFile(produced).replace(versionCacheParam,"") #remove version cache param used for cache invalidation + if readFile(expected) != producedFile: echo "FAILURE: files differ: ", produced echo diffFiles(expected, produced).output inc failures if fixup: - copyFile(produced, expected) + writeFile(expected, producedFile) else: echo "SUCCESS: files identical: ", produced From b2c3b8f931e680aafaceb5a89bb59c361c81a30a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 6 Aug 2023 08:52:17 +0800 Subject: [PATCH 383/489] introduces online bisecting (#22390) * introduces online bisecting * Update .github/ISSUE_TEMPLATE/bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 8406f607f2..0145138650 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -71,5 +71,6 @@ body: which should give more context on a compiler crash. - If it's a regression, you can help us by identifying which version introduced the bug, see [Bisecting for regressions](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions), - or at least try known past releases (eg `choosenim 1.2.0`). + or at least try known past releases (e.g. `choosenim 2.0.0`). The Nim repo also supports online bisecting + via making a comment, which contains a code block starting by `!nim c`, `!nim js` etc. , see [nimrun-action](https://github.com/juancarlospaco/nimrun-action). - [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html) From 137d608d7d68a91c99149aa1127dd675ee45f751 Mon Sep 17 00:00:00 2001 From: Bung Date: Sun, 6 Aug 2023 15:21:24 +0800 Subject: [PATCH 384/489] add test for #3907 (#21069) * add test for #3907 --- tests/misc/t3907.nim | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/misc/t3907.nim diff --git a/tests/misc/t3907.nim b/tests/misc/t3907.nim new file mode 100644 index 0000000000..45fc75e814 --- /dev/null +++ b/tests/misc/t3907.nim @@ -0,0 +1,10 @@ +import std/assertions + +let a = 0 +let b = if false: -1 else: a +doAssert b == 0 + +let c: range[0..high(int)] = 0 +let d = if false: -1 else: c + +doAssert d == 0 From 95c751a9e4d42eb61917684339406d1ff07a4225 Mon Sep 17 00:00:00 2001 From: Bung Date: Sun, 6 Aug 2023 15:46:43 +0800 Subject: [PATCH 385/489] =?UTF-8?q?fix=20#15005;=20[ARC]=20Global=20variab?= =?UTF-8?q?le=20declared=20in=20a=20block=20is=20destroyed=20too=E2=80=A6?= =?UTF-8?q?=20(#22388)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix #15005 [ARC] Global variable declared in a block is destroyed too early --- compiler/injectdestructors.nim | 3 ++- tests/global/t15005.nim | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/global/t15005.nim diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 590012806c..15f375d28f 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -1153,7 +1153,8 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy let snk = c.genSink(s, dest, ri, flags) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) elif ri.sym.kind != skParam and ri.sym.owner == c.owner and - isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri): + isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri) and + {sfGlobal, sfPure} <= ri.sym.flags == false: # Rule 3: `=sink`(x, z); wasMoved(z) let snk = c.genSink(s, dest, ri, flags) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) diff --git a/tests/global/t15005.nim b/tests/global/t15005.nim new file mode 100644 index 0000000000..6395b1dde8 --- /dev/null +++ b/tests/global/t15005.nim @@ -0,0 +1,18 @@ +type + T = ref object + data: string + +template foo(): T = + var a15005 {.global.}: T + once: + a15005 = T(data: "hi") + + a15005 + +proc test() = + var b15005 = foo() + + doAssert b15005.data == "hi" + +test() +test() From f18e4c4050cb59cf828372f89c01d9e80f6516c5 Mon Sep 17 00:00:00 2001 From: Bung Date: Sun, 6 Aug 2023 19:07:01 +0800 Subject: [PATCH 386/489] fix set op related to {sfGlobal, sfPure} (#22393) --- compiler/hlo.nim | 2 +- compiler/injectdestructors.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/hlo.nim b/compiler/hlo.nim index 1aab9d5fe9..2e1652f09d 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -73,7 +73,7 @@ proc hlo(c: PContext, n: PNode): PNode = else: if n.kind in {nkFastAsgn, nkAsgn, nkSinkAsgn, nkIdentDefs, nkVarTuple} and n[0].kind == nkSym and - {sfGlobal, sfPure} * n[0].sym.flags == {sfGlobal, sfPure}: + {sfGlobal, sfPure} <= n[0].sym.flags: # do not optimize 'var g {.global} = re(...)' again! return n result = applyPatterns(c, n) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 15f375d28f..4463d1d694 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -1154,7 +1154,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy result = newTree(nkStmtList, snk, c.genWasMoved(ri)) elif ri.sym.kind != skParam and ri.sym.owner == c.owner and isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri) and - {sfGlobal, sfPure} <= ri.sym.flags == false: + not ({sfGlobal, sfPure} <= ri.sym.flags): # Rule 3: `=sink`(x, z); wasMoved(z) let snk = c.genSink(s, dest, ri, flags) result = newTree(nkStmtList, snk, c.genWasMoved(ri)) From d2b197bdcd91667bbb42763b195d13cd293142fe Mon Sep 17 00:00:00 2001 From: Bung Date: Sun, 6 Aug 2023 19:07:36 +0800 Subject: [PATCH 387/489] Stick search result (#22394) * nimdoc: stick search result inside browser viewport * fix nimdoc.out.css --------- Co-authored-by: Locria Cyber <74560659+locriacyber@users.noreply.github.com> --- doc/nimdoc.css | 8 +++++++- nimdoc/testproject/expected/nimdoc.out.css | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 1417d9eff1..3fb5497ff6 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -769,7 +769,13 @@ div.search_results { background-color: var(--third-background); margin: 3em; padding: 1em; - border: 1px solid #4d4d4d; } + border: 1px solid #4d4d4d; + position: sticky; + top: 0; + isolation: isolate; + z-index: 1; + max-height: 100vh; + overflow-y: scroll; } div#global-links ul { margin-left: 0; diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css index 1417d9eff1..3fb5497ff6 100644 --- a/nimdoc/testproject/expected/nimdoc.out.css +++ b/nimdoc/testproject/expected/nimdoc.out.css @@ -769,7 +769,13 @@ div.search_results { background-color: var(--third-background); margin: 3em; padding: 1em; - border: 1px solid #4d4d4d; } + border: 1px solid #4d4d4d; + position: sticky; + top: 0; + isolation: isolate; + z-index: 1; + max-height: 100vh; + overflow-y: scroll; } div#global-links ul { margin-left: 0; From 67122a9cb6be78b070a71941e74cbcc812633fa6 Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Sun, 6 Aug 2023 14:23:00 +0200 Subject: [PATCH 388/489] Let inferGenericTypes continue if a param is already bound (#22384) * Play with typeRel * Temp solution: Fixup call's param types * Test result type with two generic params * Asserts * Tiny cleanup * Skip sink * Ignore proc * Use changeType * Remove conversion * Remove last bits of conversion * Flag --------- Co-authored-by: SirOlaf <> --- compiler/semcall.nim | 9 ++++++--- tests/generics/treturn_inference.nim | 25 ++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index f0d0f648a6..4af96a0ead 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -564,7 +564,7 @@ proc getCallLineInfo(n: PNode): TLineInfo = proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) = ## Helper proc to inherit bound generic parameters from expectedType into x. - ## Does nothing if 'inferGenericTypes' isn't in c.features + ## Does nothing if 'inferGenericTypes' isn't in c.features. if inferGenericTypes notin c.features: return if expectedType == nil or x.callee[0] == nil: return # required for inference @@ -578,7 +578,7 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) = ## skips types and puts the skipped version on stack # It might make sense to skip here one by one. It's not part of the main # type reduction because the right side normally won't be skipped - const toSkip = { tyVar, tyLent, tyStatic, tyCompositeTypeClass } + const toSkip = { tyVar, tyLent, tyStatic, tyCompositeTypeClass, tySink } let x = a.skipTypes(toSkip) y = if a.kind notin toSkip: b @@ -603,7 +603,9 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) = if t[i] == nil or u[i] == nil: return stackPut(t[i], u[i]) of tyGenericParam: - if x.bindings.idTableGet(t) != nil: return + let prebound = x.bindings.idTableGet(t).PType + if prebound != nil: + continue # Skip param, already bound # fully reduced generic param, bind it if t notin flatUnbound: @@ -611,6 +613,7 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) = flatBound.add(u) else: discard + # update bindings for i in 0 ..< flatUnbound.len(): x.bindings.idTablePut(flatUnbound[i], flatBound[i]) diff --git a/tests/generics/treturn_inference.nim b/tests/generics/treturn_inference.nim index 05d38cef48..fa9b70f691 100644 --- a/tests/generics/treturn_inference.nim +++ b/tests/generics/treturn_inference.nim @@ -136,4 +136,27 @@ block: x: Table[int, float] let a = Foo(x: initTable()) - doAssert a.x is Table[int, float] \ No newline at end of file + doAssert a.x is Table[int, float] + +# partial binding +block: + type + ResultKind = enum + Ok, Error + + Result[T, E] = object + case kind: ResultKind + of Ok: + okVal: T + of Error: + errVal: E + + proc err[T, E](myParam: E): Result[T, E] = + Result[T, E](kind : Error, errVal : myParam) + + proc doStuff(): Result[int, string] = + err("Error") + + let res = doStuff() + doAssert res.kind == Error + doAssert res.errVal == "Error" \ No newline at end of file From 53586d1f32dfe4f2e859178a3e43a6614520763f Mon Sep 17 00:00:00 2001 From: konsumlamm <44230978+konsumlamm@users.noreply.github.com> Date: Sun, 6 Aug 2023 14:24:35 +0200 Subject: [PATCH 389/489] Fix some jsgen bugs (#22330) Fix `succ`, `pred` Fix `genRangeChck` for unsigned ints Fix typo in `dec` --- compiler/jsgen.nim | 53 +++++++++++++++++++++++++++++++------ compiler/semmagic.nim | 4 --- tests/int/tunsignedconv.nim | 36 ++++++++++++++++++------- 3 files changed, 72 insertions(+), 21 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index a5f4d29b27..f4d7d64563 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -676,8 +676,38 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = applyFormat("modInt64($1, $2)", "$1 % $2") else: applyFormat("modInt($1, $2)", "Math.trunc($1 % $2)") - of mSucc: applyFormat("addInt($1, $2)", "($1 + $2)") - of mPred: applyFormat("subInt($1, $2)", "($1 - $2)") + of mSucc: + let typ = n[1].typ.skipTypes(abstractVarRange) + case typ.kind + of tyUInt..tyUInt32: + binaryUintExpr(p, n, r, "+") + of tyUInt64: + if optJsBigInt64 in p.config.globalOptions: + applyFormat("BigInt.asUintN(64, $1 + BigInt($2))") + else: binaryUintExpr(p, n, r, "+") + elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + if optOverflowCheck notin p.options: + applyFormat("BigInt.asIntN(64, $1 + BigInt($2))") + else: binaryExpr(p, n, r, "addInt64", "addInt64($1, BigInt($2))") + else: + if optOverflowCheck notin p.options: applyFormat("$1 + $2") + else: binaryExpr(p, n, r, "addInt", "addInt($1, $2)") + of mPred: + let typ = n[1].typ.skipTypes(abstractVarRange) + case typ.kind + of tyUInt..tyUInt32: + binaryUintExpr(p, n, r, "-") + of tyUInt64: + if optJsBigInt64 in p.config.globalOptions: + applyFormat("BigInt.asUintN(64, $1 - BigInt($2))") + else: binaryUintExpr(p, n, r, "-") + elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: + if optOverflowCheck notin p.options: + applyFormat("BigInt.asIntN(64, $1 - BigInt($2))") + else: binaryExpr(p, n, r, "subInt64", "subInt64($1, BigInt($2))") + else: + if optOverflowCheck notin p.options: applyFormat("$1 - $2") + else: binaryExpr(p, n, r, "subInt", "subInt($1, $2)") of mAddF64: applyFormat("($1 + $2)", "($1 + $2)") of mSubF64: applyFormat("($1 - $2)", "($1 - $2)") of mMulF64: applyFormat("($1 * $2)", "($1 * $2)") @@ -2346,7 +2376,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) = of tyUInt64: if optJsBigInt64 in p.config.globalOptions: binaryExpr(p, n, r, "", "$1 = BigInt.asUintN(64, $3 - BigInt($2))", true) - else: binaryUintExpr(p, n, r, "+", true) + else: binaryUintExpr(p, n, r, "-", true) elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions: if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 = BigInt.asIntN(64, $3 - BigInt($2))", true) @@ -2564,12 +2594,19 @@ proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) = gen(p, n[0], r) let src = skipTypes(n[0].typ, abstractVarRange) let dest = skipTypes(n.typ, abstractVarRange) - if src.kind in {tyInt64, tyUInt64} and dest.kind notin {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: - r.res = "Number($1)" % [r.res] - if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and - checkUnsignedConversions notin p.config.legacyFeatures): - discard "XXX maybe emit masking instructions here" + if optRangeCheck notin p.options: + return + elif dest.kind in {tyUInt..tyUInt64} and checkUnsignedConversions notin p.config.legacyFeatures: + if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + r.res = "BigInt.asUintN($1, $2)" % [$(dest.size * 8), r.res] + else: + r.res = "BigInt.asUintN($1, BigInt($2))" % [$(dest.size * 8), r.res] + if not (dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions): + r.res = "Number($1)" % [r.res] else: + if src.kind in {tyInt64, tyUInt64} and dest.kind notin {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions: + # we do a range check anyway, so it's ok if the number gets rounded + r.res = "Number($1)" % [r.res] gen(p, n[1], a) gen(p, n[2], b) useMagic(p, "chckRange") diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 97a3207744..4fba4eaf92 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -656,10 +656,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, if not checkIsolate(n[1]): localError(c.config, n.info, "expression cannot be isolated: " & $n[1]) result = n - of mPred: - if n[1].typ.skipTypes(abstractInst).kind in {tyUInt..tyUInt64}: - n[0].sym.magic = mSubU - result = n of mPrivateAccess: result = semPrivateAccess(c, n) of mArrToSeq: diff --git a/tests/int/tunsignedconv.nim b/tests/int/tunsignedconv.nim index c32f85b4dc..6c73521d38 100644 --- a/tests/int/tunsignedconv.nim +++ b/tests/int/tunsignedconv.nim @@ -1,15 +1,19 @@ +discard """ + targets: "c cpp js" +""" + # Tests unsigned literals and implicit conversion between uints and ints -var h8:uint8 = 128 -var h16:uint16 = 32768 -var h32:uint32 = 2147483648'u32 -var h64:uint64 = 9223372036854775808'u64 -var foobar:uint64 = 9223372036854775813'u64 # Issue 728 +var h8: uint8 = 128 +var h16: uint16 = 32768 +var h32: uint32 = 2147483648'u32 +var h64: uint64 = 9223372036854775808'u64 +var foobar: uint64 = 9223372036854775813'u64 # Issue 728 -var v8:uint8 = 10 -var v16:uint16 = 10 -var v32:uint32 = 10 -var v64:uint64 = 10 +var v8: uint8 = 10 +var v16: uint16 = 10 +var v32: uint32 = 10 +var v64: uint64 = 10 # u8 + literal produces u8: var a8: uint8 = v8 + 10 @@ -95,3 +99,17 @@ template main() = static: main() main() + +block: + let a = uint64.high + let b = uint32.high + + doAssert a.uint64 == a + doAssert a.uint32 == uint32.high + doAssert a.uint16 == uint16.high + doAssert a.uint8 == uint8.high + + doAssert b.uint64 == b + doAssert b.uint32 == b + doAssert b.uint16 == uint16.high + doAssert b.uint8 == uint8.high From 93ced31353813c2f19c38a8c0af44737fa8d9f86 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 6 Aug 2023 20:26:21 +0800 Subject: [PATCH 390/489] use strictdefs for compiler (#22365) * wip; use strictdefs for compiler * checkpoint * complete the chores * more fixes * first phase cleanup * Update compiler/bitsets.nim * cleanup --- compiler/aliasanalysis.nim | 2 +- compiler/aliases.nim | 13 +- compiler/ast.nim | 16 +++ compiler/astalgo.nim | 5 + compiler/bitsets.nim | 1 + compiler/btrees.nim | 1 + compiler/ccgcalls.nim | 47 +++--- compiler/ccgexprs.nim | 221 +++++++++++++++-------------- compiler/ccgreset.nim | 2 +- compiler/ccgstmts.nim | 55 +++---- compiler/ccgtrav.nim | 6 +- compiler/ccgtypes.nim | 45 +++--- compiler/ccgutils.nim | 5 +- compiler/cgen.nim | 27 ++-- compiler/cgmeth.nim | 7 +- compiler/closureiters.nim | 13 +- compiler/commands.nim | 47 ++++-- compiler/concepts.nim | 7 + compiler/condsyms.nim | 2 + compiler/depends.nim | 1 + compiler/dfa.nim | 5 +- compiler/docgen.nim | 46 ++++-- compiler/docgen2.nim | 2 + compiler/enumtostr.nim | 1 + compiler/evalffi.nim | 23 ++- compiler/extccomp.nim | 25 ++-- compiler/filters.nim | 13 +- compiler/gorgeimpl.nim | 3 +- compiler/guards.nim | 148 +++++++++++++++++-- compiler/hlo.nim | 8 +- compiler/ic/cbackend.nim | 2 +- compiler/ic/dce.nim | 4 + compiler/ic/ic.nim | 9 +- compiler/ic/navigator.nim | 6 +- compiler/ic/packed_ast.nim | 1 + compiler/ic/rodfiles.nim | 6 +- compiler/importer.nim | 3 + compiler/injectdestructors.nim | 6 +- compiler/int128.nim | 6 +- compiler/isolation_check.nim | 7 +- compiler/jsgen.nim | 119 +++++++++------- compiler/lambdalifting.nim | 7 +- compiler/lexer.nim | 18 ++- compiler/liftdestructors.nim | 14 +- compiler/liftlocals.nim | 1 + compiler/lineinfos.nim | 2 +- compiler/linter.nim | 2 + compiler/llstream.nim | 3 + compiler/lookups.nim | 20 ++- compiler/magicsys.nim | 2 + compiler/main.nim | 4 +- compiler/modulegraphs.nim | 6 + compiler/msgs.nim | 6 +- compiler/nilcheck.nim | 18 +-- compiler/nim.cfg | 7 + compiler/nim.nim | 3 + compiler/nimblecmd.nim | 11 +- compiler/nimconf.nim | 6 +- compiler/nimsets.nim | 4 +- compiler/optimizer.nim | 2 +- compiler/options.nim | 5 +- compiler/packagehandling.nim | 1 + compiler/parampatterns.nim | 1 + compiler/parser.nim | 2 + compiler/patterns.nim | 40 +++++- compiler/pipelines.nim | 11 +- compiler/platform.nim | 2 + compiler/pragmas.nim | 4 + compiler/renderer.nim | 46 +++--- compiler/renderverbatim.nim | 1 + compiler/reorder.nim | 7 + compiler/rodutils.nim | 1 + compiler/ropes.nim | 6 +- compiler/sem.nim | 22 ++- compiler/semcall.nim | 16 ++- compiler/semexprs.nim | 21 ++- compiler/semfold.nim | 28 +++- compiler/semgnrc.nim | 3 +- compiler/seminst.nim | 5 +- compiler/semmagic.nim | 5 +- compiler/semobjconstr.nim | 27 ++-- compiler/semparallel.nim | 3 + compiler/sempass2.nim | 4 +- compiler/semstmts.nim | 31 +++- compiler/semtempl.nim | 1 + compiler/semtypes.nim | 39 +++-- compiler/semtypinst.nim | 3 + compiler/sighashes.nim | 8 +- compiler/sigmatch.nim | 25 +++- compiler/sizealignoffsetimpl.nim | 1 + compiler/sourcemap.nim | 14 +- compiler/spawn.nim | 4 +- compiler/suggest.nim | 33 +++-- compiler/syntaxes.nim | 10 +- compiler/transf.nim | 8 +- compiler/trees.nim | 21 ++- compiler/treetab.nim | 4 + compiler/typeallowed.nim | 2 + compiler/types.nim | 48 +++++-- compiler/typesrenderer.nim | 1 + compiler/varpartitions.nim | 13 +- compiler/vm.nim | 13 +- compiler/vmgen.nim | 20 ++- compiler/vmhooks.nim | 4 +- compiler/vmmarshal.nim | 27 +++- compiler/vmops.nim | 3 +- compiler/vmprofiler.nim | 4 +- lib/pure/collections/heapqueue.nim | 2 +- lib/pure/collections/sequtils.nim | 2 +- lib/pure/collections/setimpl.nim | 1 + lib/pure/collections/sets.nim | 2 +- lib/pure/collections/tableimpl.nim | 8 +- lib/pure/collections/tables.nim | 8 +- lib/std/packedsets.nim | 1 + 114 files changed, 1223 insertions(+), 501 deletions(-) diff --git a/compiler/aliasanalysis.nim b/compiler/aliasanalysis.nim index f14b815243..e24c6d8e26 100644 --- a/compiler/aliasanalysis.nim +++ b/compiler/aliasanalysis.nim @@ -74,7 +74,7 @@ proc aliases*(obj, field: PNode): AliasKind = # x[i] -> x[i]: maybe; Further analysis could make this return true when i is a runtime-constant # x[i] -> x[j]: maybe; also returns maybe if only one of i or j is a compiletime-constant template collectImportantNodes(result, n) = - var result: seq[PNode] + var result: seq[PNode] = @[] var n = n while true: case n.kind diff --git a/compiler/aliases.nim b/compiler/aliases.nim index 4b50fdb282..fa9824c41e 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -114,6 +114,8 @@ proc isPartOf*(a, b: PNode): TAnalysisResult = # use expensive type check: if isPartOf(a.sym.typ, b.sym.typ) != arNo: result = arMaybe + else: + result = arNo of nkBracketExpr: result = isPartOf(a[0], b[0]) if a.len >= 2 and b.len >= 2: @@ -149,7 +151,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult = result = isPartOf(a[1], b[1]) of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: result = isPartOf(a[0], b[0]) - else: discard + else: result = arNo # Calls return a new location, so a default of ``arNo`` is fine. else: # go down recursively; this is quite demanding: @@ -165,6 +167,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult = of DerefKinds: # a* !<| b[] iff + result = arNo if isPartOf(a.typ, b.typ) != arNo: result = isPartOf(a, b[0]) if result == arNo: result = arMaybe @@ -186,7 +189,9 @@ proc isPartOf*(a, b: PNode): TAnalysisResult = if isPartOf(a.typ, b.typ) != arNo: result = isPartOf(a[0], b) if result == arNo: result = arMaybe - else: discard + else: + result = arNo + else: result = arNo of nkObjConstr: result = arNo for i in 1.. 0: result = isPartOf(a, b[0]) - else: discard + else: + result = arNo + else: result = arNo diff --git a/compiler/ast.nim b/compiler/ast.nim index 539b6e9547..eccf5a9852 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1036,6 +1036,8 @@ proc comment*(n: PNode): string = if nfHasComment in n.flags and not gconfig.useIc: # IC doesn't track comments, see `packed_ast`, so this could fail result = gconfig.comments[n.nodeId] + else: + result = "" proc `comment=`*(n: PNode, a: string) = let id = n.nodeId @@ -1222,6 +1224,7 @@ proc getDeclPragma*(n: PNode): PNode = case n.kind of routineDefs: if n[pragmasPos].kind != nkEmpty: result = n[pragmasPos] + else: result = nil of nkTypeDef: #[ type F3*{.deprecated: "x3".} = int @@ -1241,6 +1244,8 @@ proc getDeclPragma*(n: PNode): PNode = ]# if n[0].kind == nkPragmaExpr: result = n[0][1] + else: + result = nil else: # support as needed for `nkIdentDefs` etc. result = nil @@ -1256,6 +1261,12 @@ proc extractPragma*(s: PSym): PNode = if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1: # s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma] result = s.ast[0][1] + else: + result = nil + else: + result = nil + else: + result = nil assert result == nil or result.kind == nkPragma proc skipPragmaExpr*(n: PNode): PNode = @@ -1602,6 +1613,7 @@ proc initStrTable*(x: var TStrTable) = newSeq(x.data, StartSize) proc newStrTable*: TStrTable = + result = default(TStrTable) initStrTable(result) proc initIdTable*(x: var TIdTable) = @@ -1609,6 +1621,7 @@ proc initIdTable*(x: var TIdTable) = newSeq(x.data, StartSize) proc newIdTable*: TIdTable = + result = default(TIdTable) initIdTable(result) proc resetIdTable*(x: var TIdTable) = @@ -1811,6 +1824,7 @@ proc hasNilSon*(n: PNode): bool = result = false proc containsNode*(n: PNode, kinds: TNodeKinds): bool = + result = false if n == nil: return case n.kind of nkEmpty..nkNilLit: result = n.kind in kinds @@ -2012,6 +2026,8 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool = if base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}: result = true + else: + result = false proc isInfixAs*(n: PNode): bool = return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as" diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 4e09fab02f..d0aec085f5 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -197,6 +197,7 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym = result = nil proc sameIgnoreBacktickGensymInfo(a, b: string): bool = + result = false if a[0] != b[0]: return false var alen = a.len - 1 while alen > 0 and a[alen] != '`': dec(alen) @@ -230,6 +231,7 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym = ## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id), ## if c.instLines: actual.info else: templ.info) ## ``` + result = nil for i in 1.. 0: result.add ", " diff --git a/compiler/bitsets.nim b/compiler/bitsets.nim index 67598f9cae..756d93217c 100644 --- a/compiler/bitsets.nim +++ b/compiler/bitsets.nim @@ -87,5 +87,6 @@ const populationCount: array[uint8, uint8] = block: arr proc bitSetCard*(x: TBitSet): BiggestInt = + result = 0 for it in x: result.inc int(populationCount[it]) diff --git a/compiler/btrees.nim b/compiler/btrees.nim index 92f07f6b09..3b737b1bc9 100644 --- a/compiler/btrees.nim +++ b/compiler/btrees.nim @@ -38,6 +38,7 @@ template less(a, b): bool = cmp(a, b) < 0 template eq(a, b): bool = cmp(a, b) == 0 proc getOrDefault*[Key, Val](b: BTree[Key, Val], key: Key): Val = + result = default(Val) var x = b.root while x.isInternal: for j in 0.. # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq->data[seq->len-1] = x; - var a, b, dest, tmpL, call: TLoc + var a, b, dest, tmpL, call: TLoc = default(TLoc) initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) let seqType = skipTypes(e[1].typ, {tyVar}) @@ -1369,7 +1377,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = gcUsage(p.config, e) proc genReset(p: BProc, n: PNode) = - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, n[1], a) specializeReset(p, a) when false: @@ -1384,7 +1392,7 @@ proc genDefault(p: BProc; n: PNode; d: var TLoc) = proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = var sizeExpr = sizeExpr let typ = a.t - var b: TLoc + var b: TLoc = default(TLoc) initLoc(b, locExpr, a.lode, OnHeap) let refType = typ.skipTypes(abstractInstOwned) assert refType.kind == tyRef @@ -1411,7 +1419,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = localError(p.module.config, a.lode.info, "the destructor that is turned into a finalizer needs " & "to have the 'nimcall' calling convention") - var f: TLoc + var f: TLoc = default(TLoc) initLocExpr(p, newSymNode(op), f) p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) @@ -1437,11 +1445,11 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = genObjectInit(p, cpsStmts, bt, a, constructRefObj) proc genNew(p: BProc, e: PNode) = - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, e[1], a) # 'genNew' also handles 'unsafeNew': if e.len == 3: - var se: TLoc + var se: TLoc = default(TLoc) initLocExpr(p, e[2], se) rawGenNew(p, a, se.rdLoc, needsInit = true) else: @@ -1450,7 +1458,7 @@ proc genNew(p: BProc, e: PNode) = proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = let seqtype = skipTypes(dest.t, abstractVarRange) - var call: TLoc + var call: TLoc = default(TLoc) initLoc(call, locExpr, dest.lode, OnHeap) if dest.storage == OnHeap and usesWriteBarrier(p.config): if canFormAcycle(p.module.g.graph, dest.t): @@ -1476,7 +1484,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = genAssignment(p, dest, call, {}) proc genNewSeq(p: BProc, e: PNode) = - var a, b: TLoc + var a, b: TLoc = default(TLoc) initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) if optSeqDestructors in p.config.globalOptions: @@ -1492,7 +1500,7 @@ proc genNewSeq(p: BProc, e: PNode) = proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = let seqtype = skipTypes(e.typ, abstractVarRange) - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, e[1], a) if optSeqDestructors in p.config.globalOptions: if d.k == locNone: getTemp(p, e.typ, d, needsInit=false) @@ -1548,7 +1556,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = (d.k notin {locTemp,locLocalVar,locGlobalVar,locParam,locField}) or (isPartOf(d.lode, e) != arNo) - var tmp: TLoc + var tmp: TLoc = default(TLoc) var r: Rope if useTemp: getTemp(p, t, tmp) @@ -1567,7 +1575,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = let ty = getUniqueType(t) for i in 1..>3] &(1U<<((NU)($2)&7U)))!=0)") template binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) = - var a, b: TLoc + var a, b: TLoc = default(TLoc) assert(d.k == locNone) initLocExpr(p, e[1], a) initLocExpr(p, e[2], b) @@ -2031,7 +2040,7 @@ template binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) = lineF(p, cpsStmts, frmt, [rdLoc(a), elem]) proc genInOp(p: BProc, e: PNode, d: var TLoc) = - var a, b, x, y: TLoc + var a, b, x, y: TLoc = default(TLoc) if (e[1].kind == nkCurly) and fewCmps(p.config, e[1]): # a set constructor but not a constant set: # do not emit the set, but generate a bunch of comparisons; and if we do @@ -2081,7 +2090,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = "&", "|", "& ~"] - var a, b, i: TLoc + var a, b, i: TLoc = default(TLoc) var setType = skipTypes(e[1].typ, abstractVar) var size = int(getSize(p.config, setType)) case size @@ -2118,7 +2127,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mIncl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] |=(1U<<($2&7U));$n") of mExcl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] &= ~(1U<<($2&7U));$n") of mCard: - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, e[1], a) putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [addrLoc(p.config, a), size])) of mLtSet, mLeSet: @@ -2133,7 +2142,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = linefmt(p, cpsStmts, lookupOpr[mLeSet], [rdLoc(i), size, rdLoc(d), rdLoc(a), rdLoc(b)]) of mEqSet: - var a, b: TLoc + var a, b: TLoc = default(TLoc) assert(e[1].typ != nil) assert(e[2].typ != nil) initLocExpr(p, e[1], a) @@ -2161,7 +2170,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = ValueTypes = {tyTuple, tyObject, tyArray, tyOpenArray, tyVarargs, tyUncheckedArray} # we use whatever C gives us. Except if we have a value-type, we need to go # through its address: - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, e[1], a) let etyp = skipTypes(e.typ, abstractRange+{tyOwned}) let srcTyp = skipTypes(e[1].typ, abstractRange) @@ -2199,7 +2208,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) = # 'cast' and some float type involved? --> use a union. inc(p.labels) var lbl = p.labels.rope - var tmp: TLoc + var tmp: TLoc = default(TLoc) tmp.r = "LOC$1.source" % [lbl] let destsize = getSize(p.config, destt) let srcsize = getSize(p.config, srct) @@ -2222,7 +2231,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) = genSomeCast(p, e, d) proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = - var a: TLoc + var a: TLoc = default(TLoc) var dest = skipTypes(n.typ, abstractVar) initLocExpr(p, n[0], a) if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and @@ -2277,7 +2286,7 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) = genSomeCast(p, e, d) proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) = - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, n[0], a) putIntoDest(p, d, n, ropecg(p.module, "#nimToCStringConv($1)", [rdLoc(a)]), @@ -2285,7 +2294,7 @@ proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) = a.storage) proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, n[0], a) putIntoDest(p, d, n, ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]), @@ -2293,7 +2302,7 @@ proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = gcUsage(p.config, n) proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = - var x: TLoc + var x: TLoc = default(TLoc) var a = e[1] var b = e[2] if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "": @@ -2310,7 +2319,7 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) = if {optNaNCheck, optInfCheck} * p.options != {}: const opr: array[mAddF64..mDivF64, string] = ["+", "-", "*", "/"] - var a, b: TLoc + var a, b: TLoc = default(TLoc) assert(e[1].typ != nil) assert(e[2].typ != nil) initLocExpr(p, e[1], a) @@ -2335,7 +2344,7 @@ proc skipAddr(n: PNode): PNode = result = if n.kind in {nkAddr, nkHiddenAddr}: n[0] else: n proc genWasMoved(p: BProc; n: PNode) = - var a: TLoc + var a: TLoc = default(TLoc) let n1 = n[1].skipAddr if p.withinBlockLeaveActions > 0 and notYetAlive(n1): discard @@ -2346,11 +2355,11 @@ proc genWasMoved(p: BProc; n: PNode) = # [addrLoc(p.config, a), getTypeDesc(p.module, a.t)]) proc genMove(p: BProc; n: PNode; d: var TLoc) = - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, n[1].skipAddr, a) if n.len == 4: # generated by liftdestructors: - var src: TLoc + var src: TLoc = default(TLoc) initLocExpr(p, n[2], src) linefmt(p, cpsStmts, "if ($1.p != $2.p) {", [rdLoc(a), rdLoc(src)]) genStmts(p, n[3]) @@ -2377,7 +2386,7 @@ proc genDestroy(p: BProc; n: PNode) = let t = arg.typ.skipTypes(abstractInst) case t.kind of tyString: - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, arg, a) if optThreads in p.config.globalOptions: linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & @@ -2388,7 +2397,7 @@ proc genDestroy(p: BProc; n: PNode) = " #dealloc($1.p);$n" & "}$n", [rdLoc(a)]) of tySequence: - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, arg, a) linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & " #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" & @@ -2406,7 +2415,7 @@ proc genDispose(p: BProc; n: PNode) = when false: let elemType = n[1].typ.skipTypes(abstractVar).lastSon - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, n[1].skipAddr, a) if isFinal(elemType): @@ -2459,7 +2468,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}: binaryStmt(p, e, d, opr[op]) else: - var a, b: TLoc + var a, b: TLoc = default(TLoc) assert(e[1].typ != nil) assert(e[2].typ != nil) initLocExpr(p, e[1], a) @@ -2477,7 +2486,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if optSeqDestructors in p.config.globalOptions: binaryStmtAddr(p, e, d, "nimAddCharV1") else: - var dest, b, call: TLoc + var dest, b, call: TLoc = default(TLoc) initLoc(call, locCall, e, OnHeap) initLocExpr(p, e[1], dest) initLocExpr(p, e[2], b) @@ -2515,7 +2524,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mNew: genNew(p, e) of mNewFinalize: if optTinyRtti in p.config.globalOptions: - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, e[1], a) rawGenNew(p, a, "", needsInit = true) gcUsage(p.config, e) @@ -2541,6 +2550,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = elif e[1].kind == nkCheckedFieldExpr: dotExpr = e[1][0] else: + dotExpr = nil internalError(p.config, e.info, "unknown ast") let t = dotExpr[0].typ.skipTypes({tyTypeDesc}) let tname = getTypeDesc(p.module, t, dkVar) @@ -2609,7 +2619,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = localError(p.config, e.info, "for --gc:arc|orc 'deepcopy' support has to be enabled with --deepcopy:on") - var a, b: TLoc + var a, b: TLoc = default(TLoc) let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1] initLocExpr(p, x, a) initLocExpr(p, e[2], b) @@ -2635,7 +2645,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = # nimZeroMem(tmp, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c); # incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g); var - a, b, idx: TLoc + a, b, idx: TLoc = default(TLoc) if nfAllConst in e.flags: var elem = newRopeAppender() genSetNode(p, e, elem) @@ -2690,12 +2700,12 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = [rdLoc(d), aa, rope(ts)]) proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = - var rec: TLoc + var rec: TLoc = default(TLoc) if not handleConstExpr(p, n, d): let t = n.typ discard getTypeDesc(p.module, t) # so that any fields are initialized - var tmp: TLoc + var tmp: TLoc = default(TLoc) # bug #16331 let doesAlias = lhsDoesAlias(d.lode, n) let dest = if doesAlias: addr(tmp) else: addr(d) @@ -2734,7 +2744,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) = p.module.s[cfsData].add data putIntoDest(p, d, n, tmp, OnStatic) else: - var tmp, a, b: TLoc + var tmp, a, b: TLoc = default(TLoc) initLocExpr(p, n[0], a) initLocExpr(p, n[1], b) if n[0].skipConv.kind == nkClosure: @@ -2751,7 +2761,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) = putLocIntoDest(p, d, tmp) proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) = - var arr: TLoc + var arr: TLoc = default(TLoc) if not handleConstExpr(p, n, d): if d.k == locNone: getTemp(p, n.typ, d) for i in 0..Sup" else: ".Sup") for i in 2..abs(inheritanceDiff(dest, src)): r.add(".Sup") @@ -3049,7 +3059,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = let op = n[0] if n.typ.isNil: # discard the value: - var a: TLoc + var a: TLoc = default(TLoc) if op.kind == nkSym and op.sym.magic != mNone: genMagicExpr(p, n, a, op.sym.magic) else: @@ -3143,7 +3153,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = let ex = n[0] if ex.kind != nkEmpty: genLineDir(p, n) - var a: TLoc + var a: TLoc = default(TLoc) initLocExprSingleUse(p, ex, a) line(p, cpsStmts, "(void)(" & a.r & ");\L") of nkAsmStmt: genAsmStmt(p, n) @@ -3254,6 +3264,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo; result: var Rope) = globalError(p.config, info, "cannot create null element for: " & $t.kind) proc caseObjDefaultBranch(obj: PNode; branch: Int128): int = + result = 0 for i in 1 ..< obj.len: for j in 0 .. obj[i].len - 2: if obj[i][j].kind == nkRange: @@ -3464,11 +3475,11 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; resul if n[0].kind == nkNilLit: result.add "{NIM_NIL,NIM_NIL}" else: - var d: TLoc + var d: TLoc = default(TLoc) initLocExpr(p, n[0], d) result.add "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, typ, clHalfWithEnv), rdLoc(d)] else: - var d: TLoc + var d: TLoc = default(TLoc) initLocExpr(p, n, d) result.add rdLoc(d) of tyArray, tyVarargs: @@ -3497,10 +3508,10 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; resul if optSeqDestructors in p.config.globalOptions and n.kind != nkNilLit and ty == tyString: genStringLiteralV2Const(p.module, n, isConst, result) else: - var d: TLoc + var d: TLoc = default(TLoc) initLocExpr(p, n, d) result.add rdLoc(d) else: - var d: TLoc + var d: TLoc = default(TLoc) initLocExpr(p, n, d) result.add rdLoc(d) diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim index 5e6456704d..f486f71fb7 100644 --- a/compiler/ccgreset.nim +++ b/compiler/ccgreset.nim @@ -57,7 +57,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = specializeResetT(p, accessor, lastSon(typ)) of tyArray: let arraySize = lengthOrd(p.config, typ[0]) - var i: TLoc + var i: TLoc = default(TLoc) getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", [i.r, arraySize]) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 3197389814..45104399a1 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -50,6 +50,7 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} = result = true proc inExceptBlockLen(p: BProc): int = + result = 0 for x in p.nestedTryStmts: if x.inExcept: result.inc @@ -71,7 +72,7 @@ template startBlock(p: BProc, start: FormatStr = "{$n", proc endBlock(p: BProc) proc genVarTuple(p: BProc, n: PNode) = - var tup, field: TLoc + var tup, field: TLoc = default(TLoc) if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple") # if we have a something that's been captured, use the lowering instead: @@ -83,7 +84,7 @@ proc genVarTuple(p: BProc, n: PNode) = # check only the first son var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym) let hcrCond = if forHcr: getTempName(p.module) else: "" - var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] + var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] = @[] # determine if the tuple is constructed at top-level scope or inside of a block (if/while/block) let isGlobalInBlock = forHcr and p.blocks.len > 2 # do not close and reopen blocks if this is a 'global' but inside of a block (if/while/block) @@ -169,7 +170,7 @@ proc endBlock(p: BProc, blockEnd: Rope) = proc endBlock(p: BProc) = let topBlock = p.blocks.len - 1 let frameLen = p.blocks[topBlock].frameLen - var blockEnd: Rope + var blockEnd: Rope = "" if frameLen > 0: blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope]) if p.blocks[topBlock].label.len != 0: @@ -244,7 +245,7 @@ proc genGotoState(p: BProc, n: PNode) = # switch (x.state) { # case 0: goto STATE0; # ... - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, n[0], a) lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)]) p.flags.incl beforeRetNeeded @@ -263,7 +264,7 @@ proc genGotoState(p: BProc, n: PNode) = lineF(p, cpsStmts, "}$n", []) proc genBreakState(p: BProc, n: PNode, d: var TLoc) = - var a: TLoc + var a: TLoc = default(TLoc) initLoc(d, locExpr, n, OnUnknown) if n[0].kind == nkClosure: @@ -357,7 +358,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) = # generate better code here: 'Foo f = x;' genLineDir(p, vn) var decl = localVarDecl(p, vn) - var tmp: TLoc + var tmp: TLoc = default(TLoc) if isCppCtorCall: genCppVarForCtor(p, v, vn, value, decl) line(p, cpsStmts, decl) @@ -441,7 +442,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = # { elsePart } # Lend: var - a: TLoc + a: TLoc = default(TLoc) lelse: TLabel if not isEmptyType(n.typ) and d.k == locNone: getTemp(p, n.typ, d) @@ -520,7 +521,7 @@ proc genComputedGoto(p: BProc; n: PNode) = # wrapped inside stmt lists by inject destructors won't be recognised let n = n.flattenStmts() var casePos = -1 - var arraySize: int + var arraySize: int = 0 for i in 0.. 0: genIfForCaseUntil(p, n, d, rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n", @@ -1389,7 +1392,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = p.flags.incl noSafePoints genLineDir(p, t) cgsym(p.module, "Exception") - var safePoint: Rope + var safePoint: Rope = "" if not quirkyExceptions: safePoint = getTempName(p.module) linefmt(p, cpsLocals, "#TSafePoint $1;$n", [safePoint]) @@ -1492,7 +1495,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = of nkSym: var sym = it.sym if sym.kind in {skProc, skFunc, skIterator, skMethod}: - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, it, a) res.add($rdLoc(a)) elif sym.kind == skType: @@ -1505,7 +1508,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = res.add($getTypeDesc(p.module, it.typ)) else: discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs)) - var a: TLoc + var a: TLoc = default(TLoc) initLocExpr(p, it, a) res.add($a.rdLoc) @@ -1608,7 +1611,7 @@ when false: expr(p, call, d) proc asgnFieldDiscriminant(p: BProc, e: PNode) = - var a, tmp: TLoc + var a, tmp: TLoc = default(TLoc) var dotExpr = e[0] if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0] initLocExpr(p, e[0], a) @@ -1630,7 +1633,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = else: let le = e[0] let ri = e[1] - var a: TLoc + var a: TLoc = default(TLoc) discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar) initLoc(a, locNone, le, OnUnknown) a.flags.incl(lfEnforceDeref) @@ -1644,7 +1647,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = loadInto(p, le, ri, a) proc genStmts(p: BProc, t: PNode) = - var a: TLoc + var a: TLoc = default(TLoc) let isPush = p.config.hasHint(hintExtendedContext) if isPush: pushInfoContext(p.config, t.info) diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 96f5869b00..e4008bfc1e 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -74,7 +74,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = genTraverseProc(c, accessor, lastSon(typ)) of tyArray: let arraySize = lengthOrd(c.p.config, typ[0]) - var i: TLoc + var i: TLoc = default(TLoc) getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i) var oldCode = p.s(cpsStmts) freeze oldCode @@ -119,11 +119,11 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) = var p = c.p assert typ.kind == tySequence - var i: TLoc + var i: TLoc = default(TLoc) getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i) var oldCode = p.s(cpsStmts) freeze oldCode - var a: TLoc + var a: TLoc = default(TLoc) a.r = accessor lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 2aa92c130e..205031a918 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -206,8 +206,12 @@ proc mapType(conf: ConfigRef; typ: PType; isParam: bool): TCTypeKind = result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) of tyStatic: if typ.n != nil: result = mapType(conf, lastSon typ, isParam) - else: doAssert(false, "mapType: " & $typ.kind) - else: doAssert(false, "mapType: " & $typ.kind) + else: + result = ctVoid + doAssert(false, "mapType: " & $typ.kind) + else: + result = ctVoid + doAssert(false, "mapType: " & $typ.kind) proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind = @@ -322,7 +326,9 @@ proc getSimpleTypeDesc(m: BModule; typ: PType): Rope = of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ[0]) of tyStatic: if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ) - else: internalError(m.config, "tyStatic for getSimpleTypeDesc") + else: + result = "" + internalError(m.config, "tyStatic for getSimpleTypeDesc") of tyGenericInst, tyAlias, tySink, tyOwned: result = getSimpleTypeDesc(m, lastSon typ) else: result = "" @@ -501,8 +507,8 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var rettype = getTypeDescAux(m, t[0], check, dkResult) else: rettype = runtimeFormat(rettype.replace("'0", "$1"), [getTypeDescAux(m, t[0], check, dkResult)]) - var types, names, args: seq[string] - if not isCtor: + var types, names, args: seq[string] = @[] + if not isCtor: var this = t.n[1].sym fillParamName(m, this) fillLoc(this.loc, locParam, t.n[1], @@ -719,9 +725,9 @@ proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope = genRecordFieldsAux(m, typ.n, typ, check, result) if typ.itemId in m.g.graph.memberProcsPerType: let procs = m.g.graph.memberProcsPerType[typ.itemId] - var isDefaultCtorGen, isCtorGen: bool + var isDefaultCtorGen, isCtorGen: bool = false for prc in procs: - var header: Rope + var header: Rope = "" if sfConstructor in prc.flags: isCtorGen = true if prc.typ.n.len == 1: @@ -741,7 +747,8 @@ proc fillObjectFields*(m: BModule; typ: PType) = proc mangleDynLibProc(sym: PSym): Rope proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope, - check: var IntSet, hasField:var bool): Rope = + check: var IntSet, hasField:var bool): Rope = + result = "" if typ.kind == tyObject: if typ[0] == nil: if lacksMTypeField(typ): @@ -782,7 +789,7 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope, structOrUnion = "#pragma pack(push, 1)\L" & structOrUnion(typ) else: structOrUnion = structOrUnion(typ) - var baseType: string + var baseType: string = "" if typ[0] != nil: baseType = getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, dkField) if typ.sym == nil or sfCodegenDecl notin typ.sym.flags: @@ -873,6 +880,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym) let sig = hashType(origTyp, m.config) + result = "" # todo move `result = getTypePre(m, t, sig)` here ? defer: # defer is the simplest in this case if isImportedType(t) and not m.typeABICache.containsOrIncl(sig): addAbiCheck(m, t, result) @@ -953,7 +961,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes of tyProc: result = getTypeName(m, origTyp, sig) m.typeCache[sig] = result - var rettype, desc: Rope + var rettype, desc: Rope = "" genProcParams(m, t, rettype, desc, check, true, true) if not isImportedType(t): if t.callConv != ccClosure: # procedure vars may need a closure! @@ -1030,7 +1038,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes while i < cppName.len: if cppName[i] == '\'': var chunkEnd = i-1 - var idx, stars: int + var idx, stars: int = 0 if scanCppGenericSlot(cppName, i, idx, stars): result.add cppName.substr(chunkStart, chunkEnd) chunkStart = i @@ -1110,7 +1118,7 @@ proc getClosureType(m: BModule; t: PType, kind: TClosureTypeKind): Rope = assert t.kind == tyProc var check = initIntSet() result = getTempName(m) - var rettype, desc: Rope + var rettype, desc: Rope = "" genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf) if not isImportedType(t): if t.callConv != ccClosure or kind != clFull: @@ -1141,7 +1149,7 @@ proc isNonReloadable(m: BModule; prc: PSym): bool = return m.hcrOn and sfNonReloadable in prc.flags proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride: var bool; isCtor: bool) = - var afterParams: string + var afterParams: string = "" if scanf(val, "$*($*)$s$*", name, params, afterParams): isFnConst = afterParams.find("const") > -1 isOverride = afterParams.find("override") > -1 @@ -1170,11 +1178,11 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = memberOp = "#->" var typDesc = getTypeDescWeak(m, typ, check, dkParam) let asPtrStr = rope(if asPtr: "_PTR" else: "") - var name, params, rettype, superCall: string - var isFnConst, isOverride: bool + var name, params, rettype, superCall: string = "" + var isFnConst, isOverride: bool = false parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isCtor) genMemberProcParams(m, prc, superCall, rettype, params, check, true, false) - var fnConst, override: string + var fnConst, override: string = "" if isCtor: name = typDesc if isFnConst: @@ -1203,7 +1211,7 @@ proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false) var check = initIntSet() fillBackendName(m, prc) fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown) - var rettype, params: Rope + var rettype, params: Rope = "" genProcParams(m, prc.typ, rettype, params, check, true, false) # handle the 2 options for hotcodereloading codegen - function pointer # (instead of forward declaration) or header for function body with "_actual" postfix @@ -1443,7 +1451,7 @@ proc genEnumInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) = genTypeInfoAux(m, typ, typ, name, info) var nodePtrs = getTempName(m) & "_" & $typ.n.len genTNimNodeArray(m, nodePtrs, rope(typ.n.len)) - var enumNames, specialCases: Rope + var enumNames, specialCases: Rope = "" var firstNimNode = m.typeNodes var hasHoles = false for i in 0.. 1: - var cond: PNode + var cond: PNode = nil for i in 0.. 0: # Ok, we are in a try, lets see which (if any) try's we break out from: for b in countdown(c.blocks.high, i): diff --git a/compiler/docgen.nim b/compiler/docgen.nim index b25a82e4c4..4a0ae6fc9b 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -170,6 +170,7 @@ proc cmpDecimalsIgnoreCase(a, b: string): int = proc prettyString(a: object): string = # xxx pending std/prettyprint refs https://github.com/nim-lang/RFCs/issues/203#issuecomment-602534906 + result = "" for k, v in fieldPairs(a): result.add k & ": " & $v & "\n" @@ -215,12 +216,16 @@ proc whichType(d: PDoc; n: PNode): PSym = if n.kind == nkSym: if d.types.strTableContains(n.sym): result = n.sym + else: + result = nil else: + result = nil for i in 0.. 0: return @@ -484,7 +492,7 @@ proc externalDep(d: PDoc; module: PSym): string = proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string; renderFlags: TRenderFlags = {}; procLink: string) = - var r: TSrcGen + var r: TSrcGen = TSrcGen() var literal = "" initTokRender(r, n, renderFlags) var kind = tkEof @@ -600,7 +608,9 @@ proc runAllExamples(d: PDoc) = rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string]) # removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove -proc quoted(a: string): string = result.addQuoted(a) +proc quoted(a: string): string = + result = "" + result.addQuoted(a) proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): (string, int, int) = # xxx expose in compiler/lineinfos.nim @@ -726,7 +736,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var ItemPre, let (rdoccmd, code) = prepareExample(d, n, topLevel) var msg = "Example:" if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd - var s: string + var s: string = "" dispA(d.conf, s, "\n

      $1

      \n", "\n\n\\textbf{$1}\n", [msg]) dest.add s @@ -942,7 +952,10 @@ proc genDeprecationMsg(d: PDoc, n: PNode): string = if n[1].kind in {nkStrLit..nkTripleStrLit}: result = getConfigVar(d.conf, "doc.deprecationmsg") % [ "label", "Deprecated:", "message", xmltree.escape(n[1].strVal)] + else: + result = "" else: + result = "" doAssert false type DocFlags = enum @@ -950,6 +963,7 @@ type DocFlags = enum kForceExport proc genSeeSrc(d: PDoc, path: string, line: int): string = + result = "" let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc") if docItemSeeSrc.len > 0: let path = relativeTo(AbsoluteFile path, AbsoluteDir getCurrentDir(), '/') @@ -991,7 +1005,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol = result.symKind = k.toHumanStr if k in routineKinds: var - paramTypes: seq[string] + paramTypes: seq[string] = @[] renderParamTypes(paramTypes, n[paramsPos], toNormalize=true) let paramNames = renderParamNames(n[paramsPos], toNormalize=true) # In some rare cases (system.typeof) parameter type is not set for default: @@ -1038,7 +1052,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx var result = "" var literal, plainName = "" var kind = tkEof - var comm: ItemPre + var comm: ItemPre = default(ItemPre) if n.kind in routineDefs: getAllRunnableExamples(d, n, comm) else: @@ -1150,7 +1164,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): var name = getNameEsc(d, nameNode) comm = genRecComment(d, n) - r: TSrcGen + r: TSrcGen = default(TSrcGen) renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing} if nonExports: renderFlags.incl renderNonExportedFields @@ -1283,6 +1297,8 @@ proc documentNewEffect(cache: IdentCache; n: PNode): PNode = let s = n[namePos].sym if tfReturnsNew in s.typ.flags: result = newIdentNode(getIdent(cache, "new"), n.info) + else: + result = nil proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, idx: int): PNode = let spec = effectSpec(x, effectType) @@ -1305,6 +1321,8 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id result = newTreeI(nkExprColonExpr, n.info, newIdentNode(getIdent(cache, $effectType), n.info), effects) + else: + result = nil proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode = let s = n[namePos].sym @@ -1318,6 +1336,8 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName if effects.len > 0: result = newTreeI(nkExprColonExpr, n.info, newIdentNode(getIdent(cache, pragmaName), n.info), effects) + else: + result = nil proc documentRaises*(cache: IdentCache; n: PNode) = if n[namePos].kind != nkSym: return @@ -1391,7 +1411,7 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept" of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0]) of nkCallKinds: - var comm: ItemPre + var comm: ItemPre = default(ItemPre) getAllRunnableExamples(d, n, comm) if comm.len != 0: d.modDescPre.add(comm) else: discard @@ -1500,7 +1520,7 @@ proc finishGenerateDoc*(d: var PDoc) = overloadChoices.sort(cmp) var nameContent = "" for item in overloadChoices: - var itemDesc: string + var itemDesc: string = "" renderItemPre(d, item.descRst, itemDesc) nameContent.add( getConfigVar(d.conf, "doc.item") % ( @@ -1526,7 +1546,7 @@ proc finishGenerateDoc*(d: var PDoc) = for i, entry in d.jEntriesPre: if entry.rst != nil: let resolved = resolveSubs(d.sharedState, entry.rst) - var str: string + var str: string = "" renderRstToOut(d[], resolved, str) entry.json[entry.rstField] = %str d.jEntriesPre[i].rst = nil @@ -1641,7 +1661,7 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) = for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase): var overloadChoices = d.tocTable[kind][plainName] overloadChoices.sort(cmp) - var content: string + var content: string = "" for item in overloadChoices: content.add item.content d.toc2[kind].add getConfigVar(d.conf, "doc.section.toc2") % [ @@ -1672,7 +1692,7 @@ proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile): proc genOutFile(d: PDoc, groupedToc = false): string = var - code, content: string + code, content: string = "" title = "" var j = 0 var toc = "" @@ -1781,7 +1801,7 @@ proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) = proc writeOutputJson*(d: PDoc, useWarning = false) = runAllExamples(d) - var modDesc: string + var modDesc: string = "" for desc in d.modDescFinal: modDesc &= desc let content = %*{"orig": d.filename, @@ -1793,7 +1813,7 @@ proc writeOutputJson*(d: PDoc, useWarning = false) = else: let dir = d.destFile.splitFile.dir createDir(dir) - var f: File + var f: File = default(File) if open(f, d.destFile, fmWrite): write(f, $content) close(f) diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 9076034127..7fb11a3bd7 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -39,10 +39,12 @@ template closeImpl(body: untyped) {.dirty.} = discard proc closeDoc*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = + result = nil closeImpl: writeOutput(g.doc, useWarning, groupedToc) proc closeJson*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode = + result = nil closeImpl: writeOutputJson(g.doc, useWarning) diff --git a/compiler/enumtostr.nim b/compiler/enumtostr.nim index 4ae17235b3..838cd5f971 100644 --- a/compiler/enumtostr.nim +++ b/compiler/enumtostr.nim @@ -56,6 +56,7 @@ proc searchObjCaseImpl(obj: PNode; field: PSym): PNode = if obj.kind == nkRecCase and obj[0].kind == nkSym and obj[0].sym == field: result = obj else: + result = nil for x in obj: result = searchObjCaseImpl(x, field) if result != nil: break diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index 0112aebb91..3f386f76ec 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -37,9 +37,10 @@ else: var gExeHandle = loadLib() proc getDll(conf: ConfigRef, cache: var TDllCache; dll: string; info: TLineInfo): pointer = + result = nil if dll in cache: return cache[dll] - var libs: seq[string] + var libs: seq[string] = @[] libCandidates(dll, libs) for c in libs: result = loadLib(c) @@ -61,7 +62,7 @@ proc importcSymbol*(conf: ConfigRef, sym: PSym): PNode = let lib = sym.annex if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}: globalError(conf, sym.info, "dynlib needs to be a string lit") - var theAddr: pointer + var theAddr: pointer = nil if (lib.isNil or lib.kind == libHeader) and not gExeHandle.isNil: libPathMsg = "current exe: " & getAppFilename() & " nor libc: " & libcDll # first try this exe itself: @@ -108,6 +109,7 @@ proc mapCallConv(conf: ConfigRef, cc: TCallingConvention, info: TLineInfo): TABI of ccStdCall: result = when defined(windows) and defined(x86): STDCALL else: DEFAULT_ABI of ccCDecl: result = DEFAULT_ABI else: + result = default(TABI) globalError(conf, info, "cannot map calling convention to FFI") template rd(typ, p: untyped): untyped = (cast[ptr typ](p))[] @@ -132,6 +134,8 @@ proc packSize(conf: ConfigRef, v: PNode, typ: PType): int = result = sizeof(pointer) elif v.len != 0: result = v.len * packSize(conf, v[0], typ[1]) + else: + result = 0 else: result = getSize(conf, typ).int @@ -140,6 +144,7 @@ proc pack(conf: ConfigRef, v: PNode, typ: PType, res: pointer) proc getField(conf: ConfigRef, n: PNode; position: int): PSym = case n.kind of nkRecList: + result = nil for i in 0..= 5 else: @@ -644,7 +648,7 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool = let hashFile = toGeneratedFile(conf, conf.mangleModuleName(cfile.cname).AbsoluteFile, "sha1") let currentHash = footprint(conf, cfile) - var f: File + var f: File = default(File) if open(f, hashFile.string, fmRead): let oldHash = parseSecureHash(f.readLine()) close(f) @@ -779,6 +783,7 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body raise proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] = + result = @[] when defined(macosx): if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions: # if needed, add an option to skip or override location @@ -861,6 +866,7 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu result = conf.getNimcacheDir / RelativeFile(targetName) proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string = + result = "" if conf.hasHint(hintCC): if optListCmd in conf.globalOptions or conf.verbosity > 1: result = MsgKindToStr[hintCC] % (demangleModuleName(path.splitFile.name) & ": " & compileCmd) @@ -883,15 +889,15 @@ proc preventLinkCmdMaxCmdLen(conf: ConfigRef, linkCmd: string) = proc callCCompiler*(conf: ConfigRef) = var - linkCmd: string + linkCmd: string = "" extraCmds: seq[string] if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}: return # speed up that call if only compiling and no script shall be # generated #var c = cCompiler var script: Rope = "" - var cmds: TStringSeq - var prettyCmds: TStringSeq + var cmds: TStringSeq = default(TStringSeq) + var prettyCmds: TStringSeq = default(TStringSeq) let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx]) for idx, it in conf.toCompile: @@ -1022,8 +1028,9 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) = conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty) proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile): bool = + result = false if not fileExists(jsonFile) or not fileExists(conf.absOutFile): return true - var bcache: BuildCache + var bcache: BuildCache = default(BuildCache) try: bcache.fromJson(jsonFile.string.parseFile) except IOError, OSError, ValueError: stderr.write "Warning: JSON processing failed for: $#\n" % jsonFile.string @@ -1039,7 +1046,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute if $secureHashFile(file) != hash: return true proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) = - var bcache: BuildCache + var bcache: BuildCache = default(BuildCache) try: bcache.fromJson(jsonFile.string.parseFile) except ValueError, KeyError, JsonKindError: let e = getCurrentException() @@ -1052,7 +1059,8 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) = globalError(conf, gCmdLineInfo, "jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " % [outputCurrent, output, jsonFile.string]) - var cmds, prettyCmds: TStringSeq + var cmds: TStringSeq = default(TStringSeq) + var prettyCmds: TStringSeq= default(TStringSeq) let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx]) for (name, cmd) in bcache.compile: cmds.add cmd @@ -1062,6 +1070,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) = for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting) proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope = + result = "" for it in list: result.addf("--file:r\"$1\"$N", [rope(it.cname.string)]) diff --git a/compiler/filters.nim b/compiler/filters.nim index 8151c0b938..8d8af6b1c8 100644 --- a/compiler/filters.nim +++ b/compiler/filters.nim @@ -29,23 +29,30 @@ proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode = return n[i] proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char = + var x = getArg(conf, n, name, pos) if x == nil: result = default elif x.kind == nkCharLit: result = chr(int(x.intVal)) - else: invalidPragma(conf, n) + else: + result = default(char) + invalidPragma(conf, n) proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string = var x = getArg(conf, n, name, pos) if x == nil: result = default elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal - else: invalidPragma(conf, n) + else: + result = "" + invalidPragma(conf, n) proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool = var x = getArg(conf, n, name, pos) if x == nil: result = default elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false - else: invalidPragma(conf, n) + else: + result = false + invalidPragma(conf, n) proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream = var pattern = strArg(conf, call, "startswith", 1, "") diff --git a/compiler/gorgeimpl.nim b/compiler/gorgeimpl.nim index 558a6c9a3d..fb0fafc985 100644 --- a/compiler/gorgeimpl.nim +++ b/compiler/gorgeimpl.nim @@ -29,10 +29,11 @@ proc readOutput(p: Process): (string, int) = proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (string, int) = let workingDir = parentDir(toFullPath(conf, info)) + result = ("", 0) if cache.len > 0: let h = secureHash(cmd & "\t" & input & "\t" & cache) let filename = toGeneratedFile(conf, AbsoluteFile("gorge_" & $h), "txt").string - var f: File + var f: File = default(File) if optForceFullMake notin conf.globalOptions and open(f, filename): result = (f.readAll, 0) f.close diff --git a/compiler/guards.nim b/compiler/guards.nim index 15c6a64e36..1366a2382c 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -51,6 +51,10 @@ proc isLet(n: PNode): bool = elif n.sym.kind == skParam and skipTypes(n.sym.typ, abstractInst).kind notin {tyVar}: result = true + else: + result = false + else: + result = false proc isVar(n: PNode): bool = n.kind == nkSym and n.sym.kind in {skResult, skVar} and @@ -136,6 +140,8 @@ proc neg(n: PNode; o: Operators): PNode = result = a elif b != nil: result = b + else: + result = nil else: # leave not (a == 4) as it is result = newNodeI(nkCall, n.info, 2) @@ -330,6 +336,8 @@ proc usefulFact(n: PNode; o: Operators): PNode = result = n elif n[1].getMagic in someLen or n[2].getMagic in someLen: result = n + else: + result = nil of someLe+someLt: if isLetLocation(n[1], true) or isLetLocation(n[2], true): # XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1' @@ -337,12 +345,18 @@ proc usefulFact(n: PNode; o: Operators): PNode = elif n[1].getMagic in someLen or n[2].getMagic in someLen: # XXX Rethink this whole idea of 'usefulFact' for semparallel result = n + else: + result = nil of mIsNil: if isLetLocation(n[1], false) or isVar(n[1]): result = n + else: + result = nil of someIn: if isLetLocation(n[1], true): result = n + else: + result = nil of mAnd: let a = usefulFact(n[1], o) @@ -356,10 +370,14 @@ proc usefulFact(n: PNode; o: Operators): PNode = result = a elif b != nil: result = b + else: + result = nil of mNot: let a = usefulFact(n[1], o) if a != nil: result = a.neg(o) + else: + result = nil of mOr: # 'or' sucks! (p.isNil or q.isNil) --> hard to do anything # with that knowledge... @@ -376,6 +394,8 @@ proc usefulFact(n: PNode; o: Operators): PNode = result[1] = a result[2] = b result = result.neg(o) + else: + result = nil elif n.kind == nkSym and n.sym.kind == skLet: # consider: # let a = 2 < x @@ -384,8 +404,12 @@ proc usefulFact(n: PNode; o: Operators): PNode = # We make can easily replace 'a' by '2 < x' here: if n.sym.astdef != nil: result = usefulFact(n.sym.astdef, o) + else: + result = nil elif n.kind == nkStmtListExpr: result = usefulFact(n.lastSon, o) + else: + result = nil type TModel* = object @@ -451,8 +475,9 @@ proc hasSubTree(n, x: PNode): bool = of nkEmpty..nkNilLit: result = n.sameTree(x) of nkFormalParams: - discard + result = false else: + result = false for i in 0.. unknown! if sameTree(fact[2], eq[val]): result = impYes elif valuesUnequal(fact[2], eq[val]): result = impNo + else: + result = impUnknown elif sameTree(fact[2], eq[loc]): if sameTree(fact[1], eq[val]): result = impYes elif valuesUnequal(fact[1], eq[val]): result = impNo + else: + result = impUnknown + else: + result = impUnknown of mInSet: # remember: mInSet is 'contains' so the set comes first! if sameTree(fact[2], eq[loc]) and isValue(eq[val]): if inSet(fact[1], eq[val]): result = impYes else: result = impNo - of mNot, mOr, mAnd: assert(false, "impliesEq") - else: discard + else: + result = impUnknown + of mNot, mOr, mAnd: + result = impUnknown + assert(false, "impliesEq") + else: result = impUnknown proc leImpliesIn(x, c, aSet: PNode): TImplication = if c.kind in {nkCharLit..nkUInt64Lit}: @@ -512,13 +549,19 @@ proc leImpliesIn(x, c, aSet: PNode): TImplication = var value = newIntNode(c.kind, firstOrd(nil, x.typ)) # don't iterate too often: if c.intVal - value.intVal < 1000: - var i, pos, neg: int + var i, pos, neg: int = 0 while value.intVal <= c.intVal: if inSet(aSet, value): inc pos else: inc neg inc i; inc value.intVal if pos == i: result = impYes elif neg == i: result = impNo + else: + result = impUnknown + else: + result = impUnknown + else: + result = impUnknown proc geImpliesIn(x, c, aSet: PNode): TImplication = if c.kind in {nkCharLit..nkUInt64Lit}: @@ -529,17 +572,23 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication = let max = lastOrd(nil, x.typ) # don't iterate too often: if max - getInt(value) < toInt128(1000): - var i, pos, neg: int + var i, pos, neg: int = 0 while value.intVal <= max: if inSet(aSet, value): inc pos else: inc neg inc i; inc value.intVal if pos == i: result = impYes elif neg == i: result = impNo + else: result = impUnknown + else: + result = impUnknown + else: + result = impUnknown proc compareSets(a, b: PNode): TImplication = if equalSets(nil, a, b): result = impYes elif intersectSets(nil, a, b).len == 0: result = impNo + else: result = impUnknown proc impliesIn(fact, loc, aSet: PNode): TImplication = case fact[0].sym.magic @@ -550,22 +599,32 @@ proc impliesIn(fact, loc, aSet: PNode): TImplication = elif sameTree(fact[2], loc): if inSet(aSet, fact[1]): result = impYes else: result = impNo + else: + result = impUnknown of mInSet: if sameTree(fact[2], loc): result = compareSets(fact[1], aSet) + else: + result = impUnknown of someLe: if sameTree(fact[1], loc): result = leImpliesIn(fact[1], fact[2], aSet) elif sameTree(fact[2], loc): result = geImpliesIn(fact[2], fact[1], aSet) + else: + result = impUnknown of someLt: if sameTree(fact[1], loc): result = leImpliesIn(fact[1], fact[2].pred, aSet) elif sameTree(fact[2], loc): # 4 < x --> 3 <= x result = geImpliesIn(fact[2], fact[1].pred, aSet) - of mNot, mOr, mAnd: assert(false, "impliesIn") - else: discard + else: + result = impUnknown + of mNot, mOr, mAnd: + result = impUnknown + assert(false, "impliesIn") + else: result = impUnknown proc valueIsNil(n: PNode): TImplication = if n.kind == nkNilLit: impYes @@ -577,13 +636,19 @@ proc impliesIsNil(fact, eq: PNode): TImplication = of mIsNil: if sameTree(fact[1], eq[1]): result = impYes + else: + result = impUnknown of someEq: if sameTree(fact[1], eq[1]): result = valueIsNil(fact[2].skipConv) elif sameTree(fact[2], eq[1]): result = valueIsNil(fact[1].skipConv) - of mNot, mOr, mAnd: assert(false, "impliesIsNil") - else: discard + else: + result = impUnknown + of mNot, mOr, mAnd: + result = impUnknown + assert(false, "impliesIsNil") + else: result = impUnknown proc impliesGe(fact, x, c: PNode): TImplication = assert isLocation(x) @@ -594,32 +659,57 @@ proc impliesGe(fact, x, c: PNode): TImplication = # fact: x = 4; question x >= 56? --> true iff 4 >= 56 if leValue(c, fact[2]): result = impYes else: result = impNo + else: + result = impUnknown elif sameTree(fact[2], x): if isValue(fact[1]) and isValue(c): if leValue(c, fact[1]): result = impYes else: result = impNo + else: + result = impUnknown + else: + result = impUnknown of someLt: if sameTree(fact[1], x): if isValue(fact[2]) and isValue(c): # fact: x < 4; question N <= x? --> false iff N <= 4 if leValue(fact[2], c): result = impNo + else: result = impUnknown # fact: x < 4; question 2 <= x? --> we don't know + else: + result = impUnknown elif sameTree(fact[2], x): # fact: 3 < x; question: N-1 < x ? --> true iff N-1 <= 3 if isValue(fact[1]) and isValue(c): if leValue(c.pred, fact[1]): result = impYes + else: result = impUnknown + else: + result = impUnknown + else: + result = impUnknown of someLe: if sameTree(fact[1], x): if isValue(fact[2]) and isValue(c): # fact: x <= 4; question x >= 56? --> false iff 4 <= 56 if leValue(fact[2], c): result = impNo # fact: x <= 4; question x >= 2? --> we don't know + else: + result = impUnknown + else: + result = impUnknown elif sameTree(fact[2], x): # fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3 if isValue(fact[1]) and isValue(c): if leValue(c, fact[1]): result = impYes - of mNot, mOr, mAnd: assert(false, "impliesGe") - else: discard + else: result = impUnknown + else: + result = impUnknown + else: + result = impUnknown + of mNot, mOr, mAnd: + result = impUnknown + assert(false, "impliesGe") + else: result = impUnknown proc impliesLe(fact, x, c: PNode): TImplication = if not isLocation(x): @@ -634,35 +724,59 @@ proc impliesLe(fact, x, c: PNode): TImplication = # fact: x = 4; question x <= 56? --> true iff 4 <= 56 if leValue(fact[2], c): result = impYes else: result = impNo + else: + result = impUnknown elif sameTree(fact[2], x): if isValue(fact[1]) and isValue(c): if leValue(fact[1], c): result = impYes else: result = impNo + else: + result = impUnknown + else: + result = impUnknown of someLt: if sameTree(fact[1], x): if isValue(fact[2]) and isValue(c): # fact: x < 4; question x <= N? --> true iff N-1 <= 4 if leValue(fact[2], c.pred): result = impYes + else: + result = impUnknown # fact: x < 4; question x <= 2? --> we don't know + else: + result = impUnknown elif sameTree(fact[2], x): # fact: 3 < x; question: x <= 1 ? --> false iff 1 <= 3 if isValue(fact[1]) and isValue(c): if leValue(c, fact[1]): result = impNo - + else: result = impUnknown + else: + result = impUnknown + else: + result = impUnknown of someLe: if sameTree(fact[1], x): if isValue(fact[2]) and isValue(c): # fact: x <= 4; question x <= 56? --> true iff 4 <= 56 if leValue(fact[2], c): result = impYes + else: result = impUnknown # fact: x <= 4; question x <= 2? --> we don't know + else: + result = impUnknown elif sameTree(fact[2], x): # fact: 3 <= x; question: x <= 2 ? --> false iff 2 < 3 if isValue(fact[1]) and isValue(c): if leValue(c, fact[1].pred): result = impNo + else:result = impUnknown + else: + result = impUnknown + else: + result = impUnknown - of mNot, mOr, mAnd: assert(false, "impliesLe") - else: discard + of mNot, mOr, mAnd: + result = impUnknown + assert(false, "impliesLe") + else: result = impUnknown proc impliesLt(fact, x, c: PNode): TImplication = # x < 3 same as x <= 2: @@ -674,6 +788,8 @@ proc impliesLt(fact, x, c: PNode): TImplication = let q = x.pred if q != x: result = impliesLe(fact, q, c) + else: + result = impUnknown proc `~`(x: TImplication): TImplication = case x @@ -725,6 +841,7 @@ proc factImplies(fact, prop: PNode): TImplication = proc doesImply*(facts: TModel, prop: PNode): TImplication = assert prop.kind in nkCallKinds + result = impUnknown for f in facts.s: # facts can be invalidated, in which case they are 'nil': if not f.isNil: @@ -900,6 +1017,7 @@ proc applyReplacements(n: PNode; rep: TReplacements): PNode = proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication = # now check for inferrable facts: a <= b and b <= c implies a <= c + result = impUnknown for i in 0..m.s.high: let fact = m.s[i] if fact != nil and fact.getMagic in someLe: @@ -981,7 +1099,7 @@ proc addFactLt*(m: var TModel; a, b: PNode) = proc settype(n: PNode): PType = result = newType(tySet, ItemId(module: -1, item: -1), n.typ.owner) - var idgen: IdGenerator + var idgen: IdGenerator = nil addSonSkipIntLit(result, n.typ, idgen) proc buildOf(it, loc: PNode; o: Operators): PNode = diff --git a/compiler/hlo.nim b/compiler/hlo.nim index 2e1652f09d..744fddcc0f 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -20,9 +20,11 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode = # we need to ensure that the resulting AST is semchecked. However, it's # awful to semcheck before macro invocation, so we don't and treat # templates and macros as immediate in this context. - var rule: string - if c.config.hasHint(hintPattern): - rule = renderTree(n, {renderNoComments}) + var rule: string = + if c.config.hasHint(hintPattern): + renderTree(n, {renderNoComments}) + else: + "" let s = n[0].sym case s.kind of skMacro: diff --git a/compiler/ic/cbackend.nim b/compiler/ic/cbackend.nim index 21f69e4852..a1922c812d 100644 --- a/compiler/ic/cbackend.nim +++ b/compiler/ic/cbackend.nim @@ -101,7 +101,7 @@ proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool var f2 = rodfiles.open(asymFile.string) f2.loadHeader() f2.loadSection aliveSymsSection - var oldData: seq[int32] + var oldData: seq[int32] = @[] f2.loadSeq(oldData) f2.close if f2.err == ok and oldData == s: diff --git a/compiler/ic/dce.nim b/compiler/ic/dce.nim index bc61a38dec..ce64221010 100644 --- a/compiler/ic/dce.nim +++ b/compiler/ic/dce.nim @@ -40,10 +40,14 @@ proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): boo if ({sfExportc, sfCompilerProc} * flags != {}) or (symPtr.kind == skMethod): result = true + else: + result = false # XXX: This used to be a condition to: # (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or if sfCompilerProc in flags: c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId) + else: + result = false template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index a72db57c5f..c2f3f793c3 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -813,6 +813,7 @@ proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; tree: PackedTree; n: NodePos): PNode = + result = nil var i = 0 for n0 in sonsReadonly(tree, n): if i == bodyPos: @@ -1147,6 +1148,8 @@ proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache; if it.i < it.values.len: result = loadSym(it.decoder, g, int(module), it.values[it.i]) inc it.i + else: + result = nil proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache; g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym = @@ -1164,11 +1167,15 @@ proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache; if it.i < it.values.len: result = loadSym(it.decoder, g, int(module), it.values[it.i]) inc it.i + else: + result = nil proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym = if it.i < it.values.len: result = loadSym(it.decoder, g, it.module, it.values[it.i]) inc it.i + else: + result = nil iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache; g: var PackedModuleGraph; module: FileIndex; @@ -1201,7 +1208,7 @@ proc searchForCompilerproc*(m: LoadedModule; name: string): int32 = # ------------------------- .rod file viewer --------------------------------- proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) = - var m: PackedModule + var m: PackedModule = PackedModule() let err = loadRodFile(rodfile, m, config, ignoreConfig=true) if err != ok: config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim index cbba591c5a..ab49b3b7a1 100644 --- a/compiler/ic/navigator.nim +++ b/compiler/ic/navigator.nim @@ -34,7 +34,11 @@ proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool = if current.file == trackPos.file and current.line == trackPos.line: let col = trackPos.col if col >= current.col and col < current.col+tokenLen: - return true + result = true + else: + result = false + else: + result = false proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool = result = s.name != LitId(0) and diff --git a/compiler/ic/packed_ast.nim b/compiler/ic/packed_ast.nim index 0bf5cd4c31..8eafa5e968 100644 --- a/compiler/ic/packed_ast.nim +++ b/compiler/ic/packed_ast.nim @@ -305,6 +305,7 @@ proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) = result = (NodePos a, NodePos b, NodePos c) proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos = + result = default(NodePos) if tree.nodes[n.int].kind > nkNilLit: var count = 0 for child in sonsReadonly(tree, n): diff --git a/compiler/ic/rodfiles.nim b/compiler/ic/rodfiles.nim index e492624d04..41e85084f1 100644 --- a/compiler/ic/rodfiles.nim +++ b/compiler/ic/rodfiles.nim @@ -215,7 +215,7 @@ proc storeHeader*(f: var RodFile) = proc loadHeader*(f: var RodFile) = ## Loads the header which is described by `cookie`. if f.err != ok: return - var thisCookie: array[cookie.len, byte] + var thisCookie: array[cookie.len, byte] = default(array[cookie.len, byte]) if f.f.readBytes(thisCookie, 0, thisCookie.len) != thisCookie.len: setError f, ioFailure elif thisCookie != cookie: @@ -231,13 +231,14 @@ proc storeSection*(f: var RodFile; s: RodSection) = proc loadSection*(f: var RodFile; expected: RodSection) = ## read the bytes value of s, sets and error if the section is incorrect. if f.err != ok: return - var s: RodSection + var s: RodSection = default(RodSection) loadPrim(f, s) if expected != s and f.err == ok: setError f, wrongSection proc create*(filename: string): RodFile = ## create the file and open it for writing + result = default(RodFile) if not open(result.f, filename, fmWrite): setError result, cannotOpen @@ -245,5 +246,6 @@ proc close*(f: var RodFile) = close(f.f) proc open*(filename: string): RodFile = ## open the file for reading + result = default(RodFile) if not open(result.f, filename, fmRead): setError result, cannotOpen diff --git a/compiler/importer.nim b/compiler/importer.nim index 54489ada4e..f5eb5329d9 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -113,6 +113,7 @@ proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) = proc splitPragmas(c: PContext, n: PNode): (PNode, seq[TSpecialWord]) = template bail = globalError(c.config, n.info, "invalid pragma") + result = (nil, @[]) if n.kind == nkPragmaExpr: if n.len == 2 and n[1].kind == nkPragma: result[0] = n[0] @@ -307,6 +308,8 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym = suggestSym(c.graph, n.info, result, c.graph.usageSym, false) importStmtResult.add newSymNode(result, n.info) #newStrNode(toFullPath(c.config, f), n.info) + else: + result = nil proc afterImport(c: PContext, m: PSym) = # fixes bug #17510, for re-exported symbols diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 4463d1d694..aa6470d349 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -432,6 +432,7 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode = proc isCapturedVar(n: PNode): bool = let root = getRoot(n) if root != nil: result = root.name.s[0] == ':' + else: result = false proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode = result = newNodeIT(nkStmtListExpr, n.info, n.typ) @@ -733,7 +734,9 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false, result[^1] = maybeVoid(n[^1], s) dec c.inUncheckedAssignSection, inUncheckedAssignSection - else: assert(false) + else: + result = nil + assert(false) proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode = if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty: @@ -1042,6 +1045,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing of nkGotoState, nkState, nkAsmStmt: result = n else: + result = nil internalError(c.graph.config, n.info, "cannot inject destructors to node kind: " & $n.kind) proc sameLocation*(a, b: PNode): bool = diff --git a/compiler/int128.nim b/compiler/int128.nim index b0341eb379..6968b1f892 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -171,6 +171,7 @@ proc addToHex*(result: var string; arg: Int128) = i -= 1 proc toHex*(arg: Int128): string = + result = "" result.addToHex(arg) proc inc*(a: var Int128, y: uint32 = 1) = @@ -330,8 +331,8 @@ proc `*`*(a: Int128, b: int32): Int128 = if b < 0: result = -result -proc `*=`*(a: var Int128, b: int32): Int128 = - result = result * b +proc `*=`(a: var Int128, b: int32) = + a = a * b proc makeInt128(high, low: uint64): Int128 = result.udata[0] = cast[uint32](low) @@ -360,6 +361,7 @@ proc `*=`*(a: var Int128, b: Int128) = import bitops proc fastLog2*(a: Int128): int = + result = 0 if a.udata[3] != 0: return 96 + fastLog2(a.udata[3]) if a.udata[2] != 0: diff --git a/compiler/isolation_check.nim b/compiler/isolation_check.nim index 273bfb7f9f..5fd1b8d51b 100644 --- a/compiler/isolation_check.nim +++ b/compiler/isolation_check.nim @@ -21,6 +21,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool = case n.kind of nkRecList: + result = false for i in 0.. 2: @@ -833,7 +837,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = if mapType(n[1].typ) != etyBaseIndex: arithAux(p, n, r, op) else: - var x, y: TCompRes + var x, y: TCompRes = default(TCompRes) gen(p, n[1], x) gen(p, n[2], y) r.res = "($# == $# && $# == $#)" % [x.address, y.address, x.res, y.res] @@ -866,7 +870,7 @@ proc genLineDir(p: PProc, n: PNode) = p.previousFileName = currentFileName proc genWhileStmt(p: PProc, n: PNode) = - var cond: TCompRes + var cond: TCompRes = default(TCompRes) internalAssert p.config, isEmptyType(n.typ) genLineDir(p, n) inc(p.unique) @@ -961,6 +965,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = elif it.kind == nkType: throwObj = it else: + throwObj = nil internalError(p.config, n.info, "genTryStmt") if orExpr != "": orExpr.add("||") @@ -1001,7 +1006,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) = proc genRaiseStmt(p: PProc, n: PNode) = if n[0].kind != nkEmpty: - var a: TCompRes + var a: TCompRes = default(TCompRes) gen(p, n[0], a) let typ = skipTypes(n[0].typ, abstractPtrs) genLineDir(p, n) @@ -1015,7 +1020,7 @@ proc genRaiseStmt(p: PProc, n: PNode) = proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = var - a, b, cond, stmt: TCompRes + a, b, cond, stmt: TCompRes = default(TCompRes) genLineDir(p, n) gen(p, n[0], cond) let typeKind = skipTypes(n[0].typ, abstractVar).kind @@ -1149,7 +1154,7 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) = if false: discard else: - var r: TCompRes + var r = default(TCompRes) gen(p, it, r) if it.typ.kind == tyPointer: @@ -1165,13 +1170,13 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) = p.body.add(r.rdLoc) else: - var r: TCompRes + var r: TCompRes = default(TCompRes) gen(p, it, r) p.body.add(r.rdLoc) p.body.add "\L" proc genIf(p: PProc, n: PNode, r: var TCompRes) = - var cond, stmt: TCompRes + var cond, stmt: TCompRes = default(TCompRes) var toClose = 0 if not isEmptyType(n.typ): r.kind = resVal @@ -1208,6 +1213,7 @@ proc generateHeader(p: PProc, typ: PType): Rope = result.add("_Idx") proc countJsParams(typ: PType): int = + result = 0 for i in 1..= 3: # echo "BEGIN generating code for: " & prc.name.s var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options) @@ -2765,7 +2774,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope = # echo "END generated code for: " & prc.name.s proc genStmt(p: PProc, n: PNode) = - var r: TCompRes + var r: TCompRes = default(TCompRes) gen(p, n, r) if r.res != "": lineF(p, "$#;$n", [r.res]) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index ce36123b3a..ac4c160f93 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -187,6 +187,8 @@ proc getEnvParam*(routine: PSym): PSym = if hidden.kind == nkSym and hidden.sym.name.s == paramName: result = hidden.sym assert sfFromGeneric in result.flags + else: + result = nil proc interestingVar(s: PSym): bool {.inline.} = result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and @@ -199,6 +201,8 @@ proc illegalCapture(s: PSym): bool {.inline.} = proc isInnerProc(s: PSym): bool = if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone: result = s.skipGenericOwner.kind in routineKinds + else: + result = false proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode = # Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would @@ -711,6 +715,7 @@ proc symToClosure(n: PNode; owner: PSym; d: var DetectionPass; # direct dependency, so use the outer's env variable: result = makeClosure(d.graph, d.idgen, s, setupEnvVar(owner, d, c, n.info), n.info) else: + result = nil let available = getHiddenParam(d.graph, owner) let wanted = getHiddenParam(d.graph, s).typ # ugh: call through some other inner proc; @@ -936,7 +941,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym): result = newNodeI(nkStmtList, body.info) # static binding? - var env: PSym + var env: PSym = nil let op = call[0] if op.kind == nkSym and op.sym.isIterator: # createClosure() diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 5962c8b9bb..93a5f80406 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -148,9 +148,11 @@ proc isNimIdentifier*(s: string): bool = var i = 1 while i < sLen: if s[i] == '_': inc(i) - if i < sLen and s[i] notin SymChars: return + if i < sLen and s[i] notin SymChars: return false inc(i) result = true + else: + result = false proc `$`*(tok: Token): string = case tok.tokType @@ -537,8 +539,8 @@ proc getNumber(L: var Lexer, result: var Token) = of floatTypes: result.fNumber = parseFloat(result.literal) of tkUInt64Lit, tkUIntLit: - var iNumber: uint64 - var len: int + var iNumber: uint64 = uint64(0) + var len: int = 0 try: len = parseBiggestUInt(result.literal, iNumber) except ValueError: @@ -547,8 +549,8 @@ proc getNumber(L: var Lexer, result: var Token) = raise newException(ValueError, "invalid integer: " & result.literal) result.iNumber = cast[int64](iNumber) else: - var iNumber: int64 - var len: int + var iNumber: int64 = int64(0) + var len: int = 0 try: len = parseBiggestInt(result.literal, iNumber) except ValueError: @@ -1007,6 +1009,7 @@ proc getPrecedence*(tok: Token): int = else: return -10 proc newlineFollows*(L: Lexer): bool = + result = false var pos = L.bufpos while true: case L.buf[pos] @@ -1394,8 +1397,9 @@ proc rawGetTok*(L: var Lexer, tok: var Token) = proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream; cache: IdentCache; config: ConfigRef): int = - var lex: Lexer - var tok: Token + result = 0 + var lex: Lexer = default(Lexer) + var tok: Token = default(Token) initToken(tok) openLexer(lex, fileIdx, inputstream, cache, config) var prevToken = tkEof diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 11d483abb3..760ee27b5d 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -367,6 +367,8 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen) body.add newHookCall(c, op, x, y) result = true + else: + result = false elif tfHasAsgn in t.flags: var op: PSym if sameType(t, c.asgnForType): @@ -396,6 +398,8 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode; assert op.ast[genericParamsPos].kind == nkEmpty body.add newHookCall(c, op, x, y) result = true + else: + result = false proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) = let t = orig.skipTypes(abstractInst - {tyDistinct}) @@ -435,6 +439,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = onUse(c.info, op) body.add destructorCall(c, op, x) result = true + else: + result = false #result = addDestructorCall(c, t, body, x) of attachedAsgn, attachedSink, attachedTrace: var op = getAttachedOp(c.g, t, c.kind) @@ -455,6 +461,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = onUse(c.info, op) body.add newDeepCopyCall(c, op, x, y) result = true + else: + result = false of attachedWasMoved: var op = getAttachedOp(c.g, t, attachedWasMoved) @@ -469,6 +477,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = onUse(c.info, op) body.add genWasMovedCall(c, op, x) result = true + else: + result = false of attachedDup: var op = getAttachedOp(c.g, t, attachedDup) @@ -483,6 +493,8 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool = onUse(c.info, op) body.add newDupCall(c, op, x, y) result = true + else: + result = false proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode = var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info) @@ -1249,7 +1261,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf # bug #15122: We need to produce all prototypes before entering the # mind boggling recursion. Hacks like these imply we should rewrite # this module. - var generics: array[attachedWasMoved..attachedTrace, bool] + var generics: array[attachedWasMoved..attachedTrace, bool] = default(array[attachedWasMoved..attachedTrace, bool]) for k in attachedWasMoved..lastAttached: generics[k] = getAttachedOp(g, canon, k) != nil if not generics[k]: diff --git a/compiler/liftlocals.nim b/compiler/liftlocals.nim index 7ca46ab1b8..58c6189d40 100644 --- a/compiler/liftlocals.nim +++ b/compiler/liftlocals.nim @@ -49,6 +49,7 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) = liftLocals(it, i, c) proc lookupParam(params, dest: PNode): PSym = + result = nil if dest.kind != nkIdent: return nil for i in 1..= 0 and x[i] == ' ': dec(i) if i >= 0 and x[i] in s: result = true + else: + result = false const LineContinuationOprs = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', @@ -93,6 +95,7 @@ proc continueLine(line: string, inTripleString: bool): bool {.inline.} = line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs)) proc countTriples(s: string): int = + result = 0 var i = 0 while i+2 < s.len: if s[i] == '"' and s[i+1] == '"' and s[i+2] == '"': diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 17eedca924..8b9dd71fdc 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -298,7 +298,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) = var it: TTabIter var s = initTabIter(it, scope.symbols) var missingImpls = 0 - var unusedSyms: seq[tuple[sym: PSym, key: string]] + var unusedSyms: seq[tuple[sym: PSym, key: string]] = @[] while s != nil: if sfForward in s.flags and s.kind notin {skType, skModule}: # too many 'implementation of X' errors are annoying @@ -458,7 +458,7 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) = for (sym, depth, isLocal) in allSyms(c): let depth = -depth - 1 let dist = editDistance(name0, sym.name.s.nimIdentNormalize) - var msg: string + var msg: string = "" msg.add "\n ($1, $2): '$3'" % [$dist, $depth, sym.name.s] list.push SpellCandidate(dist: dist, depth: depth, msg: msg, sym: sym) @@ -488,6 +488,7 @@ proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PS var err = "ambiguous identifier: '" & s.name.s & "'" var i = 0 var ignoredModules = 0 + result = nil for candidate in importedItems(c, s.name): if i == 0: err.add " -- use one of the following:\n" else: err.add "\n" @@ -586,6 +587,8 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = amb = candidates.len > 1 if amb and checkAmbiguity in flags: errorUseQualifier(c, n.info, candidates) + else: + result = nil if result == nil: let candidates = allPureEnumFields(c, ident) if candidates.len > 0: @@ -641,6 +644,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = o.marked = initIntSet() case n.kind of nkIdent, nkAccQuoted: + result = nil var ident = considerQuotedIdent(c, n) var scope = c.currentScope o.mode = oimNoQualifier @@ -664,6 +668,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = result = n.sym o.mode = oimDone of nkDotExpr: + result = nil o.mode = oimOtherModule o.m = qualifiedLookUp(c, n[0], {checkUndeclared, checkModule}) if o.m != nil and o.m.kind == skModule: @@ -693,7 +698,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = o.symChoiceIndex = 1 o.marked = initIntSet() incl(o.marked, result.id) - else: discard + else: result = nil when false: if result != nil and result.kind == skStub: loadStub(result) @@ -708,6 +713,7 @@ proc lastOverloadScope*(o: TOverloadIter): int = else: result = -1 proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym = + result = nil assert o.currentScope == nil var idx = o.importIdx+1 o.importIdx = c.imports.len # assume the other imported modules lack this symbol too @@ -720,6 +726,7 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym inc idx proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym = + result = nil assert o.currentScope == nil while o.importIdx < c.imports.len: result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph) @@ -782,6 +789,8 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = break if result != nil: incl o.marked, result.id + else: + result = nil of oimSymChoiceLocalLookup: if o.currentScope != nil: result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked) @@ -805,13 +814,16 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = if result == nil: inc o.importIdx result = symChoiceExtension(o, c, n) + else: + result = nil when false: if result != nil and result.kind == skStub: loadStub(result) proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind]; flags: TSymFlags = {}): PSym = - var o: TOverloadIter + result = nil + var o: TOverloadIter = default(TOverloadIter) var a = initOverloadIter(o, c, n) while a != nil: if a.kind in kinds and flags <= a.flags: diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index becde13e6d..1b692f5d62 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -30,6 +30,7 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym = result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule) proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym = + result = nil let id = getIdent(g.cache, name) for r in systemModuleSyms(g, id): if r.magic == m: @@ -145,6 +146,7 @@ proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym = of tyProc: result = getSysMagic(g, info, "==", mEqProc) else: + result = nil globalError(g.config, info, "can't find magic equals operator for type kind " & $t.kind) diff --git a/compiler/main.nim b/compiler/main.nim index 364fba92e5..836f912bbc 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -56,7 +56,7 @@ proc writeCMakeDepsFile(conf: ConfigRef) = for it in conf.toCompile: cfiles.add(it.cname.string) let fileset = cfiles.toCountTable() # read old cfiles list - var fl: File + var fl: File = default(File) var prevset = initCountTable[string]() if open(fl, fname.string, fmRead): for line in fl.lines: prevset.inc(line) @@ -196,7 +196,7 @@ proc commandScan(cache: IdentCache, config: ConfigRef) = if stream != nil: var L: Lexer - tok: Token + tok: Token = default(Token) initToken(tok) openLexer(L, f, stream, cache, config) while true: diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 08cdbfd0db..f9d0578b5c 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -368,6 +368,7 @@ proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) = setAttachedOp(g, module, dest, k, op) proc loadCompilerProc*(g: ModuleGraph; name: string): PSym = + result = nil if g.config.symbolFiles == disabledSf: return nil # slow, linear search, but the results are cached: @@ -500,6 +501,7 @@ proc resetAllModules*(g: ModuleGraph) = initModuleGraphFields(g) proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = + result = nil if fileIdx.int32 >= 0: if isCachedModule(g, fileIdx.int32): result = g.packed[fileIdx.int32].module @@ -605,6 +607,7 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) = proc needsCompilation*(g: ModuleGraph): bool = # every module that *depends* on this file is also dirty: + result = false for i in 0i32..= 0: result.add "\n" & indent & spaces(info.col) & '^' + else: + result = "" proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string = let title = case msg diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index 5cc66f3ea4..96e0967702 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -309,6 +309,7 @@ proc symbol(n: PNode): Symbol = # echo "symbol ", n, " ", n.kind, " ", result.int func `$`(map: NilMap): string = + result = "" var now = map var stack: seq[NilMap] = @[] while not now.isNil: @@ -416,7 +417,7 @@ proc moveOut(ctx: NilCheckerContext, map: NilMap, target: PNode) = if targetSetIndex != noSetIndex: var targetSet = map.sets[targetSetIndex] if targetSet.len > 1: - var other: ExprIndex + var other: ExprIndex = default(ExprIndex) for element in targetSet: if element.ExprIndex != targetIndex: @@ -561,7 +562,7 @@ proc derefWarning(n, ctx, map; kind: Nilability) = if n.info in ctx.warningLocations: return ctx.warningLocations.incl(n.info) - var a: seq[History] + var a: seq[History] = @[] if n.kind == nkSym: a = history(map, ctx.index(n)) var res = "" @@ -765,7 +766,7 @@ proc checkIf(n, ctx, map): Check = # the state of the conditions: negating conditions before the current one var layerHistory = newNilMap(mapIf) # the state after branch effects - var afterLayer: NilMap + var afterLayer: NilMap = nil # the result nilability for expressions var nilability = Safe @@ -862,9 +863,10 @@ proc checkInfix(n, ctx, map): Check = ## a or b : map is an union of a and b's ## a == b : use checkCondition ## else: no change, just check args + result = default(Check) if n[0].kind == nkSym: - var mapL: NilMap - var mapR: NilMap + var mapL: NilMap = nil + var mapR: NilMap = nil if n[0].sym.magic notin {mAnd, mEqRef}: mapL = checkCondition(n[1], ctx, map, false, false) mapR = checkCondition(n[2], ctx, map, false, false) @@ -947,7 +949,7 @@ proc checkCase(n, ctx, map): Check = let base = n[0] result.map = map.copyMap() result.nilability = Safe - var a: PNode + var a: PNode = nil for child in n: case child.kind: of nkOfBranch: @@ -1222,7 +1224,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check = # TODO deeper nested elements? # A(field: B()) # # field: Safe -> - var elements: seq[(PNode, Nilability)] + var elements: seq[(PNode, Nilability)] = @[] for i, child in n: result = check(child, ctx, result.map) if i > 0: @@ -1333,7 +1335,7 @@ proc preVisit(ctx: NilCheckerContext, s: PSym, body: PNode, conf: ConfigRef) = ctx.symbolIndices = {resultId: resultExprIndex}.toTable() var cache = newIdentCache() ctx.expressions = SeqOfDistinct[ExprIndex, PNode](@[newIdentNode(cache.getIdent("result"), s.ast.info)]) - var emptySet: IntSet # set[ExprIndex] + var emptySet: IntSet = initIntSet() # set[ExprIndex] ctx.dependants = SeqOfDistinct[ExprIndex, IntSet](@[emptySet]) for i, arg in s.typ.n.sons: if i > 0: diff --git a/compiler/nim.cfg b/compiler/nim.cfg index c32dba4d13..4c55a04cbc 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -43,3 +43,10 @@ define:useStdoutAsStdmsg @if nimHasWarnBareExcept: warningAserror[BareExcept]:on @end + + +@if nimUseStrictDefs: + experimental:strictDefs + warningAsError[Uninit]:on + warningAsError[ProveInit]:on +@end diff --git a/compiler/nim.nim b/compiler/nim.nim index b28e8b20c6..d05f01c427 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -91,6 +91,9 @@ proc getNimRunExe(conf: ConfigRef): string = if conf.isDefined("mingw"): if conf.isDefined("i386"): result = "wine" elif conf.isDefined("amd64"): result = "wine64" + else: result = "" + else: + result = "" proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = let self = NimProg( diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 440d35fe52..97a66f1cd9 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -37,11 +37,16 @@ proc isSpecial(ver: Version): bool = proc isValidVersion(v: string): bool = if v.len > 0: - if v[0] in {'#'} + Digits: return true + if v[0] in {'#'} + Digits: + result = true + else: + result = false + else: + result = false proc `<`*(ver: Version, ver2: Version): bool = ## This is synced from Nimble's version module. - + result = false # Handling for special versions such as "#head" or "#branch". if ver.isSpecial or ver2.isSpecial: if ver2.isSpecial and ($ver2).normalize == "#head": @@ -145,7 +150,7 @@ proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) = conf.lazyPaths.insert(AbsoluteDir path, 0) proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) = - var packages: PackageInfo + var packages: PackageInfo = initTable[string, tuple[version, checksum: string]]() var pos = dir.len-1 if dir[pos] in {DirSep, AltSep}: inc(pos) for k,p in os.walkDir(dir): diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index fceedb2c48..f7bae4b368 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -214,7 +214,7 @@ proc parseAssignment(L: var Lexer, tok: var Token; proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache; config: ConfigRef): bool = var - L: Lexer + L: Lexer = default(Lexer) tok: Token stream: PLLStream stream = llStreamOpen(filename, fmRead) @@ -228,6 +228,8 @@ proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache; if condStack.len > 0: lexMessage(L, errGenerated, "expected @end") closeLexer(L) return true + else: + result = false proc getUserConfigPath*(filename: RelativeFile): AbsoluteFile = result = getConfigDir().AbsoluteDir / RelativeDir"nim" / filename @@ -250,7 +252,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen: template runNimScriptIfExists(path: AbsoluteFile, isMain = false) = let p = path # eval once - var s: PLLStream + var s: PLLStream = nil if isMain and optWasNimscript in conf.globalOptions: if conf.projectIsStdin: s = stdin.llStreamOpen elif conf.projectIsCmd: s = llStreamOpen(conf.cmdInput) diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim index 49c80065ae..59a542a858 100644 --- a/compiler/nimsets.nim +++ b/compiler/nimsets.nim @@ -62,7 +62,9 @@ proc someInSet*(s: PNode, a, b: PNode): bool = result = false proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet = - var first, j: Int128 + result = @[] + var first: Int128 = Zero + var j: Int128 = Zero first = firstOrd(conf, s.typ[0]) bitSetInit(result, int(getSize(conf, s.typ))) for i in 0.. 0: let b = a.split(".") assert b.len == 3, a @@ -657,7 +658,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = of "nimrawsetjmp": result = conf.target.targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osMacosx} - else: discard + else: result = false template quitOrRaise*(conf: ConfigRef, msg = "") = # xxx in future work, consider whether to also intercept `msgQuit` calls @@ -883,6 +884,7 @@ const stdPrefix = "std/" proc getRelativePathFromConfigPath*(conf: ConfigRef; f: AbsoluteFile, isTitle = false): RelativeFile = + result = RelativeFile("") let f = $f if isTitle: for dir in stdlibDirs: @@ -918,6 +920,7 @@ proc findModule*(conf: ConfigRef; modulename, currentModule: string): AbsoluteFi result = findFile(conf, m.substr(pkgPrefix.len), suppressStdlib = true) else: if m.startsWith(stdPrefix): + result = AbsoluteFile("") let stripped = m.substr(stdPrefix.len) for candidate in stdlibDirs: let path = (conf.libpath.string / candidate / stripped) diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim index 8cf209779e..30f407792a 100644 --- a/compiler/packagehandling.nim +++ b/compiler/packagehandling.nim @@ -17,6 +17,7 @@ iterator myParentDirs(p: string): string = proc getNimbleFile*(conf: ConfigRef; path: string): string = ## returns absolute path to nimble file, e.g.: /pathto/cligen.nimble + result = "" var parents = 0 block packageSearch: for d in myParentDirs(path): diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 534c3b5d18..98f5099d68 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -184,6 +184,7 @@ type arStrange # it is a strange beast like 'typedesc[var T]' proc exprRoot*(n: PNode; allowCalls = true): PSym = + result = nil var it = n while true: case it.kind diff --git a/compiler/parser.nim b/compiler/parser.nim index 7d12c2a785..c386df57bf 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1177,6 +1177,7 @@ proc optPragmas(p: var Parser): PNode = proc parseDoBlock(p: var Parser; info: TLineInfo): PNode = #| doBlock = 'do' paramListArrow pragma? colcom stmt + result = nil var params = parseParamList(p, retColon=false) let pragmas = optPragmas(p) colcom(p, result) @@ -1430,6 +1431,7 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode = result = newNodeP(nkObjectTy, p) getTok(p) of tkConcept: + result = nil parMessage(p, "the 'concept' keyword is only valid in 'type' sections") of tkVar: result = parseTypeDescKAux(p, nkVarTy, pmTypeDesc) of tkOut: result = parseTypeDescKAux(p, nkOutTy, pmTypeDesc) diff --git a/compiler/patterns.nim b/compiler/patterns.nim index ff9a9efa34..7b0d7e4fb4 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -29,6 +29,8 @@ type proc getLazy(c: PPatternContext, sym: PSym): PNode = if c.mappingIsFull: result = c.mapping[sym.position] + else: + result = nil proc putLazy(c: PPatternContext, sym: PSym, n: PNode) = if not c.mappingIsFull: @@ -65,14 +67,21 @@ proc sameTrees*(a, b: PNode): bool = for i in 0..= 2: for i in 1.. 1 var key = if keyDeep: it[0] else: it diff --git a/compiler/renderer.nim b/compiler/renderer.nim index b9c3268c4c..2af8d83269 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -76,6 +76,8 @@ proc isKeyword*(i: PIdent): bool = if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)): result = true + else: + result = false proc isExported(n: PNode): bool = ## Checks if an ident is exported. @@ -274,6 +276,7 @@ proc putComment(g: var TSrcGen, s: string) = optNL(g) proc maxLineLength(s: string): int = + result = 0 if s.len == 0: return 0 var i = 0 let hi = s.len - 1 @@ -371,6 +374,7 @@ proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string = tyLent, tyDistinct, tyOrdinal, tyAlias, tySink}: result = lastSon(result) + result = "" let typ = n.typ.skip if typ != nil and typ.kind in {tyBool, tyEnum}: if sfPure in typ.sym.flags: @@ -488,6 +492,7 @@ proc referencesUsing(n: PNode): bool = proc lsub(g: TSrcGen; n: PNode): int = # computes the length of a tree + result = 0 if isNil(n): return 0 if shouldRenderComment(g, n): return MaxLineLen + 1 case n.kind @@ -631,7 +636,7 @@ proc initContext(c: var TContext) = proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) proc gsub(g: var TSrcGen, n: PNode, fromStmtList = false) = - var c: TContext + var c: TContext = default(TContext) initContext(c) gsub(g, n, c, fromStmtList = fromStmtList) @@ -762,7 +767,7 @@ proc gcond(g: var TSrcGen, n: PNode) = put(g, tkParRi, ")") proc gif(g: var TSrcGen, n: PNode) = - var c: TContext + var c: TContext = default(TContext) gcond(g, n[0][0]) initContext(c) putWithSpace(g, tkColon, ":") @@ -775,7 +780,7 @@ proc gif(g: var TSrcGen, n: PNode) = gsub(g, n[i], c) proc gwhile(g: var TSrcGen, n: PNode) = - var c: TContext + var c: TContext = default(TContext) putWithSpace(g, tkWhile, "while") gcond(g, n[0]) putWithSpace(g, tkColon, ":") @@ -786,7 +791,7 @@ proc gwhile(g: var TSrcGen, n: PNode) = gstmts(g, n[1], c) proc gpattern(g: var TSrcGen, n: PNode) = - var c: TContext + var c: TContext = default(TContext) put(g, tkCurlyLe, "{") initContext(c) if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen): @@ -796,7 +801,7 @@ proc gpattern(g: var TSrcGen, n: PNode) = put(g, tkCurlyRi, "}") proc gpragmaBlock(g: var TSrcGen, n: PNode) = - var c: TContext + var c: TContext = default(TContext) gsub(g, n[0]) putWithSpace(g, tkColon, ":") initContext(c) @@ -806,7 +811,7 @@ proc gpragmaBlock(g: var TSrcGen, n: PNode) = gstmts(g, n[1], c) proc gtry(g: var TSrcGen, n: PNode) = - var c: TContext + var c: TContext = default(TContext) put(g, tkTry, "try") putWithSpace(g, tkColon, ":") initContext(c) @@ -817,7 +822,7 @@ proc gtry(g: var TSrcGen, n: PNode) = gsons(g, n, c, 1) proc gfor(g: var TSrcGen, n: PNode) = - var c: TContext + var c: TContext = default(TContext) putWithSpace(g, tkFor, "for") initContext(c) if longMode(g, n) or @@ -832,7 +837,7 @@ proc gfor(g: var TSrcGen, n: PNode) = gstmts(g, n[^1], c) proc gcase(g: var TSrcGen, n: PNode) = - var c: TContext + var c: TContext = default(TContext) initContext(c) if n.len == 0: return var last = if n[^1].kind == nkElse: -2 else: -1 @@ -853,7 +858,7 @@ proc genSymSuffix(result: var string, s: PSym) {.inline.} = result.addInt s.id proc gproc(g: var TSrcGen, n: PNode) = - var c: TContext + var c: TContext = default(TContext) if n[namePos].kind == nkSym: let s = n[namePos].sym var ret = renderDefinitionName(s) @@ -889,7 +894,7 @@ proc gproc(g: var TSrcGen, n: PNode) = dedent(g) proc gTypeClassTy(g: var TSrcGen, n: PNode) = - var c: TContext + var c: TContext = default(TContext) initContext(c) putWithSpace(g, tkConcept, "concept") gsons(g, n[0], c) # arglist @@ -909,7 +914,7 @@ proc gblock(g: var TSrcGen, n: PNode) = if n.len == 0: return - var c: TContext + var c: TContext = default(TContext) initContext(c) if n[0].kind != nkEmpty: @@ -930,7 +935,7 @@ proc gblock(g: var TSrcGen, n: PNode) = gstmts(g, n[1], c) proc gstaticStmt(g: var TSrcGen, n: PNode) = - var c: TContext + var c: TContext = default(TContext) putWithSpace(g, tkStatic, "static") putWithSpace(g, tkColon, ":") initContext(c) @@ -1005,6 +1010,7 @@ proc bracketKind*(g: TSrcGen, n: PNode): BracketKind = case n.kind of nkClosedSymChoice, nkOpenSymChoice: if n.len > 0: result = bracketKind(g, n[0]) + else: result = bkNone of nkSym: result = case n.sym.name.s of "[]": bkBracket @@ -1013,6 +1019,8 @@ proc bracketKind*(g: TSrcGen, n: PNode): BracketKind = of "{}=": bkCurlyAsgn else: bkNone else: result = bkNone + else: + result = bkNone proc skipHiddenNodes(n: PNode): PNode = result = n @@ -1085,11 +1093,13 @@ proc isCustomLit(n: PNode): bool = if n.len == 2 and n[0].kind == nkRStrLit: let ident = n[1].getPIdent result = ident != nil and ident.s.startsWith('\'') + else: + result = false proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = if isNil(n): return var - a: TContext + a: TContext = default(TContext) if shouldRenderComment(g, n): pushCom(g, n) case n.kind # atoms: of nkTripleStrLit: put(g, tkTripleStrLit, atom(g, n)) @@ -1437,6 +1447,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = if n.kind in {nkIdent, nkSym}: let tmp = n.getPIdent.s result = tmp.len > 0 and tmp[0] in {'a'..'z', 'A'..'Z'} + else: + result = false var useSpace = false if i == 1 and n[0].kind == nkIdent and n[0].ident.s in ["=", "'"]: if not n[1].isAlpha: # handle `=destroy`, `'big' @@ -1787,12 +1799,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = gsub(g, n, 0) put(g, tkParRi, ")") of nkGotoState: - var c: TContext + var c: TContext = default(TContext) initContext c putWithSpace g, tkSymbol, "goto" gsons(g, n, c) of nkState: - var c: TContext + var c: TContext = default(TContext) initContext c putWithSpace g, tkSymbol, "state" gsub(g, n[0], c) @@ -1817,7 +1829,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string = if n == nil: return "" - var g: TSrcGen + var g: TSrcGen = default(TSrcGen) initSrcGen(g, renderFlags, newPartialConfigRef()) # do not indent the initial statement list so that # writeFile("file.nim", repr n) @@ -1835,7 +1847,7 @@ proc renderModule*(n: PNode, outfile: string, fid = FileIndex(-1); conf: ConfigRef = nil) = var - f: File + f: File = default(File) g: TSrcGen initSrcGen(g, renderFlags, conf) g.fid = fid diff --git a/compiler/renderverbatim.nim b/compiler/renderverbatim.nim index 792079b3f4..00d546198a 100644 --- a/compiler/renderverbatim.nim +++ b/compiler/renderverbatim.nim @@ -40,6 +40,7 @@ type LineData = object proc tripleStrLitStartsAtNextLine(conf: ConfigRef, n: PNode): bool = # enabling TLineInfo.offsetA,offsetB would probably make this easier + result = false const tripleQuote = "\"\"\"" let src = sourceLine(conf, n.info) let col = n.info.col diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 4ad3f12194..f43ddc2031 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -115,6 +115,7 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev for i in 0.. 0: # we avoid running more diagnostic when inside a `compiles(expr)`, to # errors while running diagnostic (see test D20180828T234921), and @@ -405,8 +406,9 @@ proc resolveOverloads(c: PContext, n, orig: PNode, filter: TSymKinds, flags: TExprFlags, errors: var CandidateErrors, errorsEnabled: bool): TCandidate = + result = default(TCandidate) var initialBinding: PNode - var alt: TCandidate + var alt: TCandidate = default(TCandidate) var f = n[0] if f.kind == nkBracketExpr: # fill in the bindings: @@ -569,8 +571,8 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) = if expectedType == nil or x.callee[0] == nil: return # required for inference var - flatUnbound: seq[PType] - flatBound: seq[PType] + flatUnbound: seq[PType] = @[] + flatBound: seq[PType] = @[] # seq[(result type, expected type)] var typeStack = newSeq[(PType, PType)]() @@ -694,7 +696,10 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, # this time enabling all the diagnostic output (this should fail again) result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain}) elif efNoUndeclared notin flags: + result = nil notFoundError(c, n, errors) + else: + result = nil proc explicitGenericInstError(c: PContext; n: PNode): PNode = localError(c.config, getCallLineInfo(n), errCannotInstantiateX % renderTree(n)) @@ -771,6 +776,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym = # for borrowing the sym in the symbol table is returned, else nil. # New approach: generate fn(x, y, z) where x, y, z have the proper types # and use the overloading resolution mechanism: + result = nil var call = newNodeI(nkCall, fn.info) var hasDistinct = false call.add(newIdentNode(fn.name, fn.info)) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b7fc7a9bd8..dca4ce6e0d 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -655,7 +655,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp else: discard rawAddSon(result.typ, nil) # index type var - firstIndex, lastIndex: Int128 + firstIndex, lastIndex: Int128 = Zero indexType = getSysType(c.graph, n.info, tyInt) lastValidIndex = lastOrd(c.config, indexType) if n.len == 0: @@ -990,6 +990,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, proc resolveIndirectCall(c: PContext; n, nOrig: PNode; t: PType): TCandidate = + result = default(TCandidate) initCandidate(c, result, t) matches(c, n, nOrig, result) @@ -998,6 +999,8 @@ proc bracketedMacro(n: PNode): PSym = result = n[0].sym if result.kind notin {skMacro, skTemplate}: result = nil + else: + result = nil proc setGenericParams(c: PContext, n: PNode) = for i in 1.. 0: # don't interpret () as type isTupleType = tupexp[0].typ.kind == tyTypeDesc # check if either everything or nothing is tyTypeDesc @@ -2837,6 +2843,7 @@ proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PTyp result = tupexp proc shouldBeBracketExpr(n: PNode): bool = + result = false assert n.kind in nkCallKinds let a = n[0] if a.kind in nkCallKinds: @@ -2854,6 +2861,8 @@ proc asBracketExpr(c: PContext; n: PNode): PNode = if n.kind in {nkIdent, nkAccQuoted}: let s = qualifiedLookUp(c, n, {}) result = s != nil and isGenericRoutineStrict(s) + else: + result = false assert n.kind in nkCallKinds if n.len > 1 and isGeneric(c, n[1]): @@ -2983,7 +2992,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType if nfSem in n.flags: return case n.kind of nkIdent, nkAccQuoted: - var s: PSym + var s: PSym = nil if expectedType != nil and ( let expected = expectedType.skipTypes(abstractRange-{tyDistinct}); expected.kind == tyEnum): diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 07c3b3ae4e..a60bfee2a9 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -65,24 +65,34 @@ proc foldAdd(a, b: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode let res = a + b if checkInRange(g.config, n, res): result = newIntNodeT(res, n, idgen, g) + else: + result = nil proc foldSub(a, b: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = let res = a - b if checkInRange(g.config, n, res): result = newIntNodeT(res, n, idgen, g) + else: + result = nil proc foldUnarySub(a: Int128, n: PNode; idgen: IdGenerator, g: ModuleGraph): PNode = if a != firstOrd(g.config, n.typ): result = newIntNodeT(-a, n, idgen, g) + else: + result = nil proc foldAbs(a: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = if a != firstOrd(g.config, n.typ): result = newIntNodeT(abs(a), n, idgen, g) + else: + result = nil proc foldMul(a, b: Int128, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = let res = a * b if checkInRange(g.config, n, res): return newIntNodeT(res, n, idgen, g) + else: + result = nil proc ordinalValToString*(a: PNode; g: ModuleGraph): string = # because $ has the param ordinal[T], `a` is not necessarily an enum, but an @@ -94,6 +104,7 @@ proc ordinalValToString*(a: PNode; g: ModuleGraph): string = of tyChar: result = $chr(toInt64(x) and 0xff) of tyEnum: + result = "" var n = t.n for i in 0.. 2: b = getConstExpr(m, n[2], idgen, g) @@ -396,7 +407,9 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P of tyBool, tyEnum: # xxx shouldn't we disallow `tyEnum`? result = a result.typ = n.typ - else: doAssert false, $srcTyp.kind + else: + result = nil + doAssert false, $srcTyp.kind of tyInt..tyInt64, tyUInt..tyUInt64: case srcTyp.kind of tyFloat..tyFloat64: @@ -420,7 +433,7 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P result = a result.typ = n.typ of tyOpenArray, tyVarargs, tyProc, tyPointer: - discard + result = nil else: result = a result.typ = n.typ @@ -447,21 +460,25 @@ proc foldArrayAccess(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNo result = x.sons[idx] if result.kind == nkExprColonExpr: result = result[1] else: + result = nil localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n) of nkBracket: idx -= toInt64(firstOrd(g.config, x.typ)) if idx >= 0 and idx < x.len: result = x[int(idx)] - else: localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n) + else: + result = nil + localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n) of nkStrLit..nkTripleStrLit: result = newNodeIT(nkCharLit, x.info, n.typ) if idx >= 0 and idx < x.strVal.len: result.intVal = ord(x.strVal[int(idx)]) else: localError(g.config, n.info, formatErrorIndexBound(idx, x.strVal.len-1) & $n) - else: discard + else: result = nil proc foldFieldAccess(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = # a real field access; proc calls have already been transformed + result = nil if n[1].kind != nkSym: return nil var x = getConstExpr(m, n[0], idgen, g) if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return @@ -496,6 +513,7 @@ proc newSymNodeTypeDesc*(s: PSym; idgen: IdGenerator; info: TLineInfo): PNode = result.typ = s.typ proc foldDefine(m, s: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode = + result = nil var name = s.name.s let prag = extractPragma(s) if prag != nil: diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 70cb64b516..43b8d4bac4 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -59,6 +59,7 @@ template isMixedIn(sym): bool = proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, ctx: var GenericCtx; flags: TSemGenericFlags, fromDotExpr=false): PNode = + result = nil semIdeForTemplateOrGenericCheck(c.config, n, ctx.cursorInBody) incl(s.flags, sfUsed) template maybeDotChoice(c: PContext, n: PNode, s: PSym, fromDotExpr: bool) = @@ -439,7 +440,7 @@ proc semGenericStmt(c: PContext, n: PNode, if n[0].kind != nkEmpty: n[0] = semGenericStmt(c, n[0], flags+{withinTypeDesc}, ctx) for i in 1..= 0 and c.locals[s].stride != nil: result = c.locals[s].stride.intVal + else: + result = 0 else: + result = 0 for i in 0..= 1: p[0] else: p @@ -2251,7 +2266,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = of nkIdentDefs: var def = a[^1] let constraint = a[^2] - var typ: PType + var typ: PType = nil if constraint.kind != nkEmpty: typ = semTypeNode(c, constraint, nil) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 7c9bf9039d..19aa8be291 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -36,6 +36,7 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) = localError(info, errInheritanceOnlyWithNonFinalObjects) proc searchInstTypes*(g: ModuleGraph; key: PType): PType = + result = nil let genericTyp = key[0] if not (genericTyp.kind == tyGenericBody and genericTyp.sym != nil): return @@ -100,6 +101,7 @@ proc newTypeMapLayer*(cl: var TReplTypeVars): LayeredIdTable = initIdTable(result.topLayer) proc lookup(typeMap: LayeredIdTable, key: PType): PType = + result = nil var tm = typeMap while tm != nil: result = PType(idTableGet(tm.topLayer, key)) @@ -683,6 +685,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = proc initTypeVars*(p: PContext, typeMap: LayeredIdTable, info: TLineInfo; owner: PSym): TReplTypeVars = + result = default(TReplTypeVars) initIdTable(result.symMap) initIdTable(result.localCache) result.typeMap = typeMap diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 2d91fb2a01..9940d0c68e 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -159,7 +159,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi else: c.hashSym(t.sym) - var symWithFlags: PSym + var symWithFlags: PSym = nil template hasFlag(sym): bool = let ret = {sfAnon, sfGenSym} * sym.flags != {} if ret: symWithFlags = sym @@ -260,6 +260,7 @@ when defined(debugSigHashes): # (select hash from sighashes group by hash having count(*) > 1) order by hash; proc hashType*(t: PType; conf: ConfigRef; flags: set[ConsiderFlag] = {CoType}): SigHash = + result = default(SigHash) var c: MD5Context md5Init c hashType c, t, flags+{CoOwnerSig}, conf @@ -269,6 +270,7 @@ proc hashType*(t: PType; conf: ConfigRef; flags: set[ConsiderFlag] = {CoType}): typeToString(t), $result) proc hashProc(s: PSym; conf: ConfigRef): SigHash = + result = default(SigHash) var c: MD5Context md5Init c hashType c, s.typ, {CoProc}, conf @@ -289,6 +291,7 @@ proc hashProc(s: PSym; conf: ConfigRef): SigHash = md5Final c, result.MD5Digest proc hashNonProc*(s: PSym): SigHash = + result = default(SigHash) var c: MD5Context md5Init c hashSym(c, s) @@ -305,6 +308,7 @@ proc hashNonProc*(s: PSym): SigHash = md5Final c, result.MD5Digest proc hashOwner*(s: PSym): SigHash = + result = default(SigHash) var c: MD5Context md5Init c var m = s @@ -374,7 +378,7 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash = ## compute unique digest of the proc/func/method symbols ## recursing into invoked symbols as well assert(sym.kind in skProcKinds, $sym.kind) - + result = default(SigHash) graph.symBodyHashes.withValue(sym.id, value): return value[] diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 12cc1fcb12..9bf47df700 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -170,9 +170,11 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, proc newCandidate*(ctx: PContext, callee: PSym, binding: PNode, calleeScope = -1): TCandidate = + result = default(TCandidate) initCandidate(ctx, result, callee, binding, calleeScope) proc newCandidate*(ctx: PContext, callee: PType): TCandidate = + result = default(TCandidate) initCandidate(ctx, result, callee) proc copyCandidate(a: var TCandidate, b: TCandidate) = @@ -214,6 +216,7 @@ proc sumGeneric(t: PType): int = # count the "genericness" so that Foo[Foo[T]] has the value 3 # and Foo[T] has the value 2 so that we know Foo[Foo[T]] is more # specific than Foo[T]. + result = 0 var t = t var isvar = 0 while true: @@ -344,6 +347,7 @@ template describeArgImpl(c: PContext, n: PNode, i: int, startIdx = 1; prefer = p result.add argTypeToString(arg, prefer) proc describeArg*(c: PContext, n: PNode, i: int, startIdx = 1; prefer = preferName): string = + result = "" describeArgImpl(c, n, i, startIdx, prefer) proc describeArgs*(c: PContext, n: PNode, startIdx = 1; prefer = preferName): string = @@ -440,6 +444,8 @@ proc isConvertibleToRange(c: PContext, f, a: PType): bool = # `isIntLit` is correct and should be used above as well, see PR: # https://github.com/nim-lang/Nim/pull/11197 result = isIntLit(a) or a.kind in {tyFloat..tyFloat128} + else: + result = false proc handleFloatRange(f, a: PType): TTypeRelation = if a.kind == f.kind: @@ -506,6 +512,7 @@ proc skipToObject(t: PType; skipped: var SkippedPtr): PType = else: break if r.kind == tyObject and ptrs <= 1: result = r + else: result = nil proc isGenericSubtype(c: var TCandidate; a, f: PType, d: var int, fGenericOrigin: PType): bool = assert f.kind in {tyGenericInst, tyGenericInvocation, tyGenericBody} @@ -528,6 +535,8 @@ proc isGenericSubtype(c: var TCandidate; a, f: PType, d: var int, fGenericOrigin genericParamPut(c, last, fGenericOrigin) d = depth result = true + else: + result = false proc minRel(a, b: TTypeRelation): TTypeRelation = if a <= b: result = a @@ -609,6 +618,8 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = if reverseRel >= isGeneric: result = isInferred #inc c.genericMatches + else: + result = isNone else: # Note that this typeRel call will save f's resolved type into c.bindings # if f is metatype. @@ -656,7 +667,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = of tyNil: result = f.allowsNil - else: discard + else: result = isNone proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} = template checkRange[T](a0, a1, f0, f1: T): TTypeRelation = @@ -701,14 +712,14 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = typeClass[0][0] = prevCandidateType closeScope(c) - var typeParams: seq[(PSym, PType)] + var typeParams: seq[(PSym, PType)] = @[] if ff.kind == tyUserTypeClassInst: for i in 1..<(ff.len - 1): var typeParamName = ff.base[i-1].sym.name typ = ff[i] - param: PSym + param: PSym = nil alreadyBound = PType(idTableGet(m.bindings, typ)) if alreadyBound != nil: typ = alreadyBound @@ -748,8 +759,8 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType = addDecl(c, param) var - oldWriteHook: typeof(m.c.config.writelnHook) - diagnostics: seq[string] + oldWriteHook = default typeof(m.c.config.writelnHook) + diagnostics: seq[string] = @[] errorPrefix: string flags: TExprFlags = {} collectDiagnostics = m.diagnosticsEnabled or @@ -923,6 +934,7 @@ proc inferStaticsInRange(c: var TCandidate, else: failureToInferStaticParam(c.c.config, exp) + result = isNone if lowerBound.kind == nkIntLit: if upperBound.kind == nkIntLit: if lengthOrd(c.c.config, concrete) == upperBound.intVal - lowerBound.intVal + 1: @@ -2465,7 +2477,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int a = 1 # iterates over the actual given arguments f = if m.callee.kind != tyGenericBody: 1 else: 0 # iterates over formal parameters - arg: PNode # current prepared argument + arg: PNode = nil # current prepared argument formalLen = m.callee.n.len formal = if formalLen > 1: m.callee.n[1].sym else: nil # current routine parameter container: PNode = nil # constructed container @@ -2726,6 +2738,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo; else: if f.kind in {tyVar}: f = f.lastSon if typeRel(m, f, t) == isNone: + result = nil localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'") else: result = c.semGenerateInstance(c, dc, m.bindings, info) diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index e07d55fbcd..99e4342bbb 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -503,6 +503,7 @@ template foldOffsetOf*(conf: ConfigRef; n: PNode; fallback: PNode): PNode = elif node[1].kind == nkCheckedFieldExpr: dotExpr = node[1][0] else: + dotExpr = nil localError(config, node.info, "can't compute offsetof on this ast") assert dotExpr != nil diff --git a/compiler/sourcemap.nim b/compiler/sourcemap.nim index 2fcc50bbe9..b0b6fea2ef 100644 --- a/compiler/sourcemap.nim +++ b/compiler/sourcemap.nim @@ -70,6 +70,7 @@ func encode*(values: seq[int]): string {.raises: [].} = shift = 5 continueBit = 1 shl 5 mask = continueBit - 1 + result = "" for val in values: # Sign is stored in first bit var newVal = abs(val) shl 1 @@ -101,8 +102,8 @@ iterator tokenize*(line: string): (int, string) = token = "" while col < line.len: var - token: string - name: string + token: string = "" + name: string = "" # First we find the next identifier col += line.skipWhitespace(col) col += line.skipUntil(IdentStartChars, col) @@ -110,7 +111,7 @@ iterator tokenize*(line: string): (int, string) = col += line.parseIdent(token, col) # Idents will either be originalName_randomInt or HEXhexCode_randomInt if token.startsWith("HEX"): - var hex: int + var hex: int = 0 # 3 = "HEX".len and we only want to parse the two integers after it discard token[3 ..< 5].parseHex(hex) name = $chr(hex) @@ -125,6 +126,7 @@ iterator tokenize*(line: string): (int, string) = func parse*(source: string): SourceInfo = ## Parses the JS output for embedded line info ## So it can convert those into a series of mappings + result = default(SourceInfo) var skipFirstLine = true currColumn = 0 @@ -133,9 +135,9 @@ func parse*(source: string): SourceInfo = # Add each line as a node into the output for line in source.splitLines(): var - lineNumber: int - linePath: string - column: int + lineNumber: int = 0 + linePath: string = "" + column: int = 0 if line.strip().scanf("/* line $i:$i \"$+\" */", lineNumber, column, linePath): # When we reach the first line mappinsegmentg then we can assume # we can map the rest of the JS lines to Nim lines diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 7423fdfaa4..e6c089966f 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -114,7 +114,7 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; idgen: IdGenerator; spawnKind: TSpawnResult, result: PSym) = var body = newNodeI(nkStmtList, f.info) - var threadLocalBarrier: PSym + var threadLocalBarrier: PSym = nil if barrier != nil: var varSection2 = newNodeI(nkVarSection, barrier.info) threadLocalBarrier = addLocalVar(g, varSection2, nil, idgen, result, @@ -122,7 +122,7 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; body.add varSection2 body.add callCodegenProc(g, "barrierEnter", threadLocalBarrier.info, threadLocalBarrier.newSymNode) - var threadLocalProm: PSym + var threadLocalProm: PSym = nil if spawnKind == srByVar: threadLocalProm = addLocalVar(g, varSection, nil, idgen, result, fv.typ, fv) elif fv != nil: diff --git a/compiler/suggest.nim b/compiler/suggest.nim index ca19b24605..c7efad1af6 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -55,6 +55,8 @@ proc findDocComment(n: PNode): PNode = result = findDocComment(n[1]) elif n.kind in {nkAsgn, nkFastAsgn, nkSinkAsgn} and n.len == 2: result = findDocComment(n[1]) + else: + result = nil proc extractDocComment(g: ModuleGraph; s: PSym): string = var n = findDocComment(s.ast) @@ -106,7 +108,7 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int if cmpIgnoreStyle(line[column..column + result - 1], ident) != 0: result = 0 else: - var sourceIdent: string + var sourceIdent: string = "" result = parseWhile(line, sourceIdent, OpChars + {'[', '(', '{', ']', ')', '}'}, column) if ident[^1] == '=' and ident[0] in linter.Letters: @@ -254,13 +256,17 @@ proc filterSym(s: PSym; prefix: PNode; res: var PrefixMatch): bool {.inline.} = of nkOpenSymChoice, nkClosedSymChoice, nkAccQuoted: if n.len > 0: result = prefixMatch(s, n[0]) - else: discard + else: + result = default(PrefixMatch) + else: result = default(PrefixMatch) if s.kind != skModule: if prefix != nil: res = prefixMatch(s, prefix) result = res != PrefixMatch.None else: result = true + else: + result = false proc filterSymNoOpr(s: PSym; prefix: PNode; res: var PrefixMatch): bool {.inline.} = result = filterSym(s, prefix, res) and s.name.s[0] in lexer.SymChars and @@ -294,7 +300,7 @@ proc getQuality(s: PSym): range[0..100] = result = result - 5 proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var Suggestions) = - var pm: PrefixMatch + var pm: PrefixMatch = default(PrefixMatch) if filterSym(s, f, pm) and fieldVisible(c, s): outputs.add(symToSuggest(c.graph, s, isLocal=true, ideSug, info, s.getQuality, pm, c.inTypeContext > 0, 0)) @@ -302,7 +308,7 @@ proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var template wholeSymTab(cond, section: untyped) {.dirty.} = for (item, scopeN, isLocal) in uniqueSyms(c): let it = item - var pm: PrefixMatch + var pm: PrefixMatch = default(PrefixMatch) if cond: outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, section, info, getQuality(it), pm, c.inTypeContext > 0, scopeN)) @@ -365,6 +371,8 @@ proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = if exp.kind == tyVarargs: exp = elemType(exp) if exp.kind in {tyUntyped, tyTyped, tyGenericParam, tyAnything}: return result = sigmatch.argtypeMatches(c, s.typ[1], firstArg) + else: + result = false proc suggestOperations(c: PContext, n, f: PNode, typ: PType, outputs: var Suggestions) = assert typ != nil @@ -374,7 +382,7 @@ proc suggestOperations(c: PContext, n, f: PNode, typ: PType, outputs: var Sugges proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) = # do not produce too many symbols: for (it, scopeN, isLocal) in uniqueSyms(c): - var pm: PrefixMatch + var pm: PrefixMatch = default(PrefixMatch) if filterSym(it, f, pm): outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, ideSug, n.info, it.getQuality, pm, c.inTypeContext > 0, scopeN)) @@ -383,7 +391,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) # special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but # ``myObj``. var typ = n.typ - var pm: PrefixMatch + var pm: PrefixMatch = default(PrefixMatch) when defined(nimsuggest): if n.kind == nkSym and n.sym.kind == skError and c.config.suggestVersion == 0: # consider 'foo.|' where 'foo' is some not imported module. @@ -445,7 +453,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions) for node in typ.n: if node.kind == nkSym: let s = node.sym - var pm: PrefixMatch + var pm: PrefixMatch = default(PrefixMatch) if filterSym(s, field, pm): outputs.add(symToSuggest(c.graph, s, isLocal=true, ideSug, n.info, s.getQuality, pm, c.inTypeContext > 0, 0)) @@ -460,17 +468,24 @@ type proc inCheckpoint*(current, trackPos: TLineInfo): TCheckPointResult = if current.fileIndex == trackPos.fileIndex: + result = cpNone if current.line == trackPos.line and abs(current.col-trackPos.col) < 4: return cpExact if current.line >= trackPos.line: return cpFuzzy + else: + result = cpNone proc isTracked*(current, trackPos: TLineInfo, tokenLen: int): bool = if current.fileIndex==trackPos.fileIndex and current.line==trackPos.line: let col = trackPos.col if col >= current.col and col <= current.col+tokenLen-1: - return true + result = true + else: + result = false + else: + result = false when defined(nimsuggest): # Since TLineInfo defined a == operator that doesn't include the column, @@ -700,7 +715,7 @@ proc suggestSentinel*(c: PContext) = var outputs: Suggestions = @[] # suggest everything: for (it, scopeN, isLocal) in uniqueSyms(c): - var pm: PrefixMatch + var pm: PrefixMatch = default(PrefixMatch) if filterSymNoOpr(it, nil, pm): outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, ideSug, newLineInfo(c.config.m.trackPos.fileIndex, 0, -1), it.getQuality, diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index c00fe8b677..1c8acf2a64 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -36,6 +36,8 @@ proc containsShebang(s: string, i: int): bool = var j = i + 2 while j < s.len and s[j] in Whitespace: inc(j) result = s[j] == '/' + else: + result = false proc parsePipe(filename: AbsoluteFile, inputStream: PLLStream; cache: IdentCache; config: ConfigRef): PNode = @@ -64,6 +66,7 @@ proc parsePipe(filename: AbsoluteFile, inputStream: PLLStream; cache: IdentCache llStreamClose(s) proc getFilter(ident: PIdent): FilterKind = + result = filtNone for i in FilterKind: if cmpIgnoreStyle(ident.s, $i) == 0: return i @@ -74,6 +77,7 @@ proc getCallee(conf: ConfigRef; n: PNode): PIdent = elif n.kind == nkIdent: result = n.ident else: + result = nil localError(conf, n.info, "invalid filter: " & renderTree(n)) proc applyFilter(p: var Parser, n: PNode, filename: AbsoluteFile, @@ -124,7 +128,7 @@ proc openParser*(p: var Parser, fileIdx: FileIndex, inputstream: PLLStream; proc setupParser*(p: var Parser; fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): bool = let filename = toFullPathConsiderDirty(config, fileIdx) - var f: File + var f: File = default(File) if not open(f, filename.string): rawMessage(config, errGenerated, "cannot open file: " & filename.string) return false @@ -132,7 +136,9 @@ proc setupParser*(p: var Parser; fileIdx: FileIndex; cache: IdentCache; result = true proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode = - var p: Parser + var p: Parser = default(Parser) if setupParser(p, fileIdx, cache, config): result = parseAll(p) closeParser(p) + else: + result = nil diff --git a/compiler/transf.nim b/compiler/transf.nim index d0428b725d..92d740276b 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -242,9 +242,10 @@ proc transformConstSection(c: PTransf, v: PNode): PNode = proc hasContinue(n: PNode): bool = case n.kind - of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard + of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: result = false of nkContinueStmt: result = true else: + result = false for i in 0.. 0: n[0] else: n @@ -145,12 +156,14 @@ proc isNoSideEffectPragma*(n: PNode): bool = result = k == wNoSideEffect proc findPragma*(n: PNode, which: TSpecialWord): PNode = + result = nil if n.kind == nkPragma: for son in n: if whichPragma(son) == which: return son proc effectSpec*(n: PNode, effectType: TSpecialWord): PNode = + result = nil for i in 0.. 0: assert(t.n[0].kind == nkSym) result = toInt128(t.n[0].sym.position) + else: + result = Zero of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, tyStatic, tyInferred, tyUserTypeClasses, tyLent: result = firstOrd(conf, lastSon(t)) of tyOrdinal: if t.len > 0: result = firstOrd(conf, lastSon(t)) - else: internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') + else: + result = Zero + internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') of tyUncheckedArray, tyCstring: result = Zero else: - internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') result = Zero + internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') proc firstFloat*(t: PType): BiggestFloat = case t.kind @@ -834,14 +840,14 @@ proc targetSizeSignedToKind*(conf: ConfigRef): TTypeKind = of 8: result = tyInt64 of 4: result = tyInt32 of 2: result = tyInt16 - else: discard + else: result = tyNone proc targetSizeUnsignedToKind*(conf: ConfigRef): TTypeKind = case conf.target.intSize of 8: result = tyUInt64 of 4: result = tyUInt32 of 2: result = tyUInt16 - else: discard + else: result = tyNone proc normalizeKind*(conf: ConfigRef, k: TTypeKind): TTypeKind = case k @@ -869,7 +875,7 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = of 4: result = toInt128(0x7FFFFFFF) of 2: result = toInt128(0x00007FFF) of 1: result = toInt128(0x0000007F) - else: discard + else: result = Zero else: result = toInt128(0x7FFFFFFFFFFFFFFF'u64) of tyInt8: result = toInt128(0x0000007F) of tyInt16: result = toInt128(0x00007FFF) @@ -889,18 +895,22 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 = if t.n.len > 0: assert(t.n[^1].kind == nkSym) result = toInt128(t.n[^1].sym.position) + else: + result = Zero of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink, tyStatic, tyInferred, tyUserTypeClasses, tyLent: result = lastOrd(conf, lastSon(t)) of tyProxy: result = Zero of tyOrdinal: if t.len > 0: result = lastOrd(conf, lastSon(t)) - else: internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')') + else: + result = Zero + internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')') of tyUncheckedArray: result = Zero else: - internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')') result = Zero + internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')') proc lastFloat*(t: PType): BiggestFloat = case t.kind @@ -972,7 +982,7 @@ type proc initSameTypeClosure: TSameTypeClosure = # we do the initialization lazily for performance (avoids memory allocations) - discard + result = TSameTypeClosure() proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool = result = c.s.len > 0 and c.s.contains((a.id, b.id)) @@ -1011,6 +1021,8 @@ proc equalParam(a, b: PSym): TParamsEquality = result = paramsEqual elif b.ast != nil: result = paramsIncompatible + else: + result = paramsNotEqual else: result = paramsNotEqual @@ -1078,6 +1090,8 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = return false elif a.n != b.n and (a.n == nil or b.n == nil) and IgnoreTupleFields notin c.flags: result = false + else: + result = false template ifFastObjectTypeCheckFailed(a, b: PType, body: untyped) = if tfFromGeneric notin a.flags + b.flags: @@ -1097,6 +1111,8 @@ template ifFastObjectTypeCheckFailed(a, b: PType, body: untyped) = if tfFromGeneric in a.flags * b.flags and a.sym.id == b.sym.id: # ok, we need the expensive structural check body + else: + result = false proc sameObjectTypes*(a, b: PType): bool = # specialized for efficiency (sigmatch uses it) @@ -1134,6 +1150,12 @@ proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool = for i in 0.. 1: # we know the result is derived from the first argument: - var roots: seq[(PSym, int)] + var roots: seq[(PSym, int)] = @[] allRoots(n[1], roots, RootEscapes) for r in roots: connect(c, dest.sym, r[0], n[1].info) @@ -618,7 +620,8 @@ proc deps(c: var Partitions; dest, src: PNode) = if borrowChecking in c.goals: borrowingAsgn(c, dest, src) - var targets, sources: seq[(PSym, int)] + var targets: seq[(PSym, int)] = @[] + var sources: seq[(PSym, int)] = @[] allRoots(dest, targets, 0) allRoots(src, sources, 0) @@ -668,7 +671,7 @@ proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) = if constParameters in c.goals and tfNoSideEffect in callee.flags: discard "we know there are no hidden mutations through an immutable parameter" elif c.inNoSideEffectSection == 0 and containsPointer(n.typ): - var roots: seq[(PSym, int)] + var roots: seq[(PSym, int)] = @[] allRoots(n, roots, RootEscapes) for r in roots: potentialMutation(c, r[0], r[1], n.info) @@ -716,7 +719,7 @@ proc traverse(c: var Partitions; n: PNode) = if i < L: let paramType = parameters[i].skipTypes({tyGenericInst, tyAlias}) if not paramType.isCompileTimeOnly and paramType.kind in {tyVar, tySink, tyOwned}: - var roots: seq[(PSym, int)] + var roots: seq[(PSym, int)] = @[] allRoots(it, roots, RootEscapes) if paramType.kind == tyVar: if c.inNoSideEffectSection == 0: diff --git a/compiler/vm.nim b/compiler/vm.nim index 7376ff165e..1f4e4333d0 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -381,6 +381,7 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int = return pc + 1 proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool = + result = false if desttyp.kind == tyString: dest.ensureKind(rkNode) dest.node = newNode(nkStrLit) @@ -548,11 +549,12 @@ proc takeCharAddress(c: PCtx, src: PNode, index: BiggestInt, pc: int): TFullReg proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = + result = TFullReg(kind: rkNone) var pc = start var tos = tos # Used to keep track of where the execution is resumed. var savedPC = -1 - var savedFrame: PStackFrame + var savedFrame: PStackFrame = nil when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc): template updateRegsAlias = discard template regs: untyped = tos.slots @@ -1381,7 +1383,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let prcValue = c.globals[prc.position-1] if prcValue.kind == nkEmpty: globalError(c.config, c.debug[pc], "cannot run " & prc.name.s) - var slots2: TNodeSeq + var slots2: TNodeSeq = default(TNodeSeq) slots2.setLen(tos.slots.len) for i in 0..= 0 # 'nim check' does not like this internalAssert. if tmp >= 0: result = TRegister(tmp) + else: + result = 0 proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} = # stmt is different from 'void' in meta programming contexts. @@ -830,10 +832,14 @@ proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = proc isInt8Lit(n: PNode): bool = if n.kind in {nkCharLit..nkUInt64Lit}: result = n.intVal >= low(int8) and n.intVal <= high(int8) + else: + result = false proc isInt16Lit(n: PNode): bool = if n.kind in {nkCharLit..nkUInt64Lit}: result = n.intVal >= low(int16) and n.intVal <= high(int16) + else: + result = false proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = if n[2].isInt8Lit: @@ -854,7 +860,9 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) = # xxx consider whether to use t2 and targ2 here if n.typ.kind == arg.typ.kind and arg.typ.kind == tyProc: # don't do anything for lambda lifting conversions: - return true + result = true + else: + result = false if implicitConv(): gen(c, arg, dest) @@ -1419,6 +1427,7 @@ proc unneededIndirection(n: PNode): bool = n.typ.skipTypes(abstractInstOwned-{tyTypeDesc}).kind == tyRef proc canElimAddr(n: PNode; idgen: IdGenerator): PNode = + result = nil case n[0].kind of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: var m = n[0][0] @@ -1500,6 +1509,7 @@ proc cannotEval(c: PCtx; n: PNode) {.noinline.} = n.renderTree) proc isOwnedBy(a, b: PSym): bool = + result = false var a = a.owner while a != nil and a.kind != skModule: if a == b: return true @@ -1512,7 +1522,9 @@ proc getOwner(c: PCtx): PSym = proc importcCondVar*(s: PSym): bool {.inline.} = # see also importcCond if sfImportc in s.flags: - return s.kind in {skVar, skLet, skConst} + result = s.kind in {skVar, skLet, skConst} + else: + result = false proc checkCanEval(c: PCtx; n: PNode) = # we need to ensure that we don't evaluate 'x' here: @@ -1635,6 +1647,7 @@ proc isEmptyBody(n: PNode): bool = proc importcCond*(c: PCtx; s: PSym): bool {.inline.} = ## return true to importc `s`, false to execute its body instead (refs #8405) + result = false if sfImportc in s.flags: if s.kind in routineKinds: return isEmptyBody(getBody(c.graph, s)) @@ -2048,6 +2061,7 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) = proc genProc*(c: PCtx; s: PSym): int proc toKey(s: PSym): string = + result = "" var s = s while s != nil: result.add s.name.s @@ -2334,7 +2348,7 @@ proc genProc(c: PCtx; s: PSym): int = #if s.name.s == "outterMacro" or s.name.s == "innerProc": # echo "GENERATING CODE FOR ", s.name.s let last = c.code.len-1 - var eofInstr: TInstr + var eofInstr: TInstr = default(TInstr) if last >= 0 and c.code[last].opcode == opcEof: eofInstr = c.code[last] c.code.setLen(last) diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim index 1741574b86..7d9e66104c 100644 --- a/compiler/vmhooks.nim +++ b/compiler/vmhooks.nim @@ -69,7 +69,9 @@ proc getVar*(a: VmArgs; i: Natural): PNode = case p.kind of rkRegisterAddr: result = p.regAddr.node of rkNodeAddr: result = p.nodeAddr[] - else: doAssert false, $p.kind + else: + result = nil + doAssert false, $p.kind proc getNodeAddr*(a: VmArgs; i: Natural): PNode = let nodeAddr = getX(rkNodeAddr, nodeAddr) diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index b48197aefa..e1e69f6cc5 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -21,6 +21,7 @@ proc ptrToInt(x: PNode): int {.inline.} = proc getField(n: PNode; position: int): PSym = case n.kind of nkRecList: + result = nil for i in 0.. infoMax.time: infoMax = info diff --git a/lib/pure/collections/heapqueue.nim b/lib/pure/collections/heapqueue.nim index 89e532951a..bcfdf37c2b 100644 --- a/lib/pure/collections/heapqueue.nim +++ b/lib/pure/collections/heapqueue.nim @@ -59,7 +59,7 @@ proc initHeapQueue*[T](): HeapQueue[T] = ## ## **See also:** ## * `toHeapQueue proc <#toHeapQueue,openArray[T]>`_ - discard + result = default(HeapQueue[T]) proc len*[T](heap: HeapQueue[T]): int {.inline.} = ## Returns the number of elements of `heap`. diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 19bc3e65c6..e2adba910e 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -860,7 +860,7 @@ template toSeq*(iter: untyped): untyped = inc i result else: - var result: seq[typeof(iter)]# = @[] + var result: seq[typeof(iter)] = @[] for x in iter: result.add(x) result diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim index 7ebd227604..dbd4ce1d5e 100644 --- a/lib/pure/collections/setimpl.nim +++ b/lib/pure/collections/setimpl.nim @@ -62,6 +62,7 @@ template containsOrInclImpl() {.dirty.} = if index >= 0: result = true else: + result = false if mustRehash(s): enlarge(s) index = rawGetKnownHC(s, key, hc) diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 11e3249234..7e193af1a7 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -128,7 +128,7 @@ proc initHashSet*[A](initialSize = defaultInitialSize): HashSet[A] = var a = initHashSet[int]() a.incl(3) assert len(a) == 1 - + result = default(HashSet[A]) result.init(initialSize) proc `[]`*[A](s: var HashSet[A], key: A): var A = diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index fa06b99234..112aaa7d06 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -56,14 +56,14 @@ template maybeRehashPutImpl(enlarge) {.dirty.} = template putImpl(enlarge) {.dirty.} = checkIfInitialized() - var hc: Hash + var hc: Hash = default(Hash) var index = rawGet(t, key, hc) if index >= 0: t.data[index].val = val else: maybeRehashPutImpl(enlarge) template mgetOrPutImpl(enlarge) {.dirty.} = checkIfInitialized() - var hc: Hash + var hc: Hash = default(Hash) var index = rawGet(t, key, hc) if index < 0: # not present: insert (flipping index) @@ -73,7 +73,7 @@ template mgetOrPutImpl(enlarge) {.dirty.} = template hasKeyOrPutImpl(enlarge) {.dirty.} = checkIfInitialized() - var hc: Hash + var hc: Hash = default(Hash) var index = rawGet(t, key, hc) if index < 0: result = false @@ -210,3 +210,5 @@ template equalsImpl(s, t: typed) = if not t.hasKey(key): return false if t.getOrDefault(key) != val: return false return true + else: + return false diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 53490c911a..d4056897db 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -418,7 +418,7 @@ proc getOrDefault*[A, B](t: Table[A, B], key: A): B = let a = {'a': 5, 'b': 9}.toTable doAssert a.getOrDefault('a') == 5 doAssert a.getOrDefault('z') == 0 - + result = default(B) getOrDefaultImpl(t, key) proc getOrDefault*[A, B](t: Table[A, B], key: A, default: B): B = @@ -436,7 +436,7 @@ proc getOrDefault*[A, B](t: Table[A, B], key: A, default: B): B = let a = {'a': 5, 'b': 9}.toTable doAssert a.getOrDefault('a', 99) == 5 doAssert a.getOrDefault('z', 99) == 99 - + result = default(B) getOrDefaultImpl(t, key, default) proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B = @@ -1463,7 +1463,7 @@ proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B = let a = {'a': 5, 'b': 9}.toOrderedTable doAssert a.getOrDefault('a') == 5 doAssert a.getOrDefault('z') == 0 - + result = default(B) getOrDefaultImpl(t, key) proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A, default: B): B = @@ -1481,7 +1481,7 @@ proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A, default: B): B = let a = {'a': 5, 'b': 9}.toOrderedTable doAssert a.getOrDefault('a', 99) == 5 doAssert a.getOrDefault('z', 99) == 99 - + result = default(B) getOrDefaultImpl(t, key, default) proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B = diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index 04fa78ada9..c6d007c261 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -198,6 +198,7 @@ proc contains*[A](s: PackedSet[A], key: A): bool = assert B notin letters if s.elems <= s.a.len: + result = false for i in 0.. Date: Sun, 6 Aug 2023 23:59:43 +0800 Subject: [PATCH 391/489] unify starting blank lines in the experimental manual (#22396) unify starting blank lines in the experimental manal --- doc/manual_experimental.md | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 4ee035b65d..8cddce4f14 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -1976,11 +1976,9 @@ With `experimental: "strictDefs"`, `let` statements are allowed to not have an i An `out` parameter is like a `var` parameter but it must be written to before it can be used: ```nim - proc myopen(f: out File; name: string): bool = f = default(File) result = open(f, name) - ``` While it is usually the better style to use the return type in order to return results API and ABI @@ -1988,9 +1986,7 @@ considerations might make this infeasible. Like for `var T` Nim maps `out T` to For example POSIX's `stat` routine can be wrapped as: ```nim - proc stat*(a1: cstring, a2: out Stat): cint {.importc, header: "".} - ``` When the implementation of a routine with output parameters is analysed, the compiler @@ -1998,13 +1994,11 @@ checks that every path before the (implicit or explicit) return does set every o parameter: ```nim - proc p(x: out int; y: out string; cond: bool) = x = 4 if cond: y = "abc" # error: not every path initializes 'y' - ``` @@ -2014,11 +2008,9 @@ Out parameters and exception handling The analysis should take exceptions into account (but currently does not): ```nim - proc p(x: out int; y: out string; cond: bool) = x = canRaise(45) y = "abc" # <-- error: not every path initializes 'y' - ``` Once the implementation takes exceptions into account it is easy enough to @@ -2030,7 +2022,6 @@ Out parameters and inheritance It is not valid to pass an lvalue of a supertype to an `out T` parameter: ```nim - type Superclass = object of RootObj a: int @@ -2043,7 +2034,6 @@ It is not valid to pass an lvalue of a supertype to an `out T` parameter: var v: Subclass init v use v.s # the 's' field was never initialized! - ``` However, in the future this could be allowed and provide a better way to write object @@ -2167,14 +2157,12 @@ inside `Isolated[T]`. It is what a channel implementation should use in order to the freedom of data races: ```nim - proc send*[T](c: var Channel[T]; msg: sink Isolated[T]) proc recv*[T](c: var Channel[T]): T ## Note: Returns T, not Isolated[T] for convenience. proc recvIso*[T](c: var Channel[T]): Isolated[T] ## remembers the data is Isolated[T]. - ``` In order to create an `Isolated` graph one has to use either `isolate` or `unsafeIsolate`. @@ -2187,9 +2175,7 @@ is free of external aliases into it. `isolate` ensures this invariant. It is inspired by Pony's `recover` construct: ```nim - func isolate(x: sink T): Isolated[T] {.magic: "Isolate".} - ``` @@ -2251,7 +2237,6 @@ encapsulates a `ref` type effectively so that a variable of this container type can be used in an `isolate` context: ```nim - type Isolated*[T] {.sendable.} = object ## Isolated data can only be moved, not copied. value: T @@ -2265,7 +2250,6 @@ can be used in an `isolate` context: proc `=destroy`*[T](dest: var Isolated[T]) {.inline.} = # delegate to value's destroy operation `=destroy`(dest.value) - ``` The `.sendable` pragma itself is an experimenal, unchecked, unsafe annotation. It is @@ -2279,7 +2263,6 @@ Virtual pragma Here's an example of how to use the virtual pragma: ```nim - proc newCpp*[T](): ptr T {.importcpp: "new '*0()".} type Foo = object of RootObj @@ -2300,7 +2283,6 @@ let booAsFoo = cast[FooPtr](newCpp[Boo]()) foo.salute() # prints hello foo boo.salute() # prints hello boo booAsFoo.salute() # prints hello boo - ``` In this example, the `salute` function is virtual in both Foo and Boo types. This allows for polymorphism. @@ -2355,13 +2337,11 @@ The `constructor` pragma can be used in two ways: in conjunction with `importcpp Consider: ```nim - type Foo* = object x: int32 proc makeFoo(x: int32): Foo {.constructor.} = this.x = x - ``` It forward declares the constructor in the type definition. When the constructor has parameters, it also generates a default constructor. @@ -2372,8 +2352,6 @@ Like `virtual`, `constructor` also supports a syntax that allows to express C++ For example: ```nim - - {.emit:"""/*TYPESECTION*/ struct CppClass { int x; @@ -2398,7 +2376,6 @@ proc makeNimClass(x: int32): NimClass {.constructor:"NimClass('1 #1) : CppClass( # Optional: define the default constructor explicitly proc makeCppClass(): NimClass {.constructor: "NimClass() : CppClass(0, 0)".} = this.x = 1 - ``` In the example above `CppClass` has a deleted default constructor. Notice how by using the constructor syntax, one can call the appropiate constructor. From 26eb0a944fe6a0a5d09798262055aa30c9b0001a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 7 Aug 2023 15:40:39 +0800 Subject: [PATCH 392/489] a bit modern code for depends (#22400) * a bit modern code for depends * simplify --- compiler/depends.nim | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/depends.nim b/compiler/depends.nim index 6c7ee8ffc3..cb462e1888 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -106,11 +106,6 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) = changeFileExt(project, "dot")) proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext = - var g: PGen - new(g) - g.module = module - g.config = graph.config - g.graph = graph + result = PGen(module: module, config: graph.config, graph: graph) if graph.backend == nil: graph.backend = Backend(dotGraph: "") - result = g From 614a18cd05bda525f62310578115ecc6c41b7e09 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 7 Aug 2023 15:49:30 +0800 Subject: [PATCH 393/489] Delete parse directory, which was pushed wrongly before [backport] (#22401) Delete parse directory --- parse/pragmas.nim | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 parse/pragmas.nim diff --git a/parse/pragmas.nim b/parse/pragmas.nim deleted file mode 100644 index bf77a28420..0000000000 --- a/parse/pragmas.nim +++ /dev/null @@ -1,3 +0,0 @@ -# parse/pragmas.nim content - -proc foo*() = discard \ No newline at end of file From fe9ae2c69adc39cd170b4bd31221fb66135fd571 Mon Sep 17 00:00:00 2001 From: Bung Date: Mon, 7 Aug 2023 16:09:35 +0800 Subject: [PATCH 394/489] nimIoselector option (#22395) * selectors.nim: Add define to select event loop implementation * rename to nimIoselector --------- Co-authored-by: Jan Pobrislo --- lib/pure/selectors.nim | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 2d10e3f321..fcee22c09f 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -344,7 +344,18 @@ else: res = int(fdLim.rlim_cur) - 1 res - when defined(linux) and not defined(emscripten): + when defined(nimIoselector): + when nimIoselector == "epoll": + include ioselects/ioselectors_epoll + elif nimIoselector == "kqueue": + include ioselects/ioselectors_kqueue + elif nimIoselector == "poll": + include ioselects/ioselectors_poll + elif nimIoselector == "select": + include ioselects/ioselectors_select + else: + {.fatal: "Unknown nimIoselector specified by define.".} + elif defined(linux) and not defined(emscripten): include ioselects/ioselectors_epoll elif bsdPlatform: include ioselects/ioselectors_kqueue From b5b4b48c942b23991c8d11f41dc39b7e211e5b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Mon, 7 Aug 2023 09:11:00 +0100 Subject: [PATCH 395/489] [C++] Member pragma RFC (https://github.com/nim-lang/RFCs/issues/530) (#22272) * [C++] Member pragma RFC #530 rebase devel * changes the test so `echo` is not used before Nim is init * rebase devel * fixes Error: use explicit initialization of X for clarity [Uninit] --- compiler/ast.nim | 2 ++ compiler/ccgtypes.nim | 22 ++++++++++-------- compiler/cgen.nim | 4 ++-- compiler/pragmas.nim | 10 ++++---- compiler/semstmts.nim | 15 ++++++------ compiler/wordrecg.nim | 2 +- tests/cpp/tmember.nim | 53 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 85 insertions(+), 23 deletions(-) create mode 100644 tests/cpp/tmember.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index eccf5a9852..aba877187b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -314,6 +314,7 @@ type # an infinite loop, this flag is used as a sentinel to stop it. sfVirtual # proc is a C++ virtual function sfByCopy # param is marked as pass bycopy + sfMember # proc is a C++ member of a type sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl TSymFlags* = set[TSymFlag] @@ -347,6 +348,7 @@ const sfBase* = sfDiscriminant sfCustomPragma* = sfRegister # symbol is custom pragma template sfTemplateRedefinition* = sfExportc # symbol is a redefinition of an earlier template + sfCppMember* = { sfVirtual, sfMember, sfConstructor } # proc is a C++ member, meaning it will be attached to the type definition const # getting ready for the future expr/stmt merge diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 205031a918..6bac84e956 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -493,12 +493,12 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr template cgDeclFrmt*(s: PSym): string = s.constraint.strVal -proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var string, +proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params: var string, check: var IntSet, declareEnvironment=true; weakDep=false;) = let t = prc.typ let isCtor = sfConstructor in prc.flags - if isCtor: + if isCtor or (name[0] == '~' and sfMember in prc.flags): #destructors cant have void rettype = "" elif t[0] == nil or isInvalidReturnType(m.config, t): rettype = "void" @@ -555,6 +555,7 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var multiFormat(params, @['\'', '#'], [types, names]) multiFormat(superCall, @['\'', '#'], [types, names]) + multiFormat(name, @['\'', '#'], [types, names]) #so we can ~'1 on members if params == "()": if types.len == 0: params = "(void)" @@ -1148,11 +1149,14 @@ proc isReloadable(m: BModule; prc: PSym): bool = proc isNonReloadable(m: BModule; prc: PSym): bool = return m.hcrOn and sfNonReloadable in prc.flags -proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride: var bool; isCtor: bool) = +proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride, isMemberVirtual: var bool; isCtor: bool) = var afterParams: string = "" if scanf(val, "$*($*)$s$*", name, params, afterParams): isFnConst = afterParams.find("const") > -1 isOverride = afterParams.find("override") > -1 + isMemberVirtual = name.find("virtual ") > -1 + if isMemberVirtual: + name = name.replace("virtual ", "") if isCtor: discard scanf(afterParams, ":$s$*", superCall) else: @@ -1161,9 +1165,8 @@ proc parseVFunctionDecl(val: string; name, params, retType, superCall: var strin params = "(" & params & ")" proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl : bool = false) = - assert {sfVirtual, sfConstructor} * prc.flags != {} + assert sfCppMember * prc.flags != {} let isCtor = sfConstructor in prc.flags - let isVirtual = not isCtor var check = initIntSet() fillBackendName(m, prc) fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown) @@ -1179,9 +1182,10 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = var typDesc = getTypeDescWeak(m, typ, check, dkParam) let asPtrStr = rope(if asPtr: "_PTR" else: "") var name, params, rettype, superCall: string = "" - var isFnConst, isOverride: bool = false - parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isCtor) - genMemberProcParams(m, prc, superCall, rettype, params, check, true, false) + var isFnConst, isOverride, isMemberVirtual: bool = false + parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isMemberVirtual, isCtor) + genMemberProcParams(m, prc, superCall, rettype, name, params, check, true, false) + let isVirtual = sfVirtual in prc.flags or isMemberVirtual var fnConst, override: string = "" if isCtor: name = typDesc @@ -1194,7 +1198,7 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = override = " override" superCall = "" else: - if isVirtual: + if not isCtor: prc.loc.r = "$1$2(@)" % [memberOp, name] elif superCall != "": superCall = " : " & superCall diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 2643e6edd1..a3b74c408e 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1149,7 +1149,7 @@ proc isNoReturn(m: BModule; s: PSym): bool {.inline.} = proc genProcAux*(m: BModule, prc: PSym) = var p = newProc(prc, m) var header = newRopeAppender() - if m.config.backend == backendCpp and {sfVirtual, sfConstructor} * prc.flags != {}: + if m.config.backend == backendCpp and sfCppMember * prc.flags != {}: genMemberProcHeader(m, prc, header) else: genProcHeader(m, prc, header) @@ -1260,7 +1260,7 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} = proc genProcPrototype(m: BModule, sym: PSym) = useHeader(m, sym) - if lfNoDecl in sym.loc.flags or {sfVirtual, sfConstructor} * sym.flags != {}: return + if lfNoDecl in sym.loc.flags or sfCppMember * sym.flags != {}: return if lfDynamicLib in sym.loc.flags: if sym.itemId.module != m.module.position and not containsOrIncl(m.declaredThings, sym.id): diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index e0fdba566b..56e25c0b43 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -34,7 +34,7 @@ const wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl, wGensym, wInject, wRaises, wEffectsOf, wTags, wForbids, wLocks, wDelegator, wGcSafe, wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy, - wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect, wVirtual, wQuirky} + wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect, wVirtual, wQuirky, wMember} converterPragmas* = procPragmas methodPragmas* = procPragmas+{wBase}-{wImportCpp} templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty, @@ -245,10 +245,10 @@ proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string = if n.kind in nkPragmaCallKinds: result = expectStrLit(c, n) else: result = defaultStr -proc processVirtual(c: PContext, n: PNode, s: PSym) = +proc processVirtual(c: PContext, n: PNode, s: PSym, flag: TSymFlag) = s.constraint = newEmptyStrNode(c, n, getOptionalStr(c, n, "$1")) s.constraint.strVal = s.constraint.strVal % s.name.s - s.flags.incl {sfVirtual, sfInfixCall, sfExportc, sfMangleCpp} + s.flags.incl {flag, sfInfixCall, sfExportc, sfMangleCpp} s.typ.callConv = ccNoConvention incl c.config.globalOptions, optMixedMode @@ -1284,7 +1284,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wSystemRaisesDefect: sym.flags.incl sfSystemRaisesDefect of wVirtual: - processVirtual(c, it, sym) + processVirtual(c, it, sym, sfVirtual) + of wMember: + processVirtual(c, it, sym, sfMember) else: invalidPragma(c, it) elif comesFromPush and whichKeyword(ident) != wInvalid: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 448c26cf2a..302ccc8b9e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2269,26 +2269,27 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if sfBorrow in s.flags and c.config.cmd notin cmdDocLike: result[bodyPos] = c.graph.emptyNode - if {sfVirtual, sfConstructor} * s.flags != {} and sfImportc notin s.flags: + if sfCppMember * s.flags != {} and sfImportc notin s.flags: let isVirtual = sfVirtual in s.flags - let pragmaName = if isVirtual: "virtual" else: "constructor" + let isCtor = sfConstructor in s.flags + let pragmaName = if isVirtual: "virtual" elif isCtor: "constructor" else: "member" if c.config.backend == backendCpp: - if s.typ.sons.len < 2 and isVirtual: - localError(c.config, n.info, "virtual must have at least one parameter") + if s.typ.sons.len < 2 and not isCtor: + localError(c.config, n.info, pragmaName & " must have at least one parameter") for son in s.typ.sons: if son!=nil and son.isMetaType: localError(c.config, n.info, pragmaName & " unsupported for generic routine") var typ: PType - if sfConstructor in s.flags: + if isCtor: typ = s.typ.sons[0] if typ == nil or typ.kind != tyObject: localError(c.config, n.info, "constructor must return an object") else: typ = s.typ.sons[1] - if typ.kind == tyPtr and isVirtual: + if typ.kind == tyPtr and not isCtor: typ = typ[0] if typ.kind != tyObject: - localError(c.config, n.info, "virtual must be either ptr to object or object type.") + localError(c.config, n.info, pragmaName & " must be either ptr to object or object type.") if typ.owner.id == s.owner.id and c.module.id == s.owner.id: c.graph.memberProcsPerType.mgetOrPut(typ.itemId, @[]).add s else: diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index f784f0a754..b2b0c8ae23 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -103,7 +103,7 @@ type wSwitch = "switch", wThis = "this", wThrow = "throw", wTrue = "true", wTypedef = "typedef", wTypeid = "typeid", wTypeof = "typeof", wTypename = "typename", wUnion = "union", wPacked = "packed", wUnsigned = "unsigned", wVirtual = "virtual", - wVoid = "void", wVolatile = "volatile", wWchar = "wchar_t", + wVoid = "void", wVolatile = "volatile", wWchar = "wchar_t", wMember = "member", wAlignas = "alignas", wAlignof = "alignof", wConstexpr = "constexpr", wDecltype = "decltype", wNullptr = "nullptr", wNoexcept = "noexcept", diff --git a/tests/cpp/tmember.nim b/tests/cpp/tmember.nim new file mode 100644 index 0000000000..3f498c7224 --- /dev/null +++ b/tests/cpp/tmember.nim @@ -0,0 +1,53 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" + output: ''' +2 +false +hello foo +hello boo +hello boo +destructing +destructing +''' +""" +proc print(s: cstring) {.importcpp:"printf(@)", header:"".} + +type + Doo {.exportc.} = object + test: int + +proc memberProc(f: Doo) {.exportc, member.} = + echo $f.test + +proc destructor(f: Doo) {.member: "~'1()", used.} = + print "destructing\n" + +proc `==`(self, other: Doo): bool {.member:"operator==('2 const & #2) const -> '0"} = + self.test == other.test + +let doo = Doo(test: 2) +doo.memberProc() +echo doo == Doo(test: 1) + +#virtual +proc newCpp*[T](): ptr T {.importcpp:"new '*0()".} +type + Foo = object of RootObj + FooPtr = ptr Foo + Boo = object of Foo + BooPtr = ptr Boo + +proc salute(self: FooPtr) {.member: "virtual $1()".} = + echo "hello foo" + +proc salute(self: BooPtr) {.member: "virtual $1()".} = + echo "hello boo" + +let foo = newCpp[Foo]() +let boo = newCpp[Boo]() +let booAsFoo = cast[FooPtr](newCpp[Boo]()) + +foo.salute() +boo.salute() +booAsFoo.salute() From 260b4236fca566530c8327c24e5034295d0b7edc Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:11:59 +0800 Subject: [PATCH 396/489] use out parameters for getTemp (#22399) --- compiler/ccgcalls.nim | 12 +++++------- compiler/ccgexprs.nim | 28 +++++++++++++++++----------- compiler/ccgreset.nim | 2 +- compiler/ccgstmts.nim | 3 ++- compiler/ccgtrav.nim | 9 ++++----- compiler/cgen.nim | 28 ++++++++++------------------ 6 files changed, 39 insertions(+), 43 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 8661ed8337..dca581fadc 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -96,7 +96,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl.add(");\n") line(p, cpsStmts, pl) else: - var tmp: TLoc = default(TLoc) + var tmp: TLoc getTemp(p, typ[0], tmp, needsInit=true) pl.add(addrLoc(p.config, tmp)) pl.add(");\n") @@ -133,7 +133,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, genAssignment(p, d, list, {}) # no need for deep copying if canRaise: raiseExit(p) else: - var tmp: TLoc = default(TLoc) + var tmp: TLoc getTemp(p, typ[0], tmp, needsInit=true) var list: TLoc = default(TLoc) initLoc(list, locCall, d.lode, OnUnknown) @@ -273,14 +273,12 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc = # Also don't regress for non ARC-builds, too risky. if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and getSize(p.config, a.lode.typ) < 1024: - result = default(TLoc) getTemp(p, a.lode.typ, result, needsInit=false) genAssignment(p, result, a, {}) else: result = a proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc = - result = default(TLoc) getTemp(p, a.lode.typ, result, needsInit=false) genAssignment(p, result, a, {}) @@ -483,7 +481,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = genCallPattern() if canRaise: raiseExit(p) else: - var tmp: TLoc = default(TLoc) + var tmp: TLoc getTemp(p, typ[0], tmp, needsInit=true) pl.add(addrLoc(p.config, tmp)) genCallPattern() @@ -501,7 +499,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = genAssignment(p, d, list, {}) # no need for deep copying if canRaise: raiseExit(p) else: - var tmp: TLoc = default(TLoc) + var tmp: TLoc getTemp(p, typ[0], tmp) assert(d.t != nil) # generate an assignment to d: var list: TLoc = default(TLoc) @@ -782,7 +780,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = pl.add("];\n") line(p, cpsStmts, pl) else: - var tmp: TLoc = default(TLoc) + var tmp: TLoc getTemp(p, typ[0], tmp, needsInit=true) pl.add(addrLoc(p.config, tmp)) pl.add("];\n") diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index a285b86a67..cc0d0465c5 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -348,7 +348,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = linefmt(p, cpsStmts, "$1 = #copyString($2);$n", [dest.rdLoc, src.rdLoc]) elif dest.storage == OnHeap: # we use a temporary to care for the dreaded self assignment: - var tmp: TLoc = default(TLoc) + var tmp: TLoc getTemp(p, ty, tmp) linefmt(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);$n", [dest.rdLoc, src.rdLoc, tmp.rdLoc]) @@ -431,7 +431,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genDeepCopy(p: BProc; dest, src: TLoc) = template addrLocOrTemp(a: TLoc): Rope = if a.k == locExpr: - var tmp: TLoc = default(TLoc) + var tmp: TLoc getTemp(p, a.t, tmp) genAssignment(p, tmp, a, {}) addrLoc(p.config, tmp) @@ -1197,7 +1197,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = else: var L: TLabel - tmp: TLoc = default(TLoc) + tmp: TLoc getTemp(p, e.typ, tmp) # force it into a temp! inc p.splitDecls expr(p, e[1], tmp) @@ -1276,7 +1276,8 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = # appendChar(tmp0, 'z'); # asgn(s, tmp0); # } - var a, tmp: TLoc = default(TLoc) + var a = default(TLoc) + var tmp: TLoc getTemp(p, e.typ, tmp) var L = 0 var appends: Rope = "" @@ -1556,7 +1557,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = (d.k notin {locTemp,locLocalVar,locGlobalVar,locParam,locField}) or (isPartOf(d.lode, e) != arNo) - var tmp: TLoc = default(TLoc) + var tmp: TLoc = TLoc() var r: Rope if useTemp: getTemp(p, t, tmp) @@ -1604,7 +1605,8 @@ proc lhsDoesAlias(a, b: PNode): bool = if isPartOf(a, y) != arNo: return true proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = - var arr, tmp: TLoc = default(TLoc) + var arr = default(TLoc) + var tmp: TLoc = default(TLoc) # bug #668 let doesAlias = lhsDoesAlias(d.lode, n) let dest = if doesAlias: addr(tmp) else: addr(d) @@ -1669,7 +1671,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = arr.r = ropecg(p.module, "$1[$2]", [rdLoc(a), lit]) genAssignment(p, elem, arr, {needToCopy}) else: - var i: TLoc = default(TLoc) + var i: TLoc getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", [i.r, L]) initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap) @@ -1986,7 +1988,8 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) = # b = temp cowBracket(p, e[1]) cowBracket(p, e[2]) - var a, b, tmp: TLoc = default(TLoc) + var a, b = default(TLoc) + var tmp: TLoc getTemp(p, skipTypes(e[1].typ, abstractVar), tmp) initLocExpr(p, e[1], a) # eval a initLocExpr(p, e[2], b) # eval b @@ -2090,7 +2093,8 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = "&", "|", "& ~"] - var a, b, i: TLoc = default(TLoc) + var a, b = default(TLoc) + var i: TLoc var setType = skipTypes(e[1].typ, abstractVar) var size = int(getSize(p.config, setType)) case size @@ -2645,7 +2649,8 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = # nimZeroMem(tmp, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c); # incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g); var - a, b, idx: TLoc = default(TLoc) + a, b = default(TLoc) + var idx: TLoc if nfAllConst in e.flags: var elem = newRopeAppender() genSetNode(p, e, elem) @@ -2744,7 +2749,8 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) = p.module.s[cfsData].add data putIntoDest(p, d, n, tmp, OnStatic) else: - var tmp, a, b: TLoc = default(TLoc) + var tmp: TLoc + var a, b = default(TLoc) initLocExpr(p, n[0], a) initLocExpr(p, n[1], b) if n[0].skipConv.kind == nkClosure: diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim index f486f71fb7..5e6456704d 100644 --- a/compiler/ccgreset.nim +++ b/compiler/ccgreset.nim @@ -57,7 +57,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = specializeResetT(p, accessor, lastSon(typ)) of tyArray: let arraySize = lengthOrd(p.config, typ[0]) - var i: TLoc = default(TLoc) + var i: TLoc getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", [i.r, arraySize]) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 45104399a1..1751321f3f 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1611,7 +1611,8 @@ when false: expr(p, call, d) proc asgnFieldDiscriminant(p: BProc, e: PNode) = - var a, tmp: TLoc = default(TLoc) + var a = default(TLoc) + var tmp: TLoc var dotExpr = e[0] if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0] initLocExpr(p, e[0], a) diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index e4008bfc1e..9af33d45e8 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -21,7 +21,7 @@ const proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) proc genCaseRange(p: BProc, branch: PNode) -proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) +proc getTemp(p: BProc, t: PType, result: out TLoc; needsInit=false) proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode; typ: PType) = @@ -74,7 +74,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = genTraverseProc(c, accessor, lastSon(typ)) of tyArray: let arraySize = lengthOrd(c.p.config, typ[0]) - var i: TLoc = default(TLoc) + var i: TLoc getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i) var oldCode = p.s(cpsStmts) freeze oldCode @@ -119,12 +119,11 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) = var p = c.p assert typ.kind == tySequence - var i: TLoc = default(TLoc) + var i: TLoc getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i) var oldCode = p.s(cpsStmts) freeze oldCode - var a: TLoc = default(TLoc) - a.r = accessor + var a: TLoc = TLoc(r: accessor) lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", [i.r, lenExpr(c.p, a)]) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index a3b74c408e..0a54256523 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -541,17 +541,14 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = if not immediateAsgn: constructLoc(p, v.loc) -proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = +proc getTemp(p: BProc, t: PType, result: out TLoc; needsInit=false) = inc(p.labels) - result.r = "T" & rope(p.labels) & "_" + result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t, + storage: OnStack, flags: {}) if p.module.compileToCpp and isOrHasImportedCppType(t): linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, dkVar), result.r]) else: linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r]) - result.k = locTemp - result.lode = lodeTyp t - result.storage = OnStack - result.flags = {} constructLoc(p, result, not needsInit) when false: # XXX Introduce a compiler switch in order to detect these easily. @@ -562,23 +559,18 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo writeStackTrace() -proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) = +proc getTempCpp(p: BProc, t: PType, result: out TLoc; value: Rope) = inc(p.labels) - result.r = "T" & rope(p.labels) & "_" + result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t, + storage: OnStack, flags: {}) linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value]) - result.k = locTemp - result.lode = lodeTyp t - result.storage = OnStack - result.flags = {} -proc getIntTemp(p: BProc, result: var TLoc) = +proc getIntTemp(p: BProc, result: out TLoc) = inc(p.labels) - result.r = "T" & rope(p.labels) & "_" + result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, + storage: OnStack, lode: lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt), + flags: {}) linefmt(p, cpsLocals, "NI $1;$n", [result.r]) - result.k = locTemp - result.storage = OnStack - result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt) - result.flags = {} proc localVarDecl(p: BProc; n: PNode): Rope = result = "" From b4b555d8d10fa1277e57ded0dcfc4678bfafadb5 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 8 Aug 2023 11:13:38 +0800 Subject: [PATCH 397/489] tiny change on action.nim (#22405) --- ci/action.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/action.nim b/ci/action.nim index 5d3a50fda2..ad0f4df0b6 100644 --- a/ci/action.nim +++ b/ci/action.nim @@ -3,7 +3,7 @@ import std/[strutils, os, osproc, parseutils, strformat] proc main() = var msg = "" - const cmd = "./koch boot --gc:orc -d:release" + const cmd = "./koch boot --mm:orc -d:release" let (output, exitCode) = execCmdEx(cmd) From 0219c5a60740689f343f3261611219425e9f9531 Mon Sep 17 00:00:00 2001 From: Bung Date: Tue, 8 Aug 2023 12:13:14 +0800 Subject: [PATCH 398/489] fix #22287 nimlf_ undefined error (#22382) --- compiler/cgen.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 0a54256523..e21d85a072 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -301,6 +301,7 @@ proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) = genCLineDir(r, toFullPath(conf, info), info.safeLineNm, p, info, lastFileIndex) proc genLineDir(p: BProc, t: PNode) = + if p == p.module.preInitProc: return let line = t.info.safeLineNm if optEmbedOrigSrc in p.config.globalOptions: From 47d06d3d4cb85a0c7c2273864f6088a5e8521f44 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 8 Aug 2023 13:42:08 +0800 Subject: [PATCH 399/489] fixes #22387; Undefined behavior when with hash(...) (#22404) * fixes #22387; Undefined behavior when with hash(...) * fixes vm * fixes nimscript --- lib/pure/hashes.nim | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index daa7f93661..ad164d6d31 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -319,16 +319,24 @@ proc murmurHash(x: openArray[byte]): Hash = h1: uint32 i = 0 + + template impl = + var j = stepSize + while j > 0: + dec j + k1 = (k1 shl 8) or (ord(x[i+j])).uint32 + # body while i < n * stepSize: var k1: uint32 - when defined(js) or defined(sparc) or defined(sparc64): - var j = stepSize - while j > 0: - dec j - k1 = (k1 shl 8) or (ord(x[i+j])).uint32 + + when nimvm: + impl() else: - k1 = cast[ptr uint32](unsafeAddr x[i])[] + when declared(copyMem): + copyMem(addr k1, addr x[i], 4) + else: + impl() inc i, stepSize k1 = imul(k1, c1) From 37d8f32ae9ead55a065ae42636e88265ea17ce4a Mon Sep 17 00:00:00 2001 From: Bung Date: Tue, 8 Aug 2023 16:06:47 +0800 Subject: [PATCH 400/489] =?UTF-8?q?fix=20#18823=20Passing=20Natural=20to?= =?UTF-8?q?=20bitops.BitsRange[T]=20parameter=20in=20generi=E2=80=A6=20(#2?= =?UTF-8?q?0683)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix #18823 Passing Natural to bitops.BitsRange[T] parameter in generic proc is compile error --- compiler/ast.nim | 6 ++++-- compiler/semtypinst.nim | 13 +++++++------ compiler/sigmatch.nim | 8 ++++++-- tests/generics/t18823.nim | 6 ++++++ 4 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 tests/generics/t18823.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index aba877187b..55ee0e20de 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -2040,10 +2040,12 @@ proc skipColon*(n: PNode): PNode = result = n[1] proc findUnresolvedStatic*(n: PNode): PNode = - # n.typ == nil: see issue #14802 if n.kind == nkSym and n.typ != nil and n.typ.kind == tyStatic and n.typ.n == nil: return n - + if n.typ != nil and n.typ.kind == tyTypeDesc: + let t = skipTypes(n.typ, {tyTypeDesc}) + if t.kind == tyGenericParam and t.len == 0: + return n for son in n: let n = son.findUnresolvedStatic if n != nil: return n diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 19aa8be291..dfa1d2902c 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -89,7 +89,7 @@ type proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym -proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0): PNode +proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PType = nil): PNode proc initLayeredTypeMap*(pt: TIdTable): LayeredIdTable = result = LayeredIdTable() @@ -214,7 +214,7 @@ proc hasValuelessStatics(n: PNode): bool = return true false -proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode = +proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PType = nil): PNode = if n == nil: return result = copyNode(n) if n.typ != nil: @@ -256,8 +256,8 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode = when false: n = reResolveCallsWithTypedescParams(cl, n) result = if cl.allowMetaTypes: n - else: cl.c.semExpr(cl.c, n) - if not cl.allowMetaTypes: + else: cl.c.semExpr(cl.c, n, {}, expectedType) + if not cl.allowMetaTypes and expectedType != nil: assert result.kind notin nkCallKinds else: if n.len > 0: @@ -694,12 +694,13 @@ proc initTypeVars*(p: PContext, typeMap: LayeredIdTable, info: TLineInfo; result.owner = owner proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode; - owner: PSym, allowMetaTypes = false): PNode = + owner: PSym, allowMetaTypes = false, + fromStaticExpr = false, expectedType: PType = nil): PNode = var typeMap = initLayeredTypeMap(pt) var cl = initTypeVars(p, typeMap, n.info, owner) cl.allowMetaTypes = allowMetaTypes pushInfoContext(p.config, n.info) - result = replaceTypeVarsN(cl, n) + result = replaceTypeVarsN(cl, n, expectedType = expectedType) popInfoContext(p.config) when false: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 9bf47df700..462f5d0d1a 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -821,7 +821,8 @@ proc maybeSkipDistinct(m: TCandidate; t: PType, callee: PSym): PType = result = t proc tryResolvingStaticExpr(c: var TCandidate, n: PNode, - allowUnresolved = false): PNode = + allowUnresolved = false, + expectedType: PType = nil): PNode = # Consider this example: # type Value[N: static[int]] = object # proc foo[N](a: Value[N], r: range[0..(N-1)]) @@ -1179,9 +1180,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, if result notin {isNone, isGeneric}: # resolve any late-bound static expressions # that may appear in the range: + let expectedType = base(f) for i in 0..1: if f.n[i].kind == nkStaticExpr: - f.n[i] = tryResolvingStaticExpr(c, f.n[i]) + let r = tryResolvingStaticExpr(c, f.n[i], expectedType = expectedType) + if r != nil: + f.n[i] = r result = typeRangeRel(f, a) else: let f = skipTypes(f, {tyRange}) diff --git a/tests/generics/t18823.nim b/tests/generics/t18823.nim new file mode 100644 index 0000000000..94c79aebe9 --- /dev/null +++ b/tests/generics/t18823.nim @@ -0,0 +1,6 @@ +type BitsRange[T] = range[0..sizeof(T)*8-1] + +proc bar[T](a: T; b: BitsRange[T]) = + discard + +bar(1, 2.Natural) From 4c6be40b340e3ce70b3ed2207db276cb9c661dbe Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 8 Aug 2023 16:08:16 +0800 Subject: [PATCH 401/489] modernize compiler/filter_tmpl.nim (#22407) --- compiler/filter_tmpl.nim | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index 84ed991645..d04388b96a 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -201,17 +201,15 @@ proc parseLine(p: var TTmplParser) = proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream = - var p: TTmplParser - p.config = conf - p.info = newLineInfo(conf, filename, 0, 0) - p.outp = llStreamOpen("") - p.inp = stdin - p.subsChar = charArg(conf, call, "subschar", 1, '$') - p.nimDirective = charArg(conf, call, "metachar", 2, '#') - p.emit = strArg(conf, call, "emit", 3, "result.add") - p.conc = strArg(conf, call, "conc", 4, " & ") - p.toStr = strArg(conf, call, "tostring", 5, "$") - p.x = newStringOfCap(120) + var p = TTmplParser(config: conf, info: newLineInfo(conf, filename, 0, 0), + outp: llStreamOpen(""), inp: stdin, + subsChar: charArg(conf, call, "subschar", 1, '$'), + nimDirective: charArg(conf, call, "metachar", 2, '#'), + emit: strArg(conf, call, "emit", 3, "result.add"), + conc: strArg(conf, call, "conc", 4, " & "), + toStr: strArg(conf, call, "tostring", 5, "$"), + x: newStringOfCap(120) + ) # do not process the first line which contains the directive: if llStreamReadLine(p.inp, p.x): inc p.info.line From bf5d173bc65aea071e5ffdf593f6b8797b56816d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:53:21 +0800 Subject: [PATCH 402/489] fixes LineTooLong hints on old compilers (#22412) * fixes LineTooLong hints on old compilers * fixes config/nim.cfg --- compiler/condsyms.nim | 1 + compiler/nim.cfg | 1 + config/nim.cfg | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 58b89d9330..638cb5c1ef 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -160,3 +160,4 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimHasEnsureMove") defineSymbol("nimUseStrictDefs") + defineSymbol("nimHasNolineTooLong") diff --git a/compiler/nim.cfg b/compiler/nim.cfg index 4c55a04cbc..0400536851 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -50,3 +50,4 @@ define:useStdoutAsStdmsg warningAsError[Uninit]:on warningAsError[ProveInit]:on @end + diff --git a/config/nim.cfg b/config/nim.cfg index 1470de7805..7a2d5c76ef 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -14,6 +14,10 @@ cc = gcc # additional options always passed to the compiler: --parallel_build: "0" # 0 to auto-detect number of processors +@if not nimHasNolineTooLong: + hint[LineTooLong]=off +@end + @if nimHasAmbiguousEnumHint: # not needed if hint is a style check hint[AmbiguousEnum]=off From 10a6e4c236b8d4d609a07b29ad5b7b4e517cd367 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:55:18 +0800 Subject: [PATCH 403/489] clean up `gc:arc` or `gc:orc` in docs and in error messages (#22408) * clean up gc:arc/orc in docs * in error messages --- compiler/ccgexprs.nim | 2 +- lib/std/tasks.nim | 4 ++-- lib/system.nim | 4 ++-- lib/system/arc.nim | 6 +++--- lib/system/orc.nim | 10 +++++----- lib/system/osalloc.nim | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index cc0d0465c5..f1de6f757f 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2621,7 +2621,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mDeepCopy: if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions: localError(p.config, e.info, - "for --gc:arc|orc 'deepcopy' support has to be enabled with --deepcopy:on") + "for --mm:arc|atomicArc|orc 'deepcopy' support has to be enabled with --deepcopy:on") var a, b: TLoc = default(TLoc) let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1] diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim index 923cb2e994..6a4b2bb6d8 100644 --- a/lib/std/tasks.nim +++ b/lib/std/tasks.nim @@ -111,7 +111,7 @@ template addAllNode(assignParam: NimNode, procParam: NimNode) = macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkCallStrLit}): Task = ## Converts the call and its arguments to `Task`. - runnableExamples("--gc:orc"): + runnableExamples: proc hello(a: int) = echo a let b = toTask hello(13) @@ -259,7 +259,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC when defined(nimTasksDebug): echo result.repr -runnableExamples("--gc:orc"): +runnableExamples: block: var num = 0 proc hello(a: int) = inc num, a diff --git a/lib/system.nim b/lib/system.nim index 1bf1c5ccb4..3076fe2fda 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2565,7 +2565,7 @@ when hasAlloc and notJSnotNims: ## This is also used by the code generator ## for the implementation of `spawn`. ## - ## For `--gc:arc` or `--gc:orc` deepcopy support has to be enabled + ## For `--mm:arc` or `--mm:orc` deepcopy support has to be enabled ## via `--deepcopy:on`. discard @@ -2811,7 +2811,7 @@ when notJSnotNims and not defined(nimSeqsV2): ## String literals (e.g. "abc", etc) in the ARC/ORC mode are "copy on write", ## therefore you should call `prepareMutation` before modifying the strings ## via `addr`. - runnableExamples("--gc:arc"): + runnableExamples: var x = "abc" var y = "defgh" prepareMutation(y) # without this, you may get a `SIGBUS` or `SIGSEGV` diff --git a/lib/system/arc.nim b/lib/system/arc.nim index b264cbeddc..0624bd4e3a 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -223,15 +223,15 @@ proc GC_ref*[T](x: ref T) = when not defined(gcOrc): template GC_fullCollect* = - ## Forces a full garbage collection pass. With `--gc:arc` a nop. + ## Forces a full garbage collection pass. With `--mm:arc` a nop. discard template setupForeignThreadGc* = - ## With `--gc:arc` a nop. + ## With `--mm:arc` a nop. discard template tearDownForeignThreadGc* = - ## With `--gc:arc` a nop. + ## With `--mm:arc` a nop. discard proc isObjDisplayCheck(source: PNimTypeV2, targetDepth: int16, token: uint32): bool {.compilerRtl, inl.} = diff --git a/lib/system/orc.nim b/lib/system/orc.nim index b7b98c3404..335d49d0fa 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -424,13 +424,13 @@ proc GC_runOrc* = orcAssert roots.len == 0, "roots not empty!" proc GC_enableOrc*() = - ## Enables the cycle collector subsystem of `--gc:orc`. This is a `--gc:orc` + ## Enables the cycle collector subsystem of `--mm:orc`. This is a `--mm:orc` ## specific API. Check with `when defined(gcOrc)` for its existence. when not defined(nimStressOrc): rootsThreshold = 0 proc GC_disableOrc*() = - ## Disables the cycle collector subsystem of `--gc:orc`. This is a `--gc:orc` + ## Disables the cycle collector subsystem of `--mm:orc`. This is a `--mm:orc` ## specific API. Check with `when defined(gcOrc)` for its existence. when not defined(nimStressOrc): rootsThreshold = high(int) @@ -441,16 +441,16 @@ proc GC_partialCollect*(limit: int) = partialCollect(limit) proc GC_fullCollect* = - ## Forces a full garbage collection pass. With `--gc:orc` triggers the cycle + ## Forces a full garbage collection pass. With `--mm:orc` triggers the cycle ## collector. This is an alias for `GC_runOrc`. collectCycles() proc GC_enableMarkAndSweep*() = - ## For `--gc:orc` an alias for `GC_enableOrc`. + ## For `--mm:orc` an alias for `GC_enableOrc`. GC_enableOrc() proc GC_disableMarkAndSweep*() = - ## For `--gc:orc` an alias for `GC_disableOrc`. + ## For `--mm:orc` an alias for `GC_disableOrc`. GC_disableOrc() const diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 201be8540e..5509d0070c 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -30,7 +30,7 @@ const doNotUnmap = not (defined(amd64) or defined(i386)) or when defined(nimAllocPagesViaMalloc): when not defined(gcArc) and not defined(gcOrc) and not defined(gcAtomicArc): - {.error: "-d:nimAllocPagesViaMalloc is only supported with --gc:arc or --gc:orc".} + {.error: "-d:nimAllocPagesViaMalloc is only supported with --mm:arc or --mm:atomicArc or --mm:orc".} proc osTryAllocPages(size: int): pointer {.inline.} = let base = c_malloc(csize_t size + PageSize - 1 + sizeof(uint32)) From 73e661d01bdde815a5f388b960cd4d0593f7accc Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 8 Aug 2023 21:12:54 +0800 Subject: [PATCH 404/489] modernize compiler/reorder, which exposes yet another strictdefs bug (#22415) ```nim {.experimental: "strictdefs".} type NodeKind = enum nkImportStmt nkStmtList nkNone PNode = ref object kind: NodeKind proc hasImportStmt(n: PNode): bool = # Checks if the node is an import statement or # i it contains one case n.kind of nkImportStmt: return true of nkStmtList: if false: return true else: result = false var n = PNode() echo hasImportStmt(n) ``` It compiles without warnings, but shouldn't. As a contrast, ```nim {.experimental: "strictdefs".} type NodeKind = enum nkImportStmt nkStmtList nkNone PNode = ref object kind: NodeKind proc hasImportStmt(n: PNode): bool = # Checks if the node is an import statement or # i it contains one case n.kind of nkImportStmt: result = true of nkStmtList: if false: return true else: result = false var n = PNode() echo hasImportStmt(n) ``` This gives a proper warning. --- compiler/reorder.nim | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/compiler/reorder.nim b/compiler/reorder.nim index f43ddc2031..a96841bcad 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -25,17 +25,11 @@ when defined(nimDebugReorder): var idNames = newTable[int, string]() proc newDepN(id: int, pnode: PNode): DepN = - new(result) - result.id = id - result.pnode = pnode - result.idx = -1 - result.lowLink = -1 - result.onStack = false - result.kids = @[] - result.hAQ = -1 - result.hIS = -1 - result.hB = -1 - result.hCmd = -1 + result = DepN(id: id, pnode: pnode, idx: -1, + lowLink: -1, onStack: false, + kids: @[], hAQ: -1, hIS: -1, + hB: -1, hCmd: -1 + ) when defined(nimDebugReorder): result.expls = @[] @@ -114,7 +108,7 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev # XXX: for callables, this technically adds the return type dep before args for i in 0.. Date: Wed, 9 Aug 2023 08:18:47 +0800 Subject: [PATCH 405/489] modernize lineinfos; it seems that array access hinders strict def analysis like field access (#22420) modernize lineinfos; array access hinders strict def analysis like field access A bug ? ```nim proc computeNotesVerbosity(): array[0..3, TNoteKinds] = result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept} result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt} result[1] = result[2] - {warnProveField, warnProveIndex, warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd, hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin, hintPerformance} result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf, hintProcessing, hintPattern, hintExecuting, hintLinking, hintCC} ``` --- compiler/lineinfos.nim | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 6ebf3b5381..12495aa22f 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -7,8 +7,8 @@ # distribution, for details about the copyright. # -## This module contains the ``TMsgKind`` enum as well as the -## ``TLineInfo`` object. +## This module contains the `TMsgKind` enum as well as the +## `TLineInfo` object. import ropes, tables, pathutils, hashes @@ -248,6 +248,7 @@ type TNoteKinds* = set[TNoteKind] proc computeNotesVerbosity(): array[0..3, TNoteKinds] = + result = default(array[0..3, TNoteKinds]) result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept} result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt} result[1] = result[2] - {warnProveField, warnProveIndex, @@ -341,9 +342,8 @@ type proc initMsgConfig*(): MsgConfig = - result.msgContext = @[] - result.lastError = unknownLineInfo - result.filenameToIndexTbl = initTable[string, FileIndex]() - result.fileInfos = @[] - result.errorOutputs = {eStdOut, eStdErr} + result = MsgConfig(msgContext: @[], lastError: unknownLineInfo, + filenameToIndexTbl: initTable[string, FileIndex](), + fileInfos: @[], errorOutputs: {eStdOut, eStdErr} + ) result.filenameToIndexTbl["???"] = FileIndex(-1) From 3aaef9e4cf014d5df65a686efe6b8bd99d3ea465 Mon Sep 17 00:00:00 2001 From: metagn Date: Wed, 9 Aug 2023 07:12:14 +0300 Subject: [PATCH 406/489] block ambiguous type conversion dotcalls in generics (#22375) fixes #22373 --- compiler/semgnrc.nim | 11 +++++++++++ tests/generics/m22373a.nim | 7 +++++++ tests/generics/m22373b.nim | 18 ++++++++++++++++++ tests/generics/t22373.nim | 16 ++++++++++++++++ tests/generics/timports.nim | 5 +++++ 5 files changed, 57 insertions(+) create mode 100644 tests/generics/m22373a.nim create mode 100644 tests/generics/m22373b.nim create mode 100644 tests/generics/t22373.nim diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 43b8d4bac4..c8eda9c37d 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -168,6 +168,17 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, elif s.isMixedIn: result = newDot(result, symChoice(c, n, s, scForceOpen)) else: + if s.kind == skType and candidates.len > 1: + var ambig = false + let s2 = searchInScopes(c, ident, ambig) + if ambig: + # this is a type conversion like a.T where T is ambiguous with + # other types or routines + # in regular code, this never considers a type conversion and + # skips to routine overloading + # so symchoices are used which behave similarly with type symbols + result = newDot(result, symChoice(c, n, s, scForceOpen)) + return let syms = semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true) result = newDot(result, syms) diff --git a/tests/generics/m22373a.nim b/tests/generics/m22373a.nim new file mode 100644 index 0000000000..28e087ca61 --- /dev/null +++ b/tests/generics/m22373a.nim @@ -0,0 +1,7 @@ +# module a for t22373 + +# original: +type LightClientHeader* = object + +# simplified: +type TypeOrTemplate* = object diff --git a/tests/generics/m22373b.nim b/tests/generics/m22373b.nim new file mode 100644 index 0000000000..67ee4211be --- /dev/null +++ b/tests/generics/m22373b.nim @@ -0,0 +1,18 @@ +# module b for t22373 + +import m22373a + +# original: +type + LightClientDataFork* {.pure.} = enum + None = 0, + Altair = 1 +template LightClientHeader*(kind: static LightClientDataFork): auto = + when kind == LightClientDataFork.Altair: + typedesc[m22373a.LightClientHeader] + else: + static: raiseAssert "Unreachable" + +# simplified: +template TypeOrTemplate*(num: int): untyped = + typedesc[m22373a.TypeOrTemplate] diff --git a/tests/generics/t22373.nim b/tests/generics/t22373.nim new file mode 100644 index 0000000000..ecfaf0f1ba --- /dev/null +++ b/tests/generics/t22373.nim @@ -0,0 +1,16 @@ +# issue #22373 + +import m22373a +import m22373b + +# original: +template lazy_header(name: untyped): untyped {.dirty.} = + var `name _ ptr`: ptr[data_fork.LightClientHeader] # this data_fork.Foo part seems required to reproduce +proc createLightClientUpdates(data_fork: static LightClientDataFork) = + lazy_header(attested_header) +createLightClientUpdates(LightClientDataFork.Altair) + +# simplified: +proc generic[T](abc: T) = + var x: abc.TypeOrTemplate +generic(123) diff --git a/tests/generics/timports.nim b/tests/generics/timports.nim index 43f096664e..6b71cb6d3b 100644 --- a/tests/generics/timports.nim +++ b/tests/generics/timports.nim @@ -46,6 +46,11 @@ block tdotlookup: x.set("hello", "world") result = x doAssert abc(5) == 10 + block: # ensure normal call is consistent with dot call + proc T(x: int): float = x.float + proc foo[T](x: int) = + doAssert typeof(T(x)) is typeof(x.T) + foo[uint](123) block tmodule_same_as_proc: # bug #1965 From ce079a8da45c8513b8864f92be4baba40a44fb7b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 9 Aug 2023 12:33:19 +0800 Subject: [PATCH 407/489] modernize jsgen; clean up some leftovers (#22423) --- compiler/jsgen.nim | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index a3df0a2ba3..1a31547534 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -137,17 +137,15 @@ template nested(p, body) = dec p.extraIndent proc newGlobals(): PGlobals = - new(result) - result.forwarded = @[] - result.generatedSyms = initIntSet() - result.typeInfoGenerated = initIntSet() + result = PGlobals(forwarded: @[], + generatedSyms: initIntSet(), + typeInfoGenerated: initIntSet() + ) -proc initCompRes(r: var TCompRes) = - r.address = "" - r.res = "" - r.tmpLoc = "" - r.typ = etyNone - r.kind = resNone +proc initCompRes(): TCompRes = + result = TCompRes(address: "", res: "", + tmpLoc: "", typ: etyNone, kind: resNone + ) proc rdLoc(a: TCompRes): Rope {.inline.} = if a.typ != etyBaseIndex: @@ -350,9 +348,10 @@ proc isSimpleExpr(p: PProc; n: PNode): bool = if n[i].kind notin {nkCommentStmt, nkEmpty}: return false result = isSimpleExpr(p, n.lastSon) else: - result = false if n.isAtom: result = true + else: + result = false proc getTemp(p: PProc, defineInLocals: bool = true): Rope = inc(p.unique) @@ -3006,13 +3005,11 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = proc newModule(g: ModuleGraph; module: PSym): BModule = ## Create a new JS backend module node. - new(result) - result.module = module - result.sigConflicts = initCountTable[SigHash]() if g.backend == nil: g.backend = newGlobals() - result.graph = g - result.config = g.config + result = BModule(module: module, sigConflicts: initCountTable[SigHash](), + graph: g, config: g.config + ) if sfSystemModule in module.flags: PGlobals(g.backend).inSystem = true From 28b2e429ef64503f7a239ee8fc3043c3fe883ec6 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 9 Aug 2023 12:40:17 +0800 Subject: [PATCH 408/489] refactors initSrcGen and initTokRender into returning objects (#22421) --- compiler/docgen.nim | 13 +++---- compiler/renderer.nim | 84 ++++++++++++++++--------------------------- 2 files changed, 36 insertions(+), 61 deletions(-) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 4a0ae6fc9b..6a78d86932 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -492,9 +492,8 @@ proc externalDep(d: PDoc; module: PSym): string = proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string; renderFlags: TRenderFlags = {}; procLink: string) = - var r: TSrcGen = TSrcGen() + var r: TSrcGen = initTokRender(n, renderFlags) var literal = "" - initTokRender(r, n, renderFlags) var kind = tkEof var tokenPos = 0 var procTokenPos = 0 @@ -1030,8 +1029,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol = genNode = n[miscPos][1] # FIXME: what is index 1? if genNode != nil: var literal = "" - var r: TSrcGen - initTokRender(r, genNode, {renderNoBody, renderNoComments, + var r: TSrcGen = initTokRender(genNode, {renderNoBody, renderNoComments, renderNoPragmas, renderNoProcDefs, renderExpandUsing}) var kind = tkEof while true: @@ -1058,9 +1056,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx else: comm.add genRecComment(d, n) - var r: TSrcGen # Obtain the plain rendered string for hyperlink titles. - initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments, + var r: TSrcGen = initTokRender(n, {renderNoBody, renderNoComments, renderDocComments, renderNoPragmas, renderNoProcDefs, renderExpandUsing}) while true: getNextTok(r, kind, literal) @@ -1164,11 +1161,11 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): var name = getNameEsc(d, nameNode) comm = genRecComment(d, n) - r: TSrcGen = default(TSrcGen) + r: TSrcGen renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing} if nonExports: renderFlags.incl renderNonExportedFields - initTokRender(r, n, renderFlags) + r = initTokRender(n, renderFlags) result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int, "col": %n.info.col} if comm != nil: diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 2af8d83269..e39be78fe9 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -145,19 +145,13 @@ const MaxLineLen = 80 LineCommentColumn = 30 -proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) = - g.comStack = @[] - g.tokens = @[] - g.indent = 0 - g.lineLen = 0 - g.pos = 0 - g.idx = 0 - g.buf = "" - g.flags = renderFlags - g.pendingNL = -1 - g.pendingWhitespace = -1 - g.inside = {} - g.config = config +proc initSrcGen(renderFlags: TRenderFlags; config: ConfigRef): TSrcGen = + result = TSrcGen(comStack: @[], tokens: @[], indent: 0, + lineLen: 0, pos: 0, idx: 0, buf: "", + flags: renderFlags, pendingNL: -1, + pendingWhitespace: -1, inside: {}, + config: config + ) proc addTok(g: var TSrcGen, kind: TokType, s: string; sym: PSym = nil) = g.tokens.add TRenderTok(kind: kind, length: int16(s.len), sym: sym) @@ -630,14 +624,12 @@ type const emptyContext: TContext = (spacing: 0, flags: {}) -proc initContext(c: var TContext) = - c.spacing = 0 - c.flags = {} +proc initContext(): TContext = + result = (spacing: 0, flags: {}) proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) proc gsub(g: var TSrcGen, n: PNode, fromStmtList = false) = - var c: TContext = default(TContext) - initContext(c) + var c: TContext = initContext() gsub(g, n, c, fromStmtList = fromStmtList) proc hasCom(n: PNode): bool = @@ -767,9 +759,8 @@ proc gcond(g: var TSrcGen, n: PNode) = put(g, tkParRi, ")") proc gif(g: var TSrcGen, n: PNode) = - var c: TContext = default(TContext) + var c: TContext = initContext() gcond(g, n[0][0]) - initContext(c) putWithSpace(g, tkColon, ":") if longMode(g, n) or (lsub(g, n[0][1]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) @@ -780,20 +771,18 @@ proc gif(g: var TSrcGen, n: PNode) = gsub(g, n[i], c) proc gwhile(g: var TSrcGen, n: PNode) = - var c: TContext = default(TContext) + var c: TContext = initContext() putWithSpace(g, tkWhile, "while") gcond(g, n[0]) putWithSpace(g, tkColon, ":") - initContext(c) if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) # a good place for comments gstmts(g, n[1], c) proc gpattern(g: var TSrcGen, n: PNode) = - var c: TContext = default(TContext) + var c: TContext = initContext() put(g, tkCurlyLe, "{") - initContext(c) if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) # a good place for comments @@ -801,20 +790,18 @@ proc gpattern(g: var TSrcGen, n: PNode) = put(g, tkCurlyRi, "}") proc gpragmaBlock(g: var TSrcGen, n: PNode) = - var c: TContext = default(TContext) + var c: TContext = initContext() gsub(g, n[0]) putWithSpace(g, tkColon, ":") - initContext(c) if longMode(g, n) or (lsub(g, n[1]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) # a good place for comments gstmts(g, n[1], c) proc gtry(g: var TSrcGen, n: PNode) = - var c: TContext = default(TContext) + var c: TContext = initContext() put(g, tkTry, "try") putWithSpace(g, tkColon, ":") - initContext(c) if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) # a good place for comments @@ -822,9 +809,8 @@ proc gtry(g: var TSrcGen, n: PNode) = gsons(g, n, c, 1) proc gfor(g: var TSrcGen, n: PNode) = - var c: TContext = default(TContext) + var c: TContext = initContext() putWithSpace(g, tkFor, "for") - initContext(c) if longMode(g, n) or (lsub(g, n[^1]) + lsub(g, n[^2]) + 6 + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) @@ -837,8 +823,7 @@ proc gfor(g: var TSrcGen, n: PNode) = gstmts(g, n[^1], c) proc gcase(g: var TSrcGen, n: PNode) = - var c: TContext = default(TContext) - initContext(c) + var c: TContext = initContext() if n.len == 0: return var last = if n[^1].kind == nkElse: -2 else: -1 if longMode(g, n, 0, last): incl(c.flags, rfLongMode) @@ -848,7 +833,7 @@ proc gcase(g: var TSrcGen, n: PNode) = optNL(g) gsons(g, n, c, 1, last) if last == - 2: - initContext(c) + c = initContext() if longMode(g, n[^1]): incl(c.flags, rfLongMode) gsub(g, n[^1], c) @@ -858,7 +843,7 @@ proc genSymSuffix(result: var string, s: PSym) {.inline.} = result.addInt s.id proc gproc(g: var TSrcGen, n: PNode) = - var c: TContext = default(TContext) + var c: TContext = initContext() if n[namePos].kind == nkSym: let s = n[namePos].sym var ret = renderDefinitionName(s) @@ -885,7 +870,7 @@ proc gproc(g: var TSrcGen, n: PNode) = indentNL(g) gcoms(g) dedent(g) - initContext(c) + c = initContext() gstmts(g, n[bodyPos], c) putNL(g) else: @@ -894,8 +879,7 @@ proc gproc(g: var TSrcGen, n: PNode) = dedent(g) proc gTypeClassTy(g: var TSrcGen, n: PNode) = - var c: TContext = default(TContext) - initContext(c) + var c: TContext = initContext() putWithSpace(g, tkConcept, "concept") gsons(g, n[0], c) # arglist gsub(g, n[1]) # pragmas @@ -914,8 +898,7 @@ proc gblock(g: var TSrcGen, n: PNode) = if n.len == 0: return - var c: TContext = default(TContext) - initContext(c) + var c: TContext = initContext() if n[0].kind != nkEmpty: putWithSpace(g, tkBlock, "block") @@ -935,10 +918,9 @@ proc gblock(g: var TSrcGen, n: PNode) = gstmts(g, n[1], c) proc gstaticStmt(g: var TSrcGen, n: PNode) = - var c: TContext = default(TContext) + var c: TContext = initContext() putWithSpace(g, tkStatic, "static") putWithSpace(g, tkColon, ":") - initContext(c) if longMode(g, n) or (lsub(g, n[0]) + g.lineLen > MaxLineLen): incl(c.flags, rfLongMode) gcoms(g) # a good place for comments @@ -1631,7 +1613,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = of nkTypeSection: gsection(g, n, emptyContext, tkType, "type") of nkConstSection: - initContext(a) + a = initContext() incl(a.flags, rfInConstExpr) gsection(g, n, a, tkConst, "const") of nkVarSection, nkLetSection, nkUsingStmt: @@ -1799,13 +1781,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = gsub(g, n, 0) put(g, tkParRi, ")") of nkGotoState: - var c: TContext = default(TContext) - initContext c + var c: TContext = initContext() putWithSpace g, tkSymbol, "goto" gsons(g, n, c) of nkState: - var c: TContext = default(TContext) - initContext c + var c: TContext = initContext() putWithSpace g, tkSymbol, "state" gsub(g, n[0], c) putWithSpace(g, tkColon, ":") @@ -1829,8 +1809,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) = proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string = if n == nil: return "" - var g: TSrcGen = default(TSrcGen) - initSrcGen(g, renderFlags, newPartialConfigRef()) + var g: TSrcGen = initSrcGen(renderFlags, newPartialConfigRef()) # do not indent the initial statement list so that # writeFile("file.nim", repr n) # produces working Nim code: @@ -1848,8 +1827,7 @@ proc renderModule*(n: PNode, outfile: string, conf: ConfigRef = nil) = var f: File = default(File) - g: TSrcGen - initSrcGen(g, renderFlags, conf) + g: TSrcGen = initSrcGen(renderFlags, conf) g.fid = fid for i in 0.. Date: Wed, 9 Aug 2023 13:18:50 +0800 Subject: [PATCH 409/489] make the name of procs consistent with the name forwards (#22424) It seems that `--stylecheck:error` acts up when the name forwards is involved. ```nim proc thisOne*(x: var int) proc thisone(x: var int) = x = 1 ``` It cannot understand this at all. --- compiler/astalgo.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index d0aec085f5..621bd23808 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -109,7 +109,7 @@ type data*: TIIPairSeq -proc initIiTable*(x: var TIITable) +proc initIITable*(x: var TIITable) proc iiTableGet*(t: TIITable, key: int): int proc iiTablePut*(t: var TIITable, key, val: int) From 989da75b84e15a6d585e8b03d2bcd0c42a90c2fb Mon Sep 17 00:00:00 2001 From: Bung Date: Wed, 9 Aug 2023 15:43:39 +0800 Subject: [PATCH 410/489] fix #20891 Illegal capture error of env its self (#22414) * fix #20891 Illegal capture error of env its self * fix innerClosure too earlier, make condition shorter --- compiler/ast.nim | 6 ++++++ compiler/lambdalifting.nim | 10 +++++++--- tests/iter/t20891.nim | 28 ++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 tests/iter/t20891.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index 55ee0e20de..fc3f523787 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -2083,6 +2083,12 @@ proc isClosureIterator*(typ: PType): bool {.inline.} = proc isClosure*(typ: PType): bool {.inline.} = typ.kind == tyProc and typ.callConv == ccClosure +proc isNimcall*(s: PSym): bool {.inline.} = + s.typ.callConv == ccNimCall + +proc isExplicitCallConv*(s: PSym): bool {.inline.} = + tfExplicitCallConv in s.typ.flags + proc isSinkParam*(s: PSym): bool {.inline.} = s.kind == skParam and (s.typ.kind == tySink or tfHasOwned in s.typ.flags) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index ac4c160f93..37c913fe2e 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -297,17 +297,19 @@ proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner: proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) = let s = n.sym + let isEnv = s.name.id == getIdent(g.cache, ":env").id if illegalCapture(s): localError(g.config, n.info, ("'$1' is of type <$2> which cannot be captured as it would violate memory" & " safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases." & " Consider using a which can be captured.") % [s.name.s, typeToString(s.typ), g.config$s.info]) - elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags): + elif not (owner.typ.isClosure or owner.isNimcall and not owner.isExplicitCallConv or isEnv): localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" % [s.name.s, owner.name.s, $owner.typ.callConv]) incl(owner.typ.flags, tfCapturesEnv) - owner.typ.callConv = ccClosure + if not isEnv: + owner.typ.callConv = ccClosure type DetectionPass = object @@ -448,6 +450,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = let body = transformBody(c.graph, c.idgen, s, useCache) detectCapturedVars(body, s, c) let ow = s.skipGenericOwner + let innerClosure = innerProc and s.typ.callConv == ccClosure and not s.isIterator + let interested = interestingVar(s) if ow == owner: if owner.isIterator: c.somethingToDo = true @@ -462,7 +466,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = else: discard addField(obj, s, c.graph.cache, c.idgen) # direct or indirect dependency: - elif (innerProc and not s.isIterator and s.typ.callConv == ccClosure) or interestingVar(s): + elif innerClosure or interested: discard """ proc outer() = var x: int diff --git a/tests/iter/t20891.nim b/tests/iter/t20891.nim new file mode 100644 index 0000000000..34deec41bd --- /dev/null +++ b/tests/iter/t20891.nim @@ -0,0 +1,28 @@ +import macros, tables + +var mapping {.compileTime.}: Table[string, NimNode] + +macro register(a: static[string], b: typed): untyped = + mapping[a] = b + +macro getPtr(a: static[string]): untyped = + result = mapping[a] + +proc foo() = + iterator it() {.closure.} = + discard + proc getIterPtr(): pointer {.nimcall.} = + rawProc(it) + register("foo", getIterPtr()) + discard getIterPtr() # Comment either this to make it work +foo() # or this + +proc bar() = + iterator it() {.closure.} = + discard getPtr("foo") # Or this + discard + proc getIterPtr(): pointer {.nimcall.} = + rawProc(it) + register("bar", getIterPtr()) + discard getIterPtr() +bar() From 5334dc921fc177bf6253256dcd579baf244f1ad8 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 9 Aug 2023 18:43:17 +0800 Subject: [PATCH 411/489] fixes #22419; async/closure environment does not align local variables (#22425) * fixes #22419; async/closure environment does not align local variables * Apply suggestions from code review * Update tests/align/talign.nim Co-authored-by: Jacek Sieka * apply code review * update tests --------- Co-authored-by: Jacek Sieka --- compiler/lowerings.nim | 3 +++ tests/align/talign.nim | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index d70c713a15..a083b91953 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -237,6 +237,9 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item) let t = skipIntLit(s.typ, idgen) field.typ = t + if s.kind in {skLet, skVar, skField, skForVar}: + #field.bitsize = s.bitsize + field.alignment = s.alignment assert t.kind != tyTyped propagateToOwner(obj, t) field.position = obj.n.len diff --git a/tests/align/talign.nim b/tests/align/talign.nim index 3b8f6b4dfb..08373ee497 100644 --- a/tests/align/talign.nim +++ b/tests/align/talign.nim @@ -51,3 +51,19 @@ type Bug[T] = object var bug: Bug[int] doAssert sizeof(bug) == 128, "Oops my size is " & $sizeof(bug) # 16 + + +block: # bug #22419 + type + ValidatorPubKey = object + blob: array[96, byte] + + proc f(): auto = + return iterator() = + var pad: int8 = 0 + var y {.align: 16.}: ValidatorPubKey + let value = cast[uint64](addr y) + doAssert value mod 16 == 0 + + f()() + From d53a89e4539a33d9f7cf8416155d7cb700628872 Mon Sep 17 00:00:00 2001 From: Bung Date: Wed, 9 Aug 2023 18:45:43 +0800 Subject: [PATCH 412/489] fix #12938 index type of array in type section without static (#20529) * fix #12938 nim compiler assertion fail when literal integer is passed as template argument for array size * use new flag tfImplicitStatic * fix * fix #14193 * correct tfUnresolved add condition * clean test --- compiler/ast.nim | 1 + compiler/semtypes.nim | 57 ++++++++++++++++++++++++--------------- tests/generics/t12938.nim | 9 +++++++ tests/generics/t14193.nim | 6 +++++ 4 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 tests/generics/t12938.nim create mode 100644 tests/generics/t14193.nim diff --git a/compiler/ast.nim b/compiler/ast.nim index fc3f523787..d62b563682 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -591,6 +591,7 @@ type tfEffectSystemWorkaround tfIsOutParam tfSendable + tfImplicitStatic TTypeFlags* = set[TTypeFlag] diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 06be954e6d..5e72996ac1 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -335,6 +335,14 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType = localError(c.config, n.info, errXExpectsOneTypeParam % "range") result = newOrPrevType(tyError, prev, c) +proc semArrayIndexConst(c: PContext, e: PNode, info: TLineInfo): PType = + let x = semConstExpr(c, e) + if x.kind in {nkIntLit..nkUInt64Lit}: + result = makeRangeType(c, 0, x.intVal-1, info, + x.typ.skipTypes({tyTypeDesc})) + else: + result = x.typ.skipTypes({tyTypeDesc}) + proc semArrayIndex(c: PContext, n: PNode): PType = if isRange(n): result = semRangeAux(c, n, nil) @@ -351,14 +359,18 @@ proc semArrayIndex(c: PContext, n: PNode): PType = localError(c.config, n.info, "Array length can't be negative, but was " & $e.intVal) result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ) - elif e.kind == nkSym and e.typ.kind == tyStatic: - if e.sym.ast != nil: - return semArrayIndex(c, e.sym.ast) - if e.typ.lastSon.kind != tyGenericParam and not isOrdinalType(e.typ.lastSon): - let info = if n.safeLen > 1: n[1].info else: n.info - localError(c.config, info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc)) - result = makeRangeWithStaticExpr(c, e) - if c.inGenericContext > 0: result.flags.incl tfUnresolved + elif e.kind == nkSym and (e.typ.kind == tyStatic or e.typ.kind == tyTypeDesc) : + if e.typ.kind == tyStatic: + if e.sym.ast != nil: + return semArrayIndex(c, e.sym.ast) + if e.typ.lastSon.kind != tyGenericParam and not isOrdinalType(e.typ.lastSon): + let info = if n.safeLen > 1: n[1].info else: n.info + localError(c.config, info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc)) + result = makeRangeWithStaticExpr(c, e) + if c.inGenericContext > 0: result.flags.incl tfUnresolved + else: + result = e.typ.skipTypes({tyTypeDesc}) + result.flags.incl tfImplicitStatic elif e.kind in (nkCallKinds + {nkBracketExpr}) and hasUnresolvedArgs(c, e): if not isOrdinalType(e.typ.skipTypes({tyStatic, tyAlias, tyGenericInst, tySink})): localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc)) @@ -371,12 +383,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType = elif e.kind == nkIdent: result = e.typ.skipTypes({tyTypeDesc}) else: - let x = semConstExpr(c, e) - if x.kind in {nkIntLit..nkUInt64Lit}: - result = makeRangeType(c, 0, x.intVal-1, n.info, - x.typ.skipTypes({tyTypeDesc})) - else: - result = x.typ.skipTypes({tyTypeDesc}) + result = semArrayIndexConst(c, e, n.info) #localError(c.config, n[1].info, errConstExprExpected) proc semArray(c: PContext, n: PNode, prev: PType): PType = @@ -1504,20 +1511,24 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = var t = s.typ.skipTypes({tyAlias}) if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody: t = t.base - result = newOrPrevType(tyGenericInvocation, prev, c) addSonSkipIntLit(result, t, c.idgen) - template addToResult(typ) = + template addToResult(typ, skip) = + if typ.isNil: internalAssert c.config, false rawAddSon(result, typ) - else: addSonSkipIntLit(result, typ, c.idgen) + else: + if skip: + addSonSkipIntLit(result, typ, c.idgen) + else: + rawAddSon(result, makeRangeWithStaticExpr(c, typ.n)) if t.kind == tyForward: for i in 1..= i - 1 and tfImplicitStatic in rType[i - 1].flags and isIntLit(typ): + skip = false + addToResult(typ, skip) if isConcrete: if s.ast == nil and s.typ.kind != tyCompositeTypeClass: diff --git a/tests/generics/t12938.nim b/tests/generics/t12938.nim new file mode 100644 index 0000000000..e09d65c7ae --- /dev/null +++ b/tests/generics/t12938.nim @@ -0,0 +1,9 @@ +type + ExampleArray[Size, T] = array[Size, T] + +var integerArray: ExampleArray[32, int] # Compiler crash! +doAssert integerArray.len == 32 + +const Size = 2 +var integerArray2: ExampleArray[Size, int] +doAssert integerArray2.len == 2 diff --git a/tests/generics/t14193.nim b/tests/generics/t14193.nim new file mode 100644 index 0000000000..213b1a8e6e --- /dev/null +++ b/tests/generics/t14193.nim @@ -0,0 +1,6 @@ +type + Task*[N: int] = object + env*: array[N, byte] + +var task14193: Task[20] +doAssert task14193.env.len == 20 From 5ec81d076b2ddd11655ec1e90938ea08c907ab0b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 9 Aug 2023 19:49:30 +0800 Subject: [PATCH 413/489] fixes cascades of out parameters, which produces wrong ProveInit warnings (#22413) --- compiler/sempass2.nim | 14 ++++++++++---- tests/init/toutparams.nim | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/init/toutparams.nim diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index af283af303..c12cc6cb3d 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -846,7 +846,9 @@ proc trackCall(tracked: PEffects; n: PNode) = if n.typ != nil: if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray: createTypeBoundOps(tracked, n.typ, n.info) - if getConstExpr(tracked.ownerModule, n, tracked.c.idgen, tracked.graph) == nil: + + let notConstExpr = getConstExpr(tracked.ownerModule, n, tracked.c.idgen, tracked.graph) == nil + if notConstExpr: if a.kind == nkCast and a[1].typ.kind == tyProc: a = a[1] # XXX: in rare situations, templates and macros will reach here after @@ -905,9 +907,6 @@ proc trackCall(tracked: PEffects; n: PNode) = optStaticBoundsCheck in tracked.currOptions: checkBounds(tracked, n[1], n[2]) - if a.kind != nkSym or a.sym.magic notin {mRunnableExamples, mNBindSym, mExpandToAst, mQuoteAst}: - for i in 0.. 0 and a.sym.name.s[0] == '=' and tracked.owner.kind != skMacro: @@ -943,6 +942,13 @@ proc trackCall(tracked: PEffects; n: PNode) = tracked.hasSideEffect = true else: discard + if notConstExpr and (a.kind != nkSym or + a.sym.magic notin {mRunnableExamples, mNBindSym, mExpandToAst, mQuoteAst} + ): + # tracked after out analysis + for i in 0.. Date: Wed, 9 Aug 2023 23:17:08 +0800 Subject: [PATCH 414/489] Fix #5780 (#22428) * fix #5780 --- compiler/sigmatch.nim | 2 +- tests/statictypes/t5780.nim | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 tests/statictypes/t5780.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 462f5d0d1a..c0b74f8214 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1225,7 +1225,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyArray: var fRange = f[0] var aRange = a[0] - if fRange.kind == tyGenericParam: + if fRange.kind in {tyGenericParam, tyAnything}: var prev = PType(idTableGet(c.bindings, fRange)) if prev == nil: put(c, fRange, a[0]) diff --git a/tests/statictypes/t5780.nim b/tests/statictypes/t5780.nim new file mode 100644 index 0000000000..85548aaadd --- /dev/null +++ b/tests/statictypes/t5780.nim @@ -0,0 +1,3 @@ +type StringArray[N:int] = array[N, string] +let a = ["one", "two"] +doAssert a is StringArray From 91c32218559924ef4f74302310e9195773183f79 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 10 Aug 2023 02:57:13 +0800 Subject: [PATCH 415/489] simplify isAtom condition (#22430) --- compiler/ccgexprs.nim | 5 +---- compiler/jsgen.nim | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index f1de6f757f..46a353dce0 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1152,10 +1152,7 @@ proc isSimpleExpr(n: PNode): bool = if n[i].kind notin {nkCommentStmt, nkEmpty}: return false result = isSimpleExpr(n.lastSon) else: - if n.isAtom: - result = true - else: - result = false + result = n.isAtom proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = # how to generate code? diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 1a31547534..8659d511bf 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -348,10 +348,7 @@ proc isSimpleExpr(p: PProc; n: PNode): bool = if n[i].kind notin {nkCommentStmt, nkEmpty}: return false result = isSimpleExpr(p, n.lastSon) else: - if n.isAtom: - result = true - else: - result = false + result = n.isAtom proc getTemp(p: PProc, defineInLocals: bool = true): Rope = inc(p.unique) From 6ec1c80779831875b2552d6ba2d613503b53a012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Wed, 9 Aug 2023 19:57:52 +0100 Subject: [PATCH 416/489] makes asmnostackframe work with cpp member #22411 (#22429) --- compiler/cgen.nim | 7 ++++--- tests/cpp/tvirtual.nim | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index e21d85a072..af30f546ec 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1142,7 +1142,8 @@ proc isNoReturn(m: BModule; s: PSym): bool {.inline.} = proc genProcAux*(m: BModule, prc: PSym) = var p = newProc(prc, m) var header = newRopeAppender() - if m.config.backend == backendCpp and sfCppMember * prc.flags != {}: + let isCppMember = m.config.backend == backendCpp and sfCppMember * prc.flags != {} + if isCppMember: genMemberProcHeader(m, prc, header) else: genProcHeader(m, prc, header) @@ -1205,10 +1206,10 @@ proc genProcAux*(m: BModule, prc: PSym) = var generatedProc: Rope = "" generatedProc.genCLineDir prc.info, m.config if isNoReturn(p.module, prc): - if hasDeclspec in extccomp.CC[p.config.cCompiler].props: + if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember: header = "__declspec(noreturn) " & header if sfPure in prc.flags: - if hasDeclspec in extccomp.CC[p.config.cCompiler].props: + if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember: header = "__declspec(naked) " & header generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N", [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]) diff --git a/tests/cpp/tvirtual.nim b/tests/cpp/tvirtual.nim index 7acec21baa..fb792380b3 100644 --- a/tests/cpp/tvirtual.nim +++ b/tests/cpp/tvirtual.nim @@ -79,3 +79,40 @@ type Doo = object proc naiveMember(x: Doo): int {. virtual .} = 2 discard naiveMember(Doo()) +#asmnostackframe works with virtual +{.emit:"""/*TYPESECTION*/ + template + struct Box { + T* first; + + Box(int x){ + first = new T(x); + }; + }; + struct Inner { + int val; + //Coo() = default; + Inner(int x){ + val = x; + }; + }; + struct Base { + virtual Box test() = 0; + }; +""".} + +type + Inner {.importcpp.} = object + Base {.importcpp, inheritable.} = object + Child = object of Base + Box[T] {.importcpp, inheritable.} = object + first: T + +proc makeBox[T](x:int32): Box[T] {.importcpp:"Box<'0>(@)", constructor.} + +proc test(self: Child): Box[Inner] {.virtual, asmnostackframe.} = + let res {.exportc.} = makeBox[Inner](100) + {.emit:"return res;".} + + +discard Child().test() \ No newline at end of file From fa58d23080dad13283cd180260b14cf8c57ab501 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 10 Aug 2023 11:29:42 +0800 Subject: [PATCH 417/489] modernize sempass2; `initEffects` now returns `TEffects` (#22435) --- compiler/sempass2.nim | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index c12cc6cb3d..0aa8080597 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1433,27 +1433,21 @@ proc rawInitEffects(g: ModuleGraph; effects: PNode) = effects[ensuresEffects] = g.emptyNode effects[pragmasEffects] = g.emptyNode -proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects; c: PContext) = +proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; c: PContext): TEffects = rawInitEffects(g, effects) - t.exc = effects[exceptionEffects] - t.tags = effects[tagEffects] - t.forbids = effects[forbiddenEffects] - t.owner = s - t.ownerModule = s.getModule - t.init = @[] - t.guards.s = @[] - t.guards.g = g + result = TEffects(exc: effects[exceptionEffects], tags: effects[tagEffects], + forbids: effects[forbiddenEffects], owner: s, ownerModule: s.getModule, + init: @[], locked: @[], graph: g, config: g.config, c: c, + currentBlock: 1 + ) + result.guards.s = @[] + result.guards.g = g when defined(drnim): - t.currOptions = g.config.options + s.options - {optStaticBoundsCheck} + result.currOptions = g.config.options + s.options - {optStaticBoundsCheck} else: - t.currOptions = g.config.options + s.options - t.guards.beSmart = optStaticBoundsCheck in t.currOptions - t.locked = @[] - t.graph = g - t.config = g.config - t.c = c - t.currentBlock = 1 + result.currOptions = g.config.options + s.options + result.guards.beSmart = optStaticBoundsCheck in result.currOptions proc hasRealBody(s: PSym): bool = ## also handles importc procs with runnableExamples, which requires `=`, @@ -1474,8 +1468,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) = var inferredEffects = newNodeI(nkEffectList, s.info) - var t: TEffects = default(TEffects) - initEffects(g, inferredEffects, s, t, c) + var t: TEffects = initEffects(g, inferredEffects, s, c) rawInitEffects g, effects if not isEmptyType(s.typ[0]) and @@ -1586,8 +1579,7 @@ proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) = return let g = c.graph var effects = newNodeI(nkEffectList, n.info) - var t: TEffects - initEffects(g, effects, module, t, c) + var t: TEffects = initEffects(g, effects, module, c) t.isTopLevel = isTopLevel track(t, n) when defined(drnim): From baf350493b08d5e1ee25f61b7d7eff33c3499487 Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Thu, 10 Aug 2023 07:56:09 +0200 Subject: [PATCH 418/489] Fix #21760 (#22422) * Remove call-specific replaceTypeVarsN * Run for all call kinds and ignore typedesc * Testcase --------- Co-authored-by: SirOlaf <> --- compiler/seminst.nim | 4 ++-- tests/generics/t21760.nim | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 tests/generics/t21760.nim diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 22d28999d8..0dc3e3cfc9 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -275,9 +275,9 @@ proc instantiateProcType(c: PContext, pt: TIdTable, # call head symbol, because this leads to infinite recursion. if oldParam.ast != nil: var def = oldParam.ast.copyTree - if def.kind == nkCall: + if def.kind in nkCallKinds: for i in 1.. Date: Thu, 10 Aug 2023 13:57:34 +0800 Subject: [PATCH 419/489] `initLocExpr` and friends now return `TLoc` (#22434) `initLocExpr` and friends now return TLoc --- compiler/ccgcalls.nim | 58 +++--- compiler/ccgexprs.nim | 399 +++++++++++++++++------------------------- compiler/ccgstmts.nim | 83 ++++----- compiler/cgen.nim | 35 ++-- 4 files changed, 234 insertions(+), 341 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index dca581fadc..b446e83607 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -118,8 +118,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, getTempCpp(p, typ[0], d, pl) else: if d.k == locNone: getTemp(p, typ[0], d) - var list: TLoc - initLoc(list, locCall, d.lode, OnUnknown) + var list = initLoc(locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying if canRaise: raiseExit(p) @@ -127,16 +126,14 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, elif isHarmlessStore(p, canRaise, d): if d.k == locNone: getTemp(p, typ[0], d) assert(d.t != nil) # generate an assignment to d: - var list: TLoc - initLoc(list, locCall, d.lode, OnUnknown) + var list = initLoc(locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying if canRaise: raiseExit(p) else: var tmp: TLoc getTemp(p, typ[0], tmp, needsInit=true) - var list: TLoc = default(TLoc) - initLoc(list, locCall, d.lode, OnUnknown) + var list = initLoc(locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, tmp, list, {}) # no need for deep copying if canRaise: raiseExit(p) @@ -158,10 +155,9 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} = result = true proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) = - var a, b, c: TLoc = default(TLoc) - initLocExpr(p, q[1], a) - initLocExpr(p, q[2], b) - initLocExpr(p, q[3], c) + var a = initLocExpr(p, q[1]) + var b = initLocExpr(p, q[2]) + var c = initLocExpr(p, q[3]) # but first produce the required index checks: if optBoundsCheck in p.options: genBoundsCheck(p, a, b, c) @@ -226,8 +222,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) = let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0]) result.add x & ", " & y else: - var a: TLoc = default(TLoc) - initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a) + var a: TLoc = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n) case skipTypes(a.t, abstractVar+{tyStatic}).kind of tyOpenArray, tyVarargs: if reifiedOpenArray(n): @@ -283,12 +278,11 @@ proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc = genAssignment(p, result, a, {}) proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} = - var a: TLoc = default(TLoc) - initLocExpr(p, n[0], a) + var a: TLoc = initLocExpr(p, n[0]) appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc]) proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) = - var a: TLoc = default(TLoc) + var a: TLoc if n.kind == nkStringToCString: genArgStringToCString(p, n, result, needsTmp) elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: @@ -296,14 +290,14 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need openArrayLoc(p, param.typ, n, result) elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and (optByRef notin param.options or not p.module.compileToCpp): - initLocExpr(p, n, a) + a = initLocExpr(p, n) if n.kind in {nkCharLit..nkNilLit}: addAddrLoc(p.config, literalsNeedsTmp(p, a), result) else: addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result) elif p.module.compileToCpp and param.typ.kind in {tyVar} and n.kind == nkHiddenAddr: - initLocExprSingleUse(p, n[0], a) + a = initLocExprSingleUse(p, n[0]) # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still # means '*T'. See posix.nim for lots of examples that do that in the wild. let callee = call[0] @@ -314,16 +308,16 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need else: addRdLoc(a, result) else: - initLocExprSingleUse(p, n, a) + a = initLocExprSingleUse(p, n) addRdLoc(withTmpIfNeeded(p, a, needsTmp), result) #assert result != nil proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) = - var a: TLoc = default(TLoc) + var a: TLoc if n.kind == nkStringToCString: genArgStringToCString(p, n, result, needsTmp) else: - initLocExprSingleUse(p, n, a) + a = initLocExprSingleUse(p, n) addRdLoc(withTmpIfNeeded(p, a, needsTmp), result) import aliasanalysis @@ -423,9 +417,8 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) = res = res & "_actual".rope proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = - var op: TLoc = default(TLoc) # this is a hotspot in the compiler - initLocExpr(p, ri[0], op) + var op: TLoc = initLocExpr(p, ri[0]) # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInstOwned) assert(typ.kind == tyProc) @@ -447,8 +440,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)" const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists - var op: TLoc = default(TLoc) - initLocExpr(p, ri[0], op) + var op: TLoc = initLocExpr(p, ri[0]) # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInstOwned) @@ -490,8 +482,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = elif isHarmlessStore(p, canRaise, d): if d.k == locNone: getTemp(p, typ[0], d) assert(d.t != nil) # generate an assignment to d: - var list: TLoc = default(TLoc) - initLoc(list, locCall, d.lode, OnUnknown) + var list: TLoc = initLoc(locCall, d.lode, OnUnknown) if tfIterator in typ.flags: list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc] else: @@ -502,8 +493,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = var tmp: TLoc getTemp(p, typ[0], tmp) assert(d.t != nil) # generate an assignment to d: - var list: TLoc = default(TLoc) - initLoc(list, locCall, d.lode, OnUnknown) + var list: TLoc = initLoc(locCall, d.lode, OnUnknown) if tfIterator in typ.flags: list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc] else: @@ -685,8 +675,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro result.add(substr(pat, start, i - 1)) proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = - var op: TLoc = default(TLoc) - initLocExpr(p, ri[0], op) + var op: TLoc = initLocExpr(p, ri[0]) # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInst) assert(typ.kind == tyProc) @@ -710,8 +699,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = else: if d.k == locNone: getTemp(p, typ[0], d) assert(d.t != nil) # generate an assignment to d: - var list: TLoc - initLoc(list, locCall, d.lode, OnUnknown) + var list: TLoc = initLoc(locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying else: @@ -731,8 +719,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = # generates a crappy ObjC call - var op: TLoc = default(TLoc) - initLocExpr(p, ri[0], op) + var op: TLoc = initLocExpr(p, ri[0]) var pl = "[" # getUniqueType() is too expensive here: var typ = skipTypes(ri[0].typ, abstractInst) @@ -790,8 +777,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = pl.add("]") if d.k == locNone: getTemp(p, typ[0], d) assert(d.t != nil) # generate an assignment to d: - var list: TLoc = default(TLoc) - initLoc(list, locCall, ri, OnUnknown) + var list: TLoc = initLoc(locCall, ri, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying else: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 46a353dce0..e46a0470df 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -479,10 +479,9 @@ proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) = d = s # ``d`` is free, so fill it with ``s`` proc putDataIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope) = - var a: TLoc = default(TLoc) if d.k != locNone: + var a: TLoc = initLoc(locData, n, OnStatic) # need to generate an assignment here - initLoc(a, locData, n, OnStatic) a.r = r if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {}) else: genAssignment(p, d, a, {needToCopy}) @@ -494,10 +493,9 @@ proc putDataIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope) = d.r = r proc putIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope; s=OnUnknown) = - var a: TLoc = default(TLoc) if d.k != locNone: # need to generate an assignment here - initLoc(a, locExpr, n, s) + var a: TLoc = initLoc(locExpr, n, s) a.r = r if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {}) else: genAssignment(p, d, a, {needToCopy}) @@ -509,49 +507,42 @@ proc putIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope; s=OnUnknown) = d.r = r proc binaryStmt(p: BProc, e: PNode, d: var TLoc, op: string) = - var a, b: TLoc = default(TLoc) if d.k != locNone: internalError(p.config, e.info, "binaryStmt") - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) lineCg(p, cpsStmts, "$1 $2 $3;$n", [rdLoc(a), op, rdLoc(b)]) proc binaryStmtAddr(p: BProc, e: PNode, d: var TLoc, cpname: string) = - var a, b: TLoc = default(TLoc) if d.k != locNone: internalError(p.config, e.info, "binaryStmtAddr") - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) lineCg(p, cpsStmts, "#$1($2, $3);$n", [cpname, byRefLoc(p, a), rdLoc(b)]) template unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = - var a: TLoc = default(TLoc) if d.k != locNone: internalError(p.config, e.info, "unaryStmt") - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) lineCg(p, cpsStmts, frmt, [rdLoc(a)]) template binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) = - var a, b: TLoc = default(TLoc) assert(e[1].typ != nil) assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) putIntoDest(p, d, e, ropecg(p.module, frmt, [rdLoc(a), rdLoc(b)])) template binaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) = - var a, b: TLoc = default(TLoc) assert(e[1].typ != nil) assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) putIntoDest(p, d, e, ropecg(p.module, frmt, [a.rdCharLoc, b.rdCharLoc])) template unaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) = - var a: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) putIntoDest(p, d, e, ropecg(p.module, frmt, [rdLoc(a)])) template unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) = - var a: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) putIntoDest(p, d, e, ropecg(p.module, frmt, [rdCharLoc(a)])) template binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc; @@ -591,11 +582,10 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = "nimAddInt64", "nimSubInt64" ] opr: array[mAddI..mPred, string] = ["+", "-", "*", "/", "%", "+", "-"] - var a, b: TLoc = default(TLoc) assert(e[1].typ != nil) assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) # skipping 'range' is correct here as we'll generate a proper range check # later via 'chckRange' let t = e.typ.skipTypes(abstractRange) @@ -625,11 +615,9 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = putIntoDest(p, d, e, res) proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = - var - a: TLoc = default(TLoc) - t: PType + var t: PType assert(e[1].typ != nil) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) t = skipTypes(e.typ, abstractRange) if optOverflowCheck in p.options: var first = newRopeAppender() @@ -651,12 +639,11 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = var - a, b: TLoc = default(TLoc) s, k: BiggestInt = 0 assert(e[1].typ != nil) assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) # BUGFIX: cannot use result-type here, as it may be a boolean s = max(getSize(p.config, a.t), getSize(p.config, b.t)) * 8 k = getSize(p.config, a.t) * 8 @@ -710,11 +697,10 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = assert(false, $op) proc genEqProc(p: BProc, e: PNode, d: var TLoc) = - var a, b: TLoc = default(TLoc) assert(e[1].typ != nil) assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) if a.t.skipTypes(abstractInstOwned).callConv == ccClosure: putIntoDest(p, d, e, "($1.ClP_0 == $2.ClP_0 && $1.ClE_0 == $2.ClE_0)" % [rdLoc(a), rdLoc(b)]) @@ -730,10 +716,9 @@ proc genIsNil(p: BProc, e: PNode, d: var TLoc) = proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = var - a: TLoc = default(TLoc) t: PType assert(e[1].typ != nil) - initLocExpr(p, e[1], a) + var a = initLocExpr(p, e[1]) t = skipTypes(e.typ, abstractRange) template applyFormat(frmt: untyped) = @@ -767,16 +752,16 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = if e[0].typ.skipTypes(abstractInstOwned).kind == tyRef: d.storage = OnHeap else: - var a: TLoc = default(TLoc) + var a: TLoc var typ = e[0].typ if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass: typ = typ.lastSon typ = typ.skipTypes(abstractInstOwned) if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr: - initLocExprSingleUse(p, e[0][0], d) + d = initLocExprSingleUse(p, e[0][0]) return else: - initLocExprSingleUse(p, e[0], a) + a = initLocExprSingleUse(p, e[0]) if d.k == locNone: # dest = *a; <-- We do not know that 'dest' is on the heap! # It is completely wrong to set 'd.storage' here, unless it's not yet @@ -813,8 +798,7 @@ proc cowBracket(p: BProc; n: PNode) = if n.kind == nkBracketExpr and optSeqDestructors in p.config.globalOptions: let strCandidate = n[0] if strCandidate.typ.skipTypes(abstractInst).kind == tyString: - var a: TLoc = default(TLoc) - initLocExpr(p, strCandidate, a) + var a: TLoc = initLocExpr(p, strCandidate) linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)]) proc cow(p: BProc; n: PNode) {.inline.} = @@ -823,31 +807,28 @@ proc cow(p: BProc; n: PNode) {.inline.} = proc genAddr(p: BProc, e: PNode, d: var TLoc) = # careful 'addr(myptrToArray)' needs to get the ampersand: if e[0].typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr}: - var a: TLoc = default(TLoc) - initLocExpr(p, e[0], a) + var a: TLoc = initLocExpr(p, e[0]) putIntoDest(p, d, e, "&" & a.r, a.storage) #Message(e.info, warnUser, "HERE NEW &") elif mapType(p.config, e[0].typ, mapTypeChooser(e[0]) == skParam) == ctArray or isCppRef(p, e.typ): expr(p, e[0], d) else: - var a: TLoc = default(TLoc) - initLocExpr(p, e[0], a) + var a: TLoc = initLocExpr(p, e[0]) putIntoDest(p, d, e, addrLoc(p.config, a), a.storage) template inheritLocation(d: var TLoc, a: TLoc) = if d.k == locNone: d.storage = a.storage -proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc) = - initLocExpr(p, e[0], a) +proc genRecordFieldAux(p: BProc, e: PNode, d: var TLoc, a: var TLoc) = + a = initLocExpr(p, e[0]) if e[1].kind != nkSym: internalError(p.config, e.info, "genRecordFieldAux") d.inheritLocation(a) discard getTypeDesc(p.module, a.t) # fill the record's fields.loc proc genTupleElem(p: BProc, e: PNode, d: var TLoc) = var - a: TLoc = default(TLoc) i: int = 0 - initLocExpr(p, e[0], a) + var a: TLoc = initLocExpr(p, e[0]) let tupType = a.t.skipTypes(abstractInst+{tyVar}) assert tupType.kind == tyTuple d.inheritLocation(a) @@ -900,7 +881,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) = proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) = - var test, u, v: TLoc = default(TLoc) + var test, u, v: TLoc for i in 1.. 0: args.add(", ") case detectStrVersion(p.module) @@ -1238,8 +1213,7 @@ proc genEcho(p: BProc, n: PNode) = if n.len == 0: linefmt(p, cpsStmts, "#echoBinSafe(NIM_NIL, $1);$n", [n.len]) else: - var a: TLoc = default(TLoc) - initLocExpr(p, n, a) + var a: TLoc = initLocExpr(p, n) linefmt(p, cpsStmts, "#echoBinSafe($1, $2);$n", [a.rdLoc, n.len]) when false: p.module.includeHeader("") @@ -1273,7 +1247,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = # appendChar(tmp0, 'z'); # asgn(s, tmp0); # } - var a = default(TLoc) + var a: TLoc var tmp: TLoc getTemp(p, e.typ, tmp) var L = 0 @@ -1281,7 +1255,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = var lens: Rope = "" for i in 0.. # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq->data[seq->len-1] = x; - var a, b, dest, tmpL, call: TLoc = default(TLoc) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var tmpL: TLoc = default(TLoc) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) let seqType = skipTypes(e[1].typ, {tyVar}) - initLoc(call, locCall, e, OnHeap) + var call = initLoc(locCall, e, OnHeap) if not p.module.compileToCpp: const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)" call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), @@ -1367,7 +1341,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = genRefAssign(p, a, call) #if bt != b.t: # echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t) - initLoc(dest, locExpr, e[2], OnHeap) + var dest = initLoc(locExpr, e[2], OnHeap) getIntTemp(p, tmpL) lineCg(p, cpsStmts, "$1 = $2->$3++;$n", [tmpL.r, rdLoc(a), lenField(p)]) dest.r = ropecg(p.module, "$1$3[$2]", [rdLoc(a), tmpL.r, dataField(p)]) @@ -1375,8 +1349,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = gcUsage(p.config, e) proc genReset(p: BProc, n: PNode) = - var a: TLoc = default(TLoc) - initLocExpr(p, n[1], a) + var a: TLoc = initLocExpr(p, n[1]) specializeReset(p, a) when false: linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", @@ -1390,8 +1363,7 @@ proc genDefault(p: BProc; n: PNode; d: var TLoc) = proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = var sizeExpr = sizeExpr let typ = a.t - var b: TLoc = default(TLoc) - initLoc(b, locExpr, a.lode, OnHeap) + var b: TLoc = initLoc(locExpr, a.lode, OnHeap) let refType = typ.skipTypes(abstractInstOwned) assert refType.kind == tyRef let bt = refType.lastSon @@ -1417,8 +1389,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = localError(p.module.config, a.lode.info, "the destructor that is turned into a finalizer needs " & "to have the 'nimcall' calling convention") - var f: TLoc = default(TLoc) - initLocExpr(p, newSymNode(op), f) + var f: TLoc = initLocExpr(p, newSymNode(op)) p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) if a.storage == OnHeap and usesWriteBarrier(p.config): @@ -1443,12 +1414,10 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = genObjectInit(p, cpsStmts, bt, a, constructRefObj) proc genNew(p: BProc, e: PNode) = - var a: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) # 'genNew' also handles 'unsafeNew': if e.len == 3: - var se: TLoc = default(TLoc) - initLocExpr(p, e[2], se) + var se: TLoc = initLocExpr(p, e[2]) rawGenNew(p, a, se.rdLoc, needsInit = true) else: rawGenNew(p, a, "", needsInit = true) @@ -1456,8 +1425,7 @@ proc genNew(p: BProc, e: PNode) = proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = let seqtype = skipTypes(dest.t, abstractVarRange) - var call: TLoc = default(TLoc) - initLoc(call, locExpr, dest.lode, OnHeap) + var call: TLoc = initLoc(locExpr, dest.lode, OnHeap) if dest.storage == OnHeap and usesWriteBarrier(p.config): if canFormAcycle(p.module.g.graph, dest.t): linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", [dest.rdLoc]) @@ -1482,9 +1450,8 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = genAssignment(p, dest, call, {}) proc genNewSeq(p: BProc, e: PNode) = - var a, b: TLoc = default(TLoc) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) if optSeqDestructors in p.config.globalOptions: let seqtype = skipTypes(e[1].typ, abstractVarRange) linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", @@ -1498,8 +1465,7 @@ proc genNewSeq(p: BProc, e: PNode) = proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = let seqtype = skipTypes(e.typ, abstractVarRange) - var a: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) if optSeqDestructors in p.config.globalOptions: if d.k == locNone: getTemp(p, e.typ, d, needsInit=false) linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", @@ -1602,7 +1568,7 @@ proc lhsDoesAlias(a, b: PNode): bool = if isPartOf(a, y) != arNo: return true proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = - var arr = default(TLoc) + var arr: TLoc var tmp: TLoc = default(TLoc) # bug #668 let doesAlias = lhsDoesAlias(d.lode, n) @@ -1623,7 +1589,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = # generate call to newSeq before adding the elements per hand: genNewSeqAux(p, dest[], lit, n.len == 0) for i in 0..finalizer = (void*)$2;$n", [ti, rdLoc(f)]) b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [ @@ -1718,8 +1684,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo; result: var Ro appcg(p.module, result, "#isObjWithCache($#.m_type, $#, $#)", [a, ti, cache]) proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = - var a: TLoc = default(TLoc) - initLocExpr(p, x, a) + var a: TLoc = initLocExpr(p, x) var dest = skipTypes(typ, typedescPtrs) var r = rdLoc(a) var nilCheck: Rope = "" @@ -1760,8 +1725,7 @@ proc genOf(p: BProc, n: PNode, d: var TLoc) = proc genRepr(p: BProc, e: PNode, d: var TLoc) = if optTinyRtti in p.config.globalOptions: localError(p.config, e.info, "'repr' is not available for --newruntime") - var a: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) var t = skipTypes(e[1].typ, abstractVarRange) case t.kind of tyInt..tyInt64, tyUInt..tyUInt64: @@ -1841,8 +1805,7 @@ proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) = # ordinary static type information putIntoDest(p, d, e, genTypeInfoV2(p.module, t, e.info)) else: - var a: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) var nilCheck = "" # use the dynamic type stored at offset 0: var rt = newRopeAppender() @@ -1850,8 +1813,7 @@ proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, d, e, rt) proc genAccessTypeField(p: BProc; e: PNode; d: var TLoc) = - var a: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) var nilCheck = "" # use the dynamic type stored at offset 0: var rt = newRopeAppender() @@ -1859,8 +1821,7 @@ proc genAccessTypeField(p: BProc; e: PNode; d: var TLoc) = putIntoDest(p, d, e, rt) template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) = - var a: TLoc = default(TLoc) - initLocExpr(p, n[1], a) + var a: TLoc = initLocExpr(p, n[1]) a.r = ropecg(p.module, frmt, [rdLoc(a)]) a.flags.excl lfIndirect # this flag should not be propagated here (not just for HCR) if d.k == locNone: getTemp(p, n.typ, d) @@ -1876,11 +1837,9 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = # Bug #9279, len(toOpenArray()) has to work: if a.kind in nkCallKinds and a[0].kind == nkSym and a[0].sym.magic == mSlice: # magic: pass slice to openArray: - var m: TLoc = default(TLoc) - var b, c: TLoc = default(TLoc) - initLocExpr(p, a[1], m) - initLocExpr(p, a[2], b) - initLocExpr(p, a[3], c) + var m = initLocExpr(p, a[1]) + var b = initLocExpr(p, a[2]) + var c = initLocExpr(p, a[3]) if optBoundsCheck in p.options: genBoundsCheck(p, m, b, c) if op == mHigh: @@ -1907,15 +1866,14 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)") else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)") of tyString: - var a: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) var x = lenExpr(p, a) if op == mHigh: x = "($1-1)" % [x] putIntoDest(p, d, e, x) of tySequence: # we go through a temporary here because people write bullshit code. - var a, tmp: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var tmp: TLoc = default(TLoc) + var a = initLocExpr(p, e[1]) getIntTemp(p, tmp) var x = lenExpr(p, a) if op == mHigh: x = "($1-1)" % [x] @@ -1939,15 +1897,14 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = e[1] = makeAddr(e[1], p.module.idgen) genCall(p, e, d) return - var a, b, call: TLoc = default(TLoc) assert(d.k == locNone) var x = e[1] if x.kind in {nkAddr, nkHiddenAddr}: x = x[0] - initLocExpr(p, x, a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, x) + var b = initLocExpr(p, e[2]) let t = skipTypes(e[1].typ, {tyVar}) - initLoc(call, locCall, e, OnHeap) + var call = initLoc(locCall, e, OnHeap) if not p.module.compileToCpp: const setLenPattern = "($3) #setLengthSeqV2(($1)?&($1)->Sup:NIM_NIL, $4, $2)" call.r = ropecg(p.module, setLenPattern, [ @@ -1967,12 +1924,11 @@ proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = if optSeqDestructors in p.config.globalOptions: binaryStmtAddr(p, e, d, "setLengthStrV2") else: - var a, b, call: TLoc = default(TLoc) if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr") - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) - initLoc(call, locCall, e, OnHeap) + var call = initLoc(locCall, e, OnHeap) call.r = ropecg(p.module, "#setLengthStr($1, $2)", [ rdLoc(a), rdLoc(b)]) genAssignment(p, a, call, {}) @@ -1985,11 +1941,10 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) = # b = temp cowBracket(p, e[1]) cowBracket(p, e[2]) - var a, b = default(TLoc) var tmp: TLoc getTemp(p, skipTypes(e[1].typ, abstractVar), tmp) - initLocExpr(p, e[1], a) # eval a - initLocExpr(p, e[2], b) # eval b + var a = initLocExpr(p, e[1]) # eval a + var b = initLocExpr(p, e[2]) # eval b genAssignment(p, tmp, a, {}) genAssignment(p, a, b, {}) genAssignment(p, b, tmp, {}) @@ -2031,16 +1986,15 @@ proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) = else: binaryExprIn(p, e, a, b, d, "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)") template binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) = - var a, b: TLoc = default(TLoc) assert(d.k == locNone) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) var elem = newRopeAppender() rdSetElemLoc(p.config, b, a.t, elem) lineF(p, cpsStmts, frmt, [rdLoc(a), elem]) proc genInOp(p: BProc, e: PNode, d: var TLoc) = - var a, b, x, y: TLoc = default(TLoc) + var a, b, x, y: TLoc if (e[1].kind == nkCurly) and fewCmps(p.config, e[1]): # a set constructor but not a constant set: # do not emit the set, but generate a bunch of comparisons; and if we do @@ -2050,19 +2004,19 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) = e[2][0] else: e[2] - initLocExpr(p, ea, a) - initLoc(b, locExpr, e, OnUnknown) + a = initLocExpr(p, ea) + b = initLoc(locExpr, e, OnUnknown) if e[1].len > 0: b.r = rope("(") for i in 0..= $2 && $1 <= $3", [rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)]) else: - initLocExpr(p, it, x) + x = initLocExpr(p, it) b.r.addf("$1 == $2", [rdCharLoc(a), rdCharLoc(x)]) if i < e[1].len - 1: b.r.add(" || ") b.r.add(")") @@ -2073,8 +2027,8 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) = else: assert(e[1].typ != nil) assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + a = initLocExpr(p, e[1]) + b = initLocExpr(p, e[2]) genInExprAux(p, e, a, b, d) proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = @@ -2090,7 +2044,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = "&", "|", "& ~"] - var a, b = default(TLoc) + var a, b: TLoc var i: TLoc var setType = skipTypes(e[1].typ, abstractVar) var size = int(getSize(p.config, setType)) @@ -2128,13 +2082,12 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mIncl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] |=(1U<<($2&7U));$n") of mExcl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] &= ~(1U<<($2&7U));$n") of mCard: - var a: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [addrLoc(p.config, a), size])) of mLtSet, mLeSet: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + a = initLocExpr(p, e[1]) + b = initLocExpr(p, e[2]) if d.k == locNone: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyBool), d) if op == mLtSet: linefmt(p, cpsStmts, lookupOpr[mLtSet], @@ -2143,17 +2096,16 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = linefmt(p, cpsStmts, lookupOpr[mLeSet], [rdLoc(i), size, rdLoc(d), rdLoc(a), rdLoc(b)]) of mEqSet: - var a, b: TLoc = default(TLoc) assert(e[1].typ != nil) assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) putIntoDest(p, d, e, ropecg(p.module, "(#nimCmpMem($1, $2, $3)==0)", [a.rdCharLoc, b.rdCharLoc, size])) of mMulSet, mPlusSet, mMinusSet: # we inline the simple for loop for better code generation: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + a = initLocExpr(p, e[1]) + b = initLocExpr(p, e[2]) if d.k == locNone: getTemp(p, setType, d) lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) $n" & @@ -2171,8 +2123,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = ValueTypes = {tyTuple, tyObject, tyArray, tyOpenArray, tyVarargs, tyUncheckedArray} # we use whatever C gives us. Except if we have a value-type, we need to go # through its address: - var a: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) let etyp = skipTypes(e.typ, abstractRange+{tyOwned}) let srcTyp = skipTypes(e[1].typ, abstractRange) if etyp.kind in ValueTypes and lfIndirect notin a.flags: @@ -2232,9 +2183,8 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) = genSomeCast(p, e, d) proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = - var a: TLoc = default(TLoc) + var a: TLoc = initLocExpr(p, n[0]) var dest = skipTypes(n.typ, abstractVar) - initLocExpr(p, n[0], a) if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and checkUnsignedConversions notin p.config.legacyFeatures): discard "no need to generate a check because it was disabled" @@ -2287,31 +2237,29 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) = genSomeCast(p, e, d) proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) = - var a: TLoc = default(TLoc) - initLocExpr(p, n[0], a) + var a: TLoc = initLocExpr(p, n[0]) putIntoDest(p, d, n, ropecg(p.module, "#nimToCStringConv($1)", [rdLoc(a)]), # "($1 ? $1->data : (NCSTRING)\"\")" % [a.rdLoc], a.storage) proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = - var a: TLoc = default(TLoc) - initLocExpr(p, n[0], a) + var a: TLoc = initLocExpr(p, n[0]) putIntoDest(p, d, n, ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]), a.storage) gcUsage(p.config, n) proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = - var x: TLoc = default(TLoc) + var x: TLoc var a = e[1] var b = e[2] if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "": - initLocExpr(p, e[2], x) + x = initLocExpr(p, e[2]) putIntoDest(p, d, e, ropecg(p.module, "($1 == 0)", [lenExpr(p, x)])) elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "": - initLocExpr(p, e[1], x) + x = initLocExpr(p, e[1]) putIntoDest(p, d, e, ropecg(p.module, "($1 == 0)", [lenExpr(p, x)])) else: @@ -2320,11 +2268,10 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) = if {optNaNCheck, optInfCheck} * p.options != {}: const opr: array[mAddF64..mDivF64, string] = ["+", "-", "*", "/"] - var a, b: TLoc = default(TLoc) assert(e[1].typ != nil) assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) putIntoDest(p, d, e, ropecg(p.module, "(($4)($2) $1 ($4)($3))", [opr[m], rdLoc(a), rdLoc(b), getSimpleTypeDesc(p.module, e[1].typ)])) @@ -2345,23 +2292,21 @@ proc skipAddr(n: PNode): PNode = result = if n.kind in {nkAddr, nkHiddenAddr}: n[0] else: n proc genWasMoved(p: BProc; n: PNode) = - var a: TLoc = default(TLoc) + var a: TLoc let n1 = n[1].skipAddr if p.withinBlockLeaveActions > 0 and notYetAlive(n1): discard else: - initLocExpr(p, n1, a, {lfEnforceDeref}) + a = initLocExpr(p, n1, {lfEnforceDeref}) resetLoc(p, a) #linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", # [addrLoc(p.config, a), getTypeDesc(p.module, a.t)]) proc genMove(p: BProc; n: PNode; d: var TLoc) = - var a: TLoc = default(TLoc) - initLocExpr(p, n[1].skipAddr, a) + var a: TLoc = initLocExpr(p, n[1].skipAddr) if n.len == 4: # generated by liftdestructors: - var src: TLoc = default(TLoc) - initLocExpr(p, n[2], src) + var src: TLoc = initLocExpr(p, n[2]) linefmt(p, cpsStmts, "if ($1.p != $2.p) {", [rdLoc(a), rdLoc(src)]) genStmts(p, n[3]) linefmt(p, cpsStmts, "}$n$1.len = $2.len; $1.p = $2.p;$n", [rdLoc(a), rdLoc(src)]) @@ -2387,8 +2332,7 @@ proc genDestroy(p: BProc; n: PNode) = let t = arg.typ.skipTypes(abstractInst) case t.kind of tyString: - var a: TLoc = default(TLoc) - initLocExpr(p, arg, a) + var a: TLoc = initLocExpr(p, arg) if optThreads in p.config.globalOptions: linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & " #deallocShared($1.p);$n" & @@ -2398,8 +2342,7 @@ proc genDestroy(p: BProc; n: PNode) = " #dealloc($1.p);$n" & "}$n", [rdLoc(a)]) of tySequence: - var a: TLoc = default(TLoc) - initLocExpr(p, arg, a) + var a: TLoc = initLocExpr(p, arg) linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & " #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" & "}$n", @@ -2416,8 +2359,7 @@ proc genDispose(p: BProc; n: PNode) = when false: let elemType = n[1].typ.skipTypes(abstractVar).lastSon - var a: TLoc = default(TLoc) - initLocExpr(p, n[1].skipAddr, a) + var a: TLoc = initLocExpr(p, n[1].skipAddr) if isFinal(elemType): if elemType.destructor != nil: @@ -2469,11 +2411,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}: binaryStmt(p, e, d, opr[op]) else: - var a, b: TLoc = default(TLoc) assert(e[1].typ != nil) assert(e[2].typ != nil) - initLocExpr(p, e[1], a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) let ranged = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyDistinct}) let res = binaryArithOverflowRaw(p, ranged, a, b, @@ -2487,10 +2428,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if optSeqDestructors in p.config.globalOptions: binaryStmtAddr(p, e, d, "nimAddCharV1") else: - var dest, b, call: TLoc = default(TLoc) - initLoc(call, locCall, e, OnHeap) - initLocExpr(p, e[1], dest) - initLocExpr(p, e[2], b) + var call = initLoc(locCall, e, OnHeap) + var dest = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)]) genAssignment(p, dest, call, {}) of mAppendStrStr: genStrAppend(p, e, d) @@ -2525,8 +2465,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mNew: genNew(p, e) of mNewFinalize: if optTinyRtti in p.config.globalOptions: - var a: TLoc = default(TLoc) - initLocExpr(p, e[1], a) + var a: TLoc = initLocExpr(p, e[1]) rawGenNew(p, a, "", needsInit = true) gcUsage(p.config, e) else: @@ -2620,10 +2559,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = localError(p.config, e.info, "for --mm:arc|atomicArc|orc 'deepcopy' support has to be enabled with --deepcopy:on") - var a, b: TLoc = default(TLoc) let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1] - initLocExpr(p, x, a) - initLocExpr(p, e[2], b) + var a = initLocExpr(p, x) + var b = initLocExpr(p, e[2]) genDeepCopy(p, a, b) of mDotDot, mEqCString: genCall(p, e, d) of mWasMoved: genWasMoved(p, e) @@ -2646,7 +2584,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = # nimZeroMem(tmp, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c); # incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g); var - a, b = default(TLoc) + a, b: TLoc var idx: TLoc if nfAllConst in e.flags: var elem = newRopeAppender() @@ -2661,8 +2599,8 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = for it in e.sons: if it.kind == nkRange: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), idx) # our counter - initLocExpr(p, it[0], a) - initLocExpr(p, it[1], b) + a = initLocExpr(p, it[0]) + b = initLocExpr(p, it[1]) var aa = newRopeAppender() rdSetElemLoc(p.config, a, e.typ, aa) var bb = newRopeAppender() @@ -2671,7 +2609,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = "$2[(NU)($1)>>3] |=(1U<<((NU)($1)&7U));$n", [rdLoc(idx), rdLoc(d), aa, bb]) else: - initLocExpr(p, it, a) + a = initLocExpr(p, it) var aa = newRopeAppender() rdSetElemLoc(p.config, a, e.typ, aa) lineF(p, cpsStmts, "$1[(NU)($2)>>3] |=(1U<<((NU)($2)&7U));$n", @@ -2683,8 +2621,8 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = for it in e.sons: if it.kind == nkRange: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), idx) # our counter - initLocExpr(p, it[0], a) - initLocExpr(p, it[1], b) + a = initLocExpr(p, it[0]) + b = initLocExpr(p, it[1]) var aa = newRopeAppender() rdSetElemLoc(p.config, a, e.typ, aa) var bb = newRopeAppender() @@ -2694,7 +2632,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = "$2 |=(($5)(1)<<(($1)%(sizeof($5)*8)));$n", [ rdLoc(idx), rdLoc(d), aa, bb, rope(ts)]) else: - initLocExpr(p, it, a) + a = initLocExpr(p, it) var aa = newRopeAppender() rdSetElemLoc(p.config, a, e.typ, aa) lineF(p, cpsStmts, @@ -2702,7 +2640,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = [rdLoc(d), aa, rope(ts)]) proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = - var rec: TLoc = default(TLoc) + var rec: TLoc if not handleConstExpr(p, n, d): let t = n.typ discard getTypeDesc(p.module, t) # so that any fields are initialized @@ -2719,7 +2657,7 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = for i in 0..Sup" else: ".Sup") for i in 2..abs(inheritanceDiff(dest, src)): r.add(".Sup") putIntoDest(p, d, n, if isRef: "&" & r else: r, a.storage) @@ -3156,8 +3090,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = let ex = n[0] if ex.kind != nkEmpty: genLineDir(p, n) - var a: TLoc = default(TLoc) - initLocExprSingleUse(p, ex, a) + var a: TLoc = initLocExprSingleUse(p, ex) line(p, cpsStmts, "(void)(" & a.r & ");\L") of nkAsmStmt: genAsmStmt(p, n) of nkTryStmt, nkHiddenTryStmt: @@ -3478,12 +3411,10 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; resul if n[0].kind == nkNilLit: result.add "{NIM_NIL,NIM_NIL}" else: - var d: TLoc = default(TLoc) - initLocExpr(p, n[0], d) + var d: TLoc = initLocExpr(p, n[0]) result.add "{(($1) $2),NIM_NIL}" % [getClosureType(p.module, typ, clHalfWithEnv), rdLoc(d)] else: - var d: TLoc = default(TLoc) - initLocExpr(p, n, d) + var d: TLoc = initLocExpr(p, n) result.add rdLoc(d) of tyArray, tyVarargs: genConstSimpleList(p, n, isConst, result) @@ -3511,10 +3442,8 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; resul if optSeqDestructors in p.config.globalOptions and n.kind != nkNilLit and ty == tyString: genStringLiteralV2Const(p.module, n, isConst, result) else: - var d: TLoc = default(TLoc) - initLocExpr(p, n, d) + var d: TLoc = initLocExpr(p, n) result.add rdLoc(d) else: - var d: TLoc = default(TLoc) - initLocExpr(p, n, d) + var d: TLoc = initLocExpr(p, n) result.add rdLoc(d) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 1751321f3f..b79eaf346e 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -72,7 +72,6 @@ template startBlock(p: BProc, start: FormatStr = "{$n", proc endBlock(p: BProc) proc genVarTuple(p: BProc, n: PNode) = - var tup, field: TLoc = default(TLoc) if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple") # if we have a something that's been captured, use the lowering instead: @@ -96,7 +95,7 @@ proc genVarTuple(p: BProc, n: PNode) = startBlock(p) genLineDir(p, n) - initLocExpr(p, n[^1], tup) + var tup = initLocExpr(p, n[^1]) var t = tup.t.skipTypes(abstractInst) for i in 0.. 0: genIfForCaseUntil(p, n, d, rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n", eqFormat = "if ($1 == $2) goto $3;$n", @@ -1495,8 +1484,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = of nkSym: var sym = it.sym if sym.kind in {skProc, skFunc, skIterator, skMethod}: - var a: TLoc = default(TLoc) - initLocExpr(p, it, a) + var a: TLoc = initLocExpr(p, it) res.add($rdLoc(a)) elif sym.kind == skType: res.add($getTypeDesc(p.module, sym.typ)) @@ -1508,8 +1496,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) = res.add($getTypeDesc(p.module, it.typ)) else: discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs)) - var a: TLoc = default(TLoc) - initLocExpr(p, it, a) + var a: TLoc = initLocExpr(p, it) res.add($a.rdLoc) if isAsmStmt and hasGnuAsm in CC[p.config.cCompiler].props: @@ -1611,11 +1598,10 @@ when false: expr(p, call, d) proc asgnFieldDiscriminant(p: BProc, e: PNode) = - var a = default(TLoc) var tmp: TLoc var dotExpr = e[0] if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0] - initLocExpr(p, e[0], a) + var a = initLocExpr(p, e[0]) getTemp(p, a.t, tmp) expr(p, e[1], tmp) if p.inUncheckedAssignSection == 0: @@ -1634,9 +1620,8 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = else: let le = e[0] let ri = e[1] - var a: TLoc = default(TLoc) + var a: TLoc = initLoc(locNone, le, OnUnknown) discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar) - initLoc(a, locNone, le, OnUnknown) a.flags.incl(lfEnforceDeref) a.flags.incl(lfPrepareForMutation) genLineDir(p, le) # it can be a nkBracketExpr, which may raise diff --git a/compiler/cgen.nim b/compiler/cgen.nim index af30f546ec..f2483e2de3 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -61,12 +61,10 @@ proc findPendingModule(m: BModule, s: PSym): BModule = var ms = getModule(s) result = m.g.modules[ms.position] -proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}) = - result.k = k - result.storage = s - result.lode = lode - result.r = "" - result.flags = flags +proc initLoc(k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}): TLoc = + result = TLoc(k: k, storage: s, lode: lode, + r: "", flags: flags + ) proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.inline.} = # fills the loc if it is not already initialized @@ -483,8 +481,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): if containsGcRef: - var nilLoc: TLoc - initLoc(nilLoc, locTemp, loc.lode, OnStack) + var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack) nilLoc.r = rope("NIM_NIL") genRefAssign(p, loc, nilLoc) else: @@ -514,8 +511,7 @@ proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)]) elif not isComplexValueType(typ): if containsGarbageCollectedRef(loc.t): - var nilLoc: TLoc - initLoc(nilLoc, locTemp, loc.lode, OnStack) + var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack) nilLoc.r = rope("NIM_NIL") genRefAssign(p, loc, nilLoc) else: @@ -731,12 +727,12 @@ proc genLiteral(p: BProc, n: PNode; result: var Rope) proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int) proc raiseExit(p: BProc) -proc initLocExpr(p: BProc, e: PNode, result: var TLoc, flags: TLocFlags = {}) = - initLoc(result, locNone, e, OnUnknown, flags) +proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc = + result = initLoc(locNone, e, OnUnknown, flags) expr(p, e, result) -proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) = - initLoc(result, locNone, e, OnUnknown) +proc initLocExprSingleUse(p: BProc, e: PNode): TLoc = + result = initLoc(locNone, e, OnUnknown) if e.kind in nkCallKinds and (e[0].kind != nkSym or e[0].sym.magic == mNone): # We cannot check for tfNoSideEffect here because of mutable parameters. discard "bug #8202; enforce evaluation order for nested calls for C++ too" @@ -827,8 +823,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) = var p = newProc(nil, m) p.options.excl optStackTrace p.flags.incl nimErrorFlagDisabled - var dest: TLoc - initLoc(dest, locTemp, lib.path, OnStack) + var dest: TLoc = initLoc(locTemp, lib.path, OnStack) dest.r = getTempName(m) appcg(m, m.s[cfsDynLibInit],"$1 $2;$n", [getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)]) @@ -863,11 +858,10 @@ proc symInDynamicLib(m: BModule, sym: PSym) = inc(m.labels, 2) if isCall: let n = lib.path - var a: TLoc = default(TLoc) - initLocExpr(m.initProc, n[0], a) + var a: TLoc = initLocExpr(m.initProc, n[0]) var params = rdLoc(a) & "(" for i in 1.. Date: Thu, 10 Aug 2023 16:26:23 +0800 Subject: [PATCH 420/489] fix #19304 Borrowing std/times.format causes Error: illformed AST (#20659) * fix #19304 Borrowing std/times.format causes Error: illformed AST * follow suggestions * mitigate for #4121 * improve error message --- compiler/semcall.nim | 44 +++++++++++++++++++++---------- compiler/semdata.nim | 2 ++ compiler/semstmts.nim | 33 ++++++++++++++--------- tests/distinct/tinvalidborrow.nim | 23 +++++++++++++--- tests/stdlib/t19304.nim | 7 +++++ 5 files changed, 80 insertions(+), 29 deletions(-) create mode 100644 tests/stdlib/t19304.nim diff --git a/compiler/semcall.nim b/compiler/semcall.nim index e5f2e820b6..073c00c37e 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -771,18 +771,25 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = else: result = explicitGenericInstError(c, n) -proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym = +proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): tuple[s: PSym, state: TBorrowState] = # Searches for the fn in the symbol table. If the parameter lists are suitable # for borrowing the sym in the symbol table is returned, else nil. # New approach: generate fn(x, y, z) where x, y, z have the proper types # and use the overloading resolution mechanism: - result = nil + const desiredTypes = abstractVar + {tyCompositeTypeClass} - {tyTypeDesc, tyDistinct} + + template getType(isDistinct: bool; t: PType):untyped = + if isDistinct: t.baseOfDistinct(c.graph, c.idgen) else: t + + result = default(tuple[s: PSym, state: TBorrowState]) var call = newNodeI(nkCall, fn.info) var hasDistinct = false + var isDistinct: bool + var x: PType + var t: PType call.add(newIdentNode(fn.name, fn.info)) for i in 1.. 0: - s.typ.n[0] = b.typ.n[0] - s.typ.flags = b.typ.flags - else: - localError(c.config, n.info, errNoSymbolToBorrowFromFound) + var (b, state) = searchForBorrowProc(c, c.currentScope.parent, s) + case state + of bsMatch: + # store the alias: + n[bodyPos] = newSymNode(b) + # Carry over the original symbol magic, this is necessary in order to ensure + # the semantic pass is correct + s.magic = b.magic + if b.typ != nil and b.typ.len > 0: + s.typ.n[0] = b.typ.n[0] + s.typ.flags = b.typ.flags + of bsNoDistinct: + localError(c.config, n.info, "borrow proc without distinct type parameter is meaningless") + of bsReturnNotMatch: + localError(c.config, n.info, "borrow from proc return type mismatch: '$1'" % typeToString(b.typ[0])) + of bsGeneric: + localError(c.config, n.info, "borrow with generic parameter is not supported") + of bsNotSupported: + localError(c.config, n.info, "borrow from '$1' is not supported" % $b.name.s) + else: + localError(c.config, n.info, errNoSymbolToBorrowFromFound) proc swapResult(n: PNode, sRes: PSym, dNode: PNode) = ## Swap nodes that are (skResult) symbols to d(estination)Node. diff --git a/tests/distinct/tinvalidborrow.nim b/tests/distinct/tinvalidborrow.nim index 08148608d6..d4b19fa8de 100644 --- a/tests/distinct/tinvalidborrow.nim +++ b/tests/distinct/tinvalidborrow.nim @@ -2,12 +2,19 @@ discard """ cmd: "nim check --hints:off --warnings:off $file" action: "reject" nimout:''' -tinvalidborrow.nim(18, 3) Error: only a 'distinct' type can borrow `.` -tinvalidborrow.nim(19, 3) Error: only a 'distinct' type can borrow `.` -tinvalidborrow.nim(20, 1) Error: no symbol to borrow from found +tinvalidborrow.nim(25, 3) Error: only a 'distinct' type can borrow `.` +tinvalidborrow.nim(26, 3) Error: only a 'distinct' type can borrow `.` +tinvalidborrow.nim(27, 1) Error: borrow proc without distinct type parameter is meaningless +tinvalidborrow.nim(36, 1) Error: borrow with generic parameter is not supported +tinvalidborrow.nim(41, 1) Error: borrow from proc return type mismatch: 'T' +tinvalidborrow.nim(42, 1) Error: borrow from '[]=' is not supported ''' """ + + + + # bug #516 type @@ -23,3 +30,13 @@ var d, e: TAtom discard( $(d == e) ) + +# issue #4121 +type HeapQueue[T] = distinct seq[T] +proc len*[T](h: HeapQueue[T]): int {.borrow.} + +# issue #3564 +type vec4[T] = distinct array[4, float32] + +proc `[]`(v: vec4, i: int): float32 {.borrow.} +proc `[]=`(v: vec4, i: int, va: float32) {.borrow.} diff --git a/tests/stdlib/t19304.nim b/tests/stdlib/t19304.nim new file mode 100644 index 0000000000..5e8795ac56 --- /dev/null +++ b/tests/stdlib/t19304.nim @@ -0,0 +1,7 @@ +import times + +type DjangoDateTime* = distinct DateTime + +# proc toTime*(x: DjangoDateTime): Time {.borrow.} # <-- works +proc format*(x: DjangoDateTime, f: TimeFormat, + loc: DateTimeLocale = DefaultLocale): string {.borrow.} From 05f7c4f79db096581352cbe20666f82300d21580 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 10 Aug 2023 16:41:24 +0800 Subject: [PATCH 421/489] fixes a typo (#22437) --- changelogs/changelog_2_2_0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/changelog_2_2_0.md b/changelogs/changelog_2_2_0.md index 341f41045a..0a293d35fb 100644 --- a/changelogs/changelog_2_2_0.md +++ b/changelogs/changelog_2_2_0.md @@ -1,4 +1,4 @@ -# v2.2.1 - 2023-mm-dd +# v2.2.0 - 2023-mm-dd ## Changes affecting backward compatibility From 8625e712503bb36e29ed24a28d484fe7d5af05fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Thu, 10 Aug 2023 13:15:23 +0100 Subject: [PATCH 422/489] adds support for functor in member (#22433) * adds support for functor in member * improves functor test --- compiler/ccgtypes.nim | 7 ++++++- tests/cpp/tmember.nim | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 6bac84e956..0b8cca77e0 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1149,14 +1149,19 @@ proc isReloadable(m: BModule; prc: PSym): bool = proc isNonReloadable(m: BModule; prc: PSym): bool = return m.hcrOn and sfNonReloadable in prc.flags -proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride, isMemberVirtual: var bool; isCtor: bool) = +proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride, isMemberVirtual: var bool; isCtor: bool, isFunctor=false) = var afterParams: string = "" if scanf(val, "$*($*)$s$*", name, params, afterParams): + if name.strip() == "operator" and params == "": #isFunctor? + parseVFunctionDecl(afterParams, name, params, retType, superCall, isFnConst, isOverride, isMemberVirtual, isCtor, true) + return isFnConst = afterParams.find("const") > -1 isOverride = afterParams.find("override") > -1 isMemberVirtual = name.find("virtual ") > -1 if isMemberVirtual: name = name.replace("virtual ", "") + if isFunctor: + name = "operator ()" if isCtor: discard scanf(afterParams, ":$s$*", superCall) else: diff --git a/tests/cpp/tmember.nim b/tests/cpp/tmember.nim index 3f498c7224..07bd5e0ee3 100644 --- a/tests/cpp/tmember.nim +++ b/tests/cpp/tmember.nim @@ -7,6 +7,7 @@ false hello foo hello boo hello boo +FunctorSupport! destructing destructing ''' @@ -51,3 +52,13 @@ let booAsFoo = cast[FooPtr](newCpp[Boo]()) foo.salute() boo.salute() booAsFoo.salute() + +type + NimFunctor = object + discard +proc invoke(f: NimFunctor, n:int) {.member:"operator ()('2 #2)" .} = + echo "FunctorSupport!" + +{.experimental: "callOperator".} +proc `()`(f: NimFunctor, n:int) {.importcpp:"#(@)" .} +NimFunctor()(1) From 8523b543d6034d8545a4db256bff83b73c927033 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 10 Aug 2023 20:17:15 +0800 Subject: [PATCH 423/489] `getTemp` and friends now return `TLoc` as requested (#22440) getTemp and friends now return `TLoc` --- compiler/ccgcalls.nim | 37 +++++++++++------------- compiler/ccgexprs.nim | 66 +++++++++++++++++++------------------------ compiler/ccgreset.nim | 3 +- compiler/ccgstmts.nim | 17 ++++++----- compiler/ccgtrav.nim | 8 ++---- compiler/cgen.nim | 6 ++-- 6 files changed, 60 insertions(+), 77 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index b446e83607..80b534cee6 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -88,7 +88,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, # beware of 'result = p(result)'. We may need to allocate a temporary: if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri): # Great, we can use 'd': - if d.k == locNone: getTemp(p, typ[0], d, needsInit=true) + if d.k == locNone: d = getTemp(p, typ[0], needsInit=true) elif d.k notin {locTemp} and not hasNoInit(ri): # reset before pass as 'result' var: discard "resetLoc(p, d)" @@ -96,8 +96,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl.add(");\n") line(p, cpsStmts, pl) else: - var tmp: TLoc - getTemp(p, typ[0], tmp, needsInit=true) + var tmp: TLoc = getTemp(p, typ[0], needsInit=true) pl.add(addrLoc(p.config, tmp)) pl.add(");\n") line(p, cpsStmts, pl) @@ -115,24 +114,23 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, excl d.flags, lfSingleUse else: if d.k == locNone and p.splitDecls == 0: - getTempCpp(p, typ[0], d, pl) + d = getTempCpp(p, typ[0], pl) else: - if d.k == locNone: getTemp(p, typ[0], d) + if d.k == locNone: d = getTemp(p, typ[0]) var list = initLoc(locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying if canRaise: raiseExit(p) elif isHarmlessStore(p, canRaise, d): - if d.k == locNone: getTemp(p, typ[0], d) + if d.k == locNone: d = getTemp(p, typ[0]) assert(d.t != nil) # generate an assignment to d: var list = initLoc(locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, d, list, {}) # no need for deep copying if canRaise: raiseExit(p) else: - var tmp: TLoc - getTemp(p, typ[0], tmp, needsInit=true) + var tmp: TLoc = getTemp(p, typ[0], needsInit=true) var list = initLoc(locCall, d.lode, OnUnknown) list.r = pl genAssignment(p, tmp, list, {}) # no need for deep copying @@ -268,13 +266,13 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc = # Also don't regress for non ARC-builds, too risky. if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and getSize(p.config, a.lode.typ) < 1024: - getTemp(p, a.lode.typ, result, needsInit=false) + result = getTemp(p, a.lode.typ, needsInit=false) genAssignment(p, result, a, {}) else: result = a proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc = - getTemp(p, a.lode.typ, result, needsInit=false) + result = getTemp(p, a.lode.typ, needsInit=false) genAssignment(p, result, a, {}) proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} = @@ -465,7 +463,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri): # Great, we can use 'd': if d.k == locNone: - getTemp(p, typ[0], d, needsInit=true) + d = getTemp(p, typ[0], needsInit=true) elif d.k notin {locTemp} and not hasNoInit(ri): # reset before pass as 'result' var: discard "resetLoc(p, d)" @@ -473,14 +471,13 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = genCallPattern() if canRaise: raiseExit(p) else: - var tmp: TLoc - getTemp(p, typ[0], tmp, needsInit=true) + var tmp: TLoc = getTemp(p, typ[0], needsInit=true) pl.add(addrLoc(p.config, tmp)) genCallPattern() if canRaise: raiseExit(p) genAssignment(p, d, tmp, {}) # no need for deep copying elif isHarmlessStore(p, canRaise, d): - if d.k == locNone: getTemp(p, typ[0], d) + if d.k == locNone: d = getTemp(p, typ[0]) assert(d.t != nil) # generate an assignment to d: var list: TLoc = initLoc(locCall, d.lode, OnUnknown) if tfIterator in typ.flags: @@ -490,8 +487,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = genAssignment(p, d, list, {}) # no need for deep copying if canRaise: raiseExit(p) else: - var tmp: TLoc - getTemp(p, typ[0], tmp) + var tmp: TLoc = getTemp(p, typ[0]) assert(d.t != nil) # generate an assignment to d: var list: TLoc = initLoc(locCall, d.lode, OnUnknown) if tfIterator in typ.flags: @@ -697,7 +693,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = d.r = pl excl d.flags, lfSingleUse else: - if d.k == locNone: getTemp(p, typ[0], d) + if d.k == locNone: d = getTemp(p, typ[0]) assert(d.t != nil) # generate an assignment to d: var list: TLoc = initLoc(locCall, d.lode, OnUnknown) list.r = pl @@ -761,21 +757,20 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = # beware of 'result = p(result)'. We always allocate a temporary: if d.k in {locTemp, locNone}: # We already got a temp. Great, special case it: - if d.k == locNone: getTemp(p, typ[0], d, needsInit=true) + if d.k == locNone: d = getTemp(p, typ[0], needsInit=true) pl.add("Result: ") pl.add(addrLoc(p.config, d)) pl.add("];\n") line(p, cpsStmts, pl) else: - var tmp: TLoc - getTemp(p, typ[0], tmp, needsInit=true) + var tmp: TLoc = getTemp(p, typ[0], needsInit=true) pl.add(addrLoc(p.config, tmp)) pl.add("];\n") line(p, cpsStmts, pl) genAssignment(p, d, tmp, {}) # no need for deep copying else: pl.add("]") - if d.k == locNone: getTemp(p, typ[0], d) + if d.k == locNone: d = getTemp(p, typ[0]) assert(d.t != nil) # generate an assignment to d: var list: TLoc = initLoc(locCall, ri, OnUnknown) list.r = pl diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index e46a0470df..dd47d1d1f8 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -348,8 +348,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = linefmt(p, cpsStmts, "$1 = #copyString($2);$n", [dest.rdLoc, src.rdLoc]) elif dest.storage == OnHeap: # we use a temporary to care for the dreaded self assignment: - var tmp: TLoc - getTemp(p, ty, tmp) + var tmp: TLoc = getTemp(p, ty) linefmt(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);$n", [dest.rdLoc, src.rdLoc, tmp.rdLoc]) linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", [tmp.rdLoc]) @@ -431,8 +430,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genDeepCopy(p: BProc; dest, src: TLoc) = template addrLocOrTemp(a: TLoc): Rope = if a.k == locExpr: - var tmp: TLoc - getTemp(p, a.t, tmp) + var tmp: TLoc = getTemp(p, a.t) genAssignment(p, tmp, a, {}) addrLoc(p.config, tmp) else: @@ -1169,8 +1167,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = else: var L: TLabel - tmp: TLoc - getTemp(p, e.typ, tmp) # force it into a temp! + var tmp: TLoc = getTemp(p, e.typ) # force it into a temp! inc p.splitDecls expr(p, e[1], tmp) L = getLabel(p) @@ -1248,8 +1245,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = # asgn(s, tmp0); # } var a: TLoc - var tmp: TLoc - getTemp(p, e.typ, tmp) + var tmp: TLoc = getTemp(p, e.typ) var L = 0 var appends: Rope = "" var lens: Rope = "" @@ -1321,7 +1317,6 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq &= x --> # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq->data[seq->len-1] = x; - var tmpL: TLoc = default(TLoc) var a = initLocExpr(p, e[1]) var b = initLocExpr(p, e[2]) let seqType = skipTypes(e[1].typ, {tyVar}) @@ -1342,7 +1337,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = #if bt != b.t: # echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t) var dest = initLoc(locExpr, e[2], OnHeap) - getIntTemp(p, tmpL) + var tmpL = getIntTemp(p) lineCg(p, cpsStmts, "$1 = $2->$3++;$n", [tmpL.r, rdLoc(a), lenField(p)]) dest.r = ropecg(p.module, "$1$3[$2]", [rdLoc(a), tmpL.r, dataField(p)]) genAssignment(p, dest, b, {needToCopy}) @@ -1357,7 +1352,7 @@ proc genReset(p: BProc, n: PNode) = genTypeInfoV1(p.module, skipTypes(a.t, {tyVar}), n.info)]) proc genDefault(p: BProc; n: PNode; d: var TLoc) = - if d.k == locNone: getTemp(p, n.typ, d, needsInit=true) + if d.k == locNone: d = getTemp(p, n.typ, needsInit=true) else: resetLoc(p, d) proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = @@ -1467,7 +1462,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = let seqtype = skipTypes(e.typ, abstractVarRange) var a: TLoc = initLocExpr(p, e[1]) if optSeqDestructors in p.config.globalOptions: - if d.k == locNone: getTemp(p, e.typ, d, needsInit=false) + if d.k == locNone: d = getTemp(p, e.typ, needsInit=false) linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n", [d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon), getSeqPayloadType(p.module, seqtype), @@ -1520,10 +1515,10 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = (d.k notin {locTemp,locLocalVar,locGlobalVar,locParam,locField}) or (isPartOf(d.lode, e) != arNo) - var tmp: TLoc = TLoc() + var tmp: TLoc = default(TLoc) var r: Rope if useTemp: - getTemp(p, t, tmp) + tmp = getTemp(p, t) r = rdLoc(tmp) if isRef: rawGenNew(p, tmp, "", needsInit = nfAllFieldsSet notin e.flags) @@ -1574,9 +1569,9 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) = let doesAlias = lhsDoesAlias(d.lode, n) let dest = if doesAlias: addr(tmp) else: addr(d) if doesAlias: - getTemp(p, n.typ, tmp) + tmp = getTemp(p, n.typ) elif d.k == locNone: - getTemp(p, n.typ, d) + d = getTemp(p, n.typ) var lit = newRopeAppender() intLiteral(n.len, lit) @@ -1609,7 +1604,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = genSeqConstr(p, n[1], d) return if d.k == locNone: - getTemp(p, n.typ, d) + d = getTemp(p, n.typ) var a = initLocExpr(p, n[1]) # generate call to newSeq before adding the elements per hand: let L = toInt(lengthOrd(p.config, n[1].typ)) @@ -1634,8 +1629,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = arr.r = ropecg(p.module, "$1[$2]", [rdLoc(a), lit]) genAssignment(p, elem, arr, {needToCopy}) else: - var i: TLoc - getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) + var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", [i.r, L]) elem = initLoc(locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap) elem.r = ropecg(p.module, "$1$3[$2]", [rdLoc(d), rdLoc(i), dataField(p)]) @@ -1824,7 +1818,7 @@ template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) = var a: TLoc = initLocExpr(p, n[1]) a.r = ropecg(p.module, frmt, [rdLoc(a)]) a.flags.excl lfIndirect # this flag should not be propagated here (not just for HCR) - if d.k == locNone: getTemp(p, n.typ, d) + if d.k == locNone: d = getTemp(p, n.typ) genAssignment(p, d, a, {}) gcUsage(p.config, n) @@ -1872,9 +1866,8 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = putIntoDest(p, d, e, x) of tySequence: # we go through a temporary here because people write bullshit code. - var tmp: TLoc = default(TLoc) + var tmp: TLoc = getIntTemp(p) var a = initLocExpr(p, e[1]) - getIntTemp(p, tmp) var x = lenExpr(p, a) if op == mHigh: x = "($1-1)" % [x] lineCg(p, cpsStmts, "$1 = $2;$n", [tmp.r, x]) @@ -1941,8 +1934,7 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) = # b = temp cowBracket(p, e[1]) cowBracket(p, e[2]) - var tmp: TLoc - getTemp(p, skipTypes(e[1].typ, abstractVar), tmp) + var tmp: TLoc = getTemp(p, skipTypes(e[1].typ, abstractVar)) var a = initLocExpr(p, e[1]) # eval a var b = initLocExpr(p, e[2]) # eval b genAssignment(p, tmp, a, {}) @@ -2085,10 +2077,10 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = var a: TLoc = initLocExpr(p, e[1]) putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [addrLoc(p.config, a), size])) of mLtSet, mLeSet: - getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter + i = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter a = initLocExpr(p, e[1]) b = initLocExpr(p, e[2]) - if d.k == locNone: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyBool), d) + if d.k == locNone: d = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyBool)) if op == mLtSet: linefmt(p, cpsStmts, lookupOpr[mLtSet], [rdLoc(i), size, rdLoc(d), rdLoc(a), rdLoc(b)]) @@ -2103,10 +2095,10 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = putIntoDest(p, d, e, ropecg(p.module, "(#nimCmpMem($1, $2, $3)==0)", [a.rdCharLoc, b.rdCharLoc, size])) of mMulSet, mPlusSet, mMinusSet: # we inline the simple for loop for better code generation: - getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter + i = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter a = initLocExpr(p, e[1]) b = initLocExpr(p, e[2]) - if d.k == locNone: getTemp(p, setType, d) + if d.k == locNone: d = getTemp(p, setType) lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) $n" & " $3[$1] = $4[$1] $6 $5[$1];$n", [ @@ -2311,7 +2303,7 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) = genStmts(p, n[3]) linefmt(p, cpsStmts, "}$n$1.len = $2.len; $1.p = $2.p;$n", [rdLoc(a), rdLoc(src)]) else: - if d.k == locNone: getTemp(p, n.typ, d) + if d.k == locNone: d = getTemp(p, n.typ) if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}: genAssignment(p, d, a, {}) var op = getAttachedOp(p.module.g.graph, n.typ, attachedWasMoved) @@ -2376,7 +2368,7 @@ proc genSlice(p: BProc; e: PNode; d: var TLoc) = prepareForMutation = e[1].kind == nkHiddenDeref and e[1].typ.skipTypes(abstractInst).kind == tyString and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}) - if d.k == locNone: getTemp(p, e.typ, d) + if d.k == locNone: d = getTemp(p, e.typ) linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $3;$n", [rdLoc(d), x, y]) when false: localError(p.config, e.info, "invalid context for 'toOpenArray'; " & @@ -2591,14 +2583,14 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = genSetNode(p, e, elem) putIntoDest(p, d, e, elem) else: - if d.k == locNone: getTemp(p, e.typ, d) + if d.k == locNone: d = getTemp(p, e.typ) if getSize(p.config, e.typ) > 8: # big set: linefmt(p, cpsStmts, "#nimZeroMem($1, sizeof($2));$n", [rdLoc(d), getTypeDesc(p.module, e.typ)]) for it in e.sons: if it.kind == nkRange: - getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), idx) # our counter + idx = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter a = initLocExpr(p, it[0]) b = initLocExpr(p, it[1]) var aa = newRopeAppender() @@ -2620,7 +2612,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(d)]) for it in e.sons: if it.kind == nkRange: - getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), idx) # our counter + idx = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter a = initLocExpr(p, it[0]) b = initLocExpr(p, it[1]) var aa = newRopeAppender() @@ -2650,9 +2642,9 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = let doesAlias = lhsDoesAlias(d.lode, n) let dest = if doesAlias: addr(tmp) else: addr(d) if doesAlias: - getTemp(p, n.typ, tmp) + tmp = getTemp(p, n.typ) elif d.k == locNone: - getTemp(p, n.typ, d) + d = getTemp(p, n.typ) for i in 0..") if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) + d = getTemp(p, t.typ) genLineDir(p, t) inc(p.labels, 2) @@ -1187,7 +1187,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) = expr(p, body, d) if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) + d = getTemp(p, t.typ) genLineDir(p, t) cgsym(p.module, "popCurrentExceptionEx") let fin = if t[^1].kind == nkFinally: t[^1] else: nil @@ -1265,7 +1265,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) = p.flags.incl nimErrorFlagAccessed if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) + d = getTemp(p, t.typ) expr(p, t[0], d) @@ -1372,7 +1372,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) = # propagateCurrentException(); # if not isEmptyType(t.typ) and d.k == locNone: - getTemp(p, t.typ, d) + d = getTemp(p, t.typ) let quirkyExceptions = p.config.exc == excQuirky or (t.kind == nkHiddenTryStmt and sfSystemModule in p.module.module.flags) if not quirkyExceptions: @@ -1598,11 +1598,10 @@ when false: expr(p, call, d) proc asgnFieldDiscriminant(p: BProc, e: PNode) = - var tmp: TLoc var dotExpr = e[0] if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0] var a = initLocExpr(p, e[0]) - getTemp(p, a.t, tmp) + var tmp: TLoc = getTemp(p, a.t) expr(p, e[1], tmp) if p.inUncheckedAssignSection == 0: let field = dotExpr[1].sym diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 9af33d45e8..adad9df3e6 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -21,7 +21,7 @@ const proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) proc genCaseRange(p: BProc, branch: PNode) -proc getTemp(p: BProc, t: PType, result: out TLoc; needsInit=false) +proc getTemp(p: BProc, t: PType, needsInit=false): TLoc proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode; typ: PType) = @@ -74,8 +74,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = genTraverseProc(c, accessor, lastSon(typ)) of tyArray: let arraySize = lengthOrd(c.p.config, typ[0]) - var i: TLoc - getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i) + var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt)) var oldCode = p.s(cpsStmts) freeze oldCode linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", @@ -119,8 +118,7 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) = var p = c.p assert typ.kind == tySequence - var i: TLoc - getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt), i) + var i: TLoc = getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo, tyInt)) var oldCode = p.s(cpsStmts) freeze oldCode var a: TLoc = TLoc(r: accessor) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index f2483e2de3..de15e8ca4f 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -538,7 +538,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = if not immediateAsgn: constructLoc(p, v.loc) -proc getTemp(p: BProc, t: PType, result: out TLoc; needsInit=false) = +proc getTemp(p: BProc, t: PType, needsInit=false): TLoc = inc(p.labels) result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t, storage: OnStack, flags: {}) @@ -556,13 +556,13 @@ proc getTemp(p: BProc, t: PType, result: out TLoc; needsInit=false) = echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo writeStackTrace() -proc getTempCpp(p: BProc, t: PType, result: out TLoc; value: Rope) = +proc getTempCpp(p: BProc, t: PType, value: Rope): TLoc = inc(p.labels) result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t, storage: OnStack, flags: {}) linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value]) -proc getIntTemp(p: BProc, result: out TLoc) = +proc getIntTemp(p: BProc): TLoc = inc(p.labels) result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, storage: OnStack, lode: lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt), From 7be2e2bef545e68ac3d88876fe7073a033fbb5f4 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 10 Aug 2023 20:26:40 +0800 Subject: [PATCH 424/489] replaces `doAssert false` with `raiseAssert` for unreachable branches, which works better with strictdefs (#22436) replaces `doAssert false` with `raiseAssert`, which works better with strictdefs --- compiler/ast.nim | 2 +- compiler/ccgreset.nim | 2 +- compiler/ccgtypes.nim | 6 +++--- compiler/depends.nim | 3 +-- compiler/dfa.nim | 2 +- compiler/docgen.nim | 5 ++--- compiler/jsgen.nim | 3 +-- compiler/liftdestructors.nim | 2 +- compiler/main.nim | 6 +++--- compiler/nim.nim | 2 +- compiler/options.nim | 2 +- compiler/pipelines.nim | 8 +++----- compiler/ropes.nim | 8 ++++---- compiler/scriptconfig.nim | 2 +- compiler/sem.nim | 4 ++-- compiler/semfold.nim | 3 +-- compiler/tccgen.nim | 2 +- compiler/vmconv.nim | 4 ++-- compiler/vmgen.nim | 4 ++-- compiler/vmhooks.nim | 4 +--- compiler/vmops.nim | 2 +- 21 files changed, 34 insertions(+), 42 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index d62b563682..99647e2930 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1499,7 +1499,7 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode = result = newNode(nkIntLit) of tyStatic: # that's a pre-existing bug, will fix in another PR result = newNode(nkIntLit) - else: doAssert false, $kind + else: raiseAssert $kind result.intVal = intVal result.typ = typ diff --git a/compiler/ccgreset.nim b/compiler/ccgreset.nim index 0976a33561..bd0e2a58a3 100644 --- a/compiler/ccgreset.nim +++ b/compiler/ccgreset.nim @@ -94,7 +94,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) = of ctInt8, ctInt16, ctInt32, ctInt64: lineCg(p, cpsStmts, "$1 = 0;$n", [accessor]) else: - doAssert false, "unexpected set type kind" + raiseAssert "unexpected set type kind" of {tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation, tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs, tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 0b8cca77e0..c2c1d63180 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -477,11 +477,11 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr if i >= frmt.len or frmt[i] notin {'0'..'9'}: break num = j if j > high(arg) + 1: - doAssert false, "invalid format string: " & frmt + raiseAssert "invalid format string: " & frmt else: res.add(arg[j-1]) else: - doAssert false, "invalid format string: " & frmt + raiseAssert "invalid format string: " & frmt var start = i while i < frmt.len: if frmt[i] != c: inc(i) @@ -847,7 +847,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType = # Make sure the index refers to one of the generic params of the type. # XXX: we should catch this earlier and report it as a semantic error. if idx >= typ.len: - doAssert false, "invalid apostrophe type parameter index" + raiseAssert "invalid apostrophe type parameter index" result = typ[idx] for i in 1..stars: diff --git a/compiler/depends.nim b/compiler/depends.nim index cb462e1888..84e66f7806 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -42,8 +42,7 @@ proc toNimblePath(s: string, isStdlib: bool): string = let sub = "lib/" var start = s.find(sub) if start < 0: - result = "" - doAssert false + raiseAssert "unreachable" else: start += sub.len let base = s[start..^1] diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 7db4c79e31..1459bde457 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -470,7 +470,7 @@ proc gen(c: var Con; n: PNode) = of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, PathKinds1: gen(c, n[1]) of nkVarSection, nkLetSection: genVarSection(c, n) - of nkDefer: doAssert false, "dfa construction pass requires the elimination of 'defer'" + of nkDefer: raiseAssert "dfa construction pass requires the elimination of 'defer'" else: discard when false: diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 6a78d86932..933fe57f6f 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -348,7 +348,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, if conf.configVars.hasKey("doc.googleAnalytics") and conf.configVars.hasKey("doc.plausibleAnalytics"): - doAssert false, "Either use googleAnalytics or plausibleAnalytics" + raiseAssert "Either use googleAnalytics or plausibleAnalytics" if conf.configVars.hasKey("doc.googleAnalytics"): result.analytics = """ @@ -954,8 +954,7 @@ proc genDeprecationMsg(d: PDoc, n: PNode): string = else: result = "" else: - result = "" - doAssert false + raiseAssert "unreachable" type DocFlags = enum kDefault diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 8659d511bf..c566a718a8 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -218,8 +218,7 @@ proc mapType(typ: PType): TJSTypeKind = of tyProc: result = etyProc of tyCstring: result = etyString of tyConcept, tyIterable: - result = etyNone - doAssert false + raiseAssert "unreachable" proc mapType(p: PProc; typ: PType): TJSTypeKind = result = mapType(typ) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 760ee27b5d..6ae4173477 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -1024,7 +1024,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = of tyOrdinal, tyRange, tyInferred, tyGenericInst, tyAlias, tySink: fillBody(c, lastSon(t), body, x, y) - of tyConcept, tyIterable: doAssert false + of tyConcept, tyIterable: raiseAssert "unreachable" proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo; diff --git a/compiler/main.nim b/compiler/main.nim index 836f912bbc..7118a253c4 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -115,7 +115,7 @@ when not defined(leanCompiler): setPipeLinePass(graph, Docgen2JsonPass) of HtmlExt: setPipeLinePass(graph, Docgen2Pass) - else: doAssert false, $ext + else: raiseAssert $ext compilePipelineProject(graph) proc commandCompileToC(graph: ModuleGraph) = @@ -267,7 +267,7 @@ proc mainCommand*(graph: ModuleGraph) = # and it has added this define implictly, so we must undo that here. # A better solution might be to fix system.nim undefSymbol(conf.symbols, "useNimRtl") - of backendInvalid: doAssert false + of backendInvalid: raiseAssert "unreachable" proc compileToBackend() = customizeForBackend(conf.backend) @@ -277,7 +277,7 @@ proc mainCommand*(graph: ModuleGraph) = of backendCpp: commandCompileToC(graph) of backendObjc: commandCompileToC(graph) of backendJs: commandCompileToJS(graph) - of backendInvalid: doAssert false + of backendInvalid: raiseAssert "unreachable" template docLikeCmd(body) = when defined(leanCompiler): diff --git a/compiler/nim.nim b/compiler/nim.nim index d05f01c427..d0aa888c41 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -140,7 +140,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) = # tasyncjs_fail` would fail, refs https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode if cmdPrefix.len == 0: cmdPrefix = findNodeJs().quoteShell cmdPrefix.add " --unhandled-rejections=strict" - else: doAssert false, $conf.backend + else: raiseAssert $conf.backend if cmdPrefix.len > 0: cmdPrefix.add " " # without the `cmdPrefix.len > 0` check, on windows you'd get a cryptic: # `The parameter is incorrect` diff --git a/compiler/options.nim b/compiler/options.nim index d8ae29eac4..bda86a5989 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -663,7 +663,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = template quitOrRaise*(conf: ConfigRef, msg = "") = # xxx in future work, consider whether to also intercept `msgQuit` calls if conf.isDefined("nimDebug"): - doAssert false, msg + raiseAssert msg else: quit(msg) # quits with QuitFailure diff --git a/compiler/pipelines.nim b/compiler/pipelines.nim index 7bde76d5f4..8517cd9426 100644 --- a/compiler/pipelines.nim +++ b/compiler/pipelines.nim @@ -44,8 +44,7 @@ proc processPipeline(graph: ModuleGraph; semNode: PNode; bModule: PPassContext): of EvalPass, InterpreterPass: result = interpreterCode(bModule, semNode) of NonePass: - result = nil - doAssert false, "use setPipeLinePass to set a proper PipelinePass" + raiseAssert "use setPipeLinePass to set a proper PipelinePass" proc processImplicitImports(graph: ModuleGraph; implicits: seq[string], nodeKind: TNodeKind, m: PSym, ctx: PContext, bModule: PPassContext, idgen: IdGenerator, @@ -133,8 +132,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator of SemPass: nil of NonePass: - doAssert false, "use setPipeLinePass to set a proper PipelinePass" - nil + raiseAssert "use setPipeLinePass to set a proper PipelinePass" if stream == nil: let filename = toFullPathConsiderDirty(graph.config, fileIdx) @@ -208,7 +206,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator when not defined(leanCompiler): discard closeJson(graph, bModule, finalNode) of NonePass: - doAssert false, "use setPipeLinePass to set a proper PipelinePass" + raiseAssert "use setPipeLinePass to set a proper PipelinePass" if graph.config.backend notin {backendC, backendCpp, backendObjc}: # We only write rod files here if no C-like backend is active. diff --git a/compiler/ropes.nim b/compiler/ropes.nim index 7fec1a30ad..e0d5aa0d37 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -76,7 +76,7 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope = if i >= frmt.len or frmt[i] notin {'0'..'9'}: break num = j if j > high(args) + 1: - doAssert false, "invalid format string: " & frmt + raiseAssert "invalid format string: " & frmt else: result.add(args[j-1]) of '{': @@ -88,10 +88,10 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope = num = j if frmt[i] == '}': inc(i) else: - doAssert false, "invalid format string: " & frmt + raiseAssert "invalid format string: " & frmt if j > high(args) + 1: - doAssert false, "invalid format string: " & frmt + raiseAssert "invalid format string: " & frmt else: result.add(args[j-1]) of 'n': @@ -101,7 +101,7 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope = result.add("\n") inc(i) else: - doAssert false, "invalid format string: " & frmt + raiseAssert "invalid format string: " & frmt else: result.add(frmt[i]) inc(i) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 46751fe4ef..1a686fd20f 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -240,7 +240,7 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile; of gcAtomicArc: defineSymbol(conf.symbols, "gcatomicarc") else: - doAssert false, "unreachable" + raiseAssert "unreachable" # ensure we load 'system.nim' again for the real non-config stuff! resetSystemArtifacts(graph) diff --git a/compiler/sem.nim b/compiler/sem.nim index 73422618d3..42e6313581 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -594,7 +594,7 @@ proc defaultFieldsForTuple(c: PContext, recNode: PNode, hasDefault: var bool, ch asgnExpr.typ = recNode.typ result.add newTree(nkExprColonExpr, recNode, asgnExpr) else: - doAssert false + raiseAssert "unreachable" proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault: bool): seq[PNode] = result = @[] @@ -630,7 +630,7 @@ proc defaultFieldsForTheUninitialized(c: PContext, recNode: PNode, checkDefault: asgnExpr.flags.incl nfSkipFieldChecking result.add newTree(nkExprColonExpr, recNode, asgnExpr) else: - doAssert false + raiseAssert "unreachable" proc defaultNodeField(c: PContext, a: PNode, aTyp: PType, checkDefault: bool): PNode = let aTypSkip = aTyp.skipTypes(defaultFieldsSkipTypes) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index a60bfee2a9..c6dec09a9b 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -408,8 +408,7 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P result = a result.typ = n.typ else: - result = nil - doAssert false, $srcTyp.kind + raiseAssert $srcTyp.kind of tyInt..tyInt64, tyUInt..tyUInt64: case srcTyp.kind of tyFloat..tyFloat64: diff --git a/compiler/tccgen.nim b/compiler/tccgen.nim index 83c891ca8b..9ee8516c47 100644 --- a/compiler/tccgen.nim +++ b/compiler/tccgen.nim @@ -14,7 +14,7 @@ const tinyPrefix = "dist/nim-tinyc-archive".unixToNativePath const nimRoot = currentSourcePath.parentDir.parentDir const tinycRoot = nimRoot / tinyPrefix when not dirExists(tinycRoot): - static: doAssert false, $(tinycRoot, "requires: ./koch installdeps tinyc") + static: raiseAssert $(tinycRoot, "requires: ./koch installdeps tinyc") {.compile: tinycRoot / "tinyc/libtcc.c".} var diff --git a/compiler/vmconv.nim b/compiler/vmconv.nim index 2353feba8c..394fb838b3 100644 --- a/compiler/vmconv.nim +++ b/compiler/vmconv.nim @@ -16,7 +16,7 @@ proc fromLit*(a: PNode, T: typedesc): auto = for ai in a: result.incl Ti(ai.intVal) else: - static: doAssert false, "not yet supported: " & $T # add as needed + static: raiseAssert "not yet supported: " & $T # add as needed proc toLit*[T](a: T): PNode = ## generic type => PNode @@ -43,7 +43,7 @@ proc toLit*[T](a: T): PNode = reti.add ai.toLit result.add reti else: - static: doAssert false, "not yet supported: " & $T # add as needed + static: raiseAssert "not yet supported: " & $T # add as needed proc toTimeLit*(a: Time, c: PCtx, obj: PNode, info: TLineInfo): PNode = # probably refactor it into `toLit` in the future diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 49ac7533b1..8aaac6272c 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -366,7 +366,7 @@ proc genBlock(c: PCtx; n: PNode; dest: var TDest) = slotTempFloat, slotTempStr, slotTempComplex}: - doAssert false, "leaking temporary " & $i & " " & $c.prc.regInfo[i].kind + raiseAssert "leaking temporary " & $i & " " & $c.prc.regInfo[i].kind c.prc.regInfo[i] = (inUse: false, kind: slotEmpty) c.clearDest(n, dest) @@ -1073,7 +1073,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = case n[1].typ.skipTypes(abstractVarRange).kind of tyString: genUnaryABI(c, n, dest, opcLenStr) of tyCstring: genUnaryABI(c, n, dest, opcLenCstring) - else: doAssert false, $n[1].typ.kind + else: raiseAssert $n[1].typ.kind of mSlice: var d = c.genx(n[1]) diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim index 7d9e66104c..2d7ad63e79 100644 --- a/compiler/vmhooks.nim +++ b/compiler/vmhooks.nim @@ -69,9 +69,7 @@ proc getVar*(a: VmArgs; i: Natural): PNode = case p.kind of rkRegisterAddr: result = p.regAddr.node of rkNodeAddr: result = p.nodeAddr[] - else: - result = nil - doAssert false, $p.kind + else: raiseAssert $p.kind proc getNodeAddr*(a: VmArgs; i: Natural): PNode = let nodeAddr = getX(rkNodeAddr, nodeAddr) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 73d24a2733..e81822ba64 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -243,7 +243,7 @@ proc registerAdditionalOps*(c: PCtx) = case n of 1: setResult(a, round(getFloat(a, 0))) of 2: setResult(a, round(getFloat(a, 0), getInt(a, 1).int)) - else: doAssert false, $n + else: raiseAssert $n proc `mod Wrapper`(a: VmArgs) {.nimcall.} = setResult(a, `mod`(getFloat(a, 0), getFloat(a, 1))) From faf1c91e6a418e21d56ac6e45e1dbc851f9ffd22 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 11 Aug 2023 00:04:29 +0800 Subject: [PATCH 425/489] fixes move sideeffects issues [backport] (#22439) * fixes move sideeffects issues [backport] * fix openarray * fixes openarray --- compiler/ccgexprs.nim | 18 +++++++++++++++--- tests/destructor/tmove.nim | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 tests/destructor/tmove.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index dd47d1d1f8..64bd16f84f 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2310,9 +2310,21 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) = if op == nil: resetLoc(p, a) else: - let addrExp = makeAddr(n[1], p.module.idgen) - let wasMovedCall = newTreeI(nkCall, n.info, newSymNode(op), addrExp) - genCall(p, wasMovedCall, d) + var b = initLocExpr(p, newSymNode(op)) + case skipTypes(a.t, abstractVar+{tyStatic}).kind + of tyOpenArray, tyVarargs: # todo fixme generated `wasMoved` hooks for + # openarrays, but it probably shouldn't? + var s: string + if reifiedOpenArray(a.lode): + if a.t.kind in {tyVar, tyLent}: + s = "$1->Field0, $1->Field1" % [rdLoc(a)] + else: + s = "$1.Field0, $1.Field1" % [rdLoc(a)] + else: + s = "$1, $1Len_0" % [rdLoc(a)] + linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), s]) + else: + linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), byRefLoc(p, a)]) else: let flags = if not canMove(p, n[1], d): {needToCopy} else: {} genAssignment(p, d, a, flags) diff --git a/tests/destructor/tmove.nim b/tests/destructor/tmove.nim new file mode 100644 index 0000000000..2762aff900 --- /dev/null +++ b/tests/destructor/tmove.nim @@ -0,0 +1,18 @@ +discard """ + targets: "c cpp" +""" + +block: + var called = 0 + + proc bar(a: var int): var int = + inc called + result = a + + proc foo = + var a = 2 + var s = move bar(a) + doAssert called == 1 + doAssert s == 2 + + foo() From 0bf286583ab5260a2d57def0bf6dd41c5fcf76c1 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 11 Aug 2023 12:50:41 +0800 Subject: [PATCH 426/489] `initNodeTable` and friends now return (#22444) --- compiler/ast.nim | 38 +++++++++++++++----------------------- compiler/cgen.nim | 2 +- compiler/docgen.nim | 2 +- compiler/evaltempl.nim | 2 +- compiler/lookups.nim | 4 ++-- compiler/magicsys.nim | 6 +++--- compiler/modulegraphs.nim | 20 ++++++++++---------- compiler/sem.nim | 2 +- compiler/semdata.nim | 10 +++++----- compiler/semexprs.nim | 3 +-- compiler/seminst.nim | 9 ++++----- compiler/semtypes.nim | 3 +-- compiler/semtypinst.nim | 6 +++--- compiler/sigmatch.nim | 4 ++-- compiler/transf.nim | 4 +--- 15 files changed, 51 insertions(+), 64 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 99647e2930..35e334b6ab 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1611,21 +1611,13 @@ proc createModuleAlias*(s: PSym, idgen: IdGenerator, newIdent: PIdent, info: TLi result.loc = s.loc result.annex = s.annex -proc initStrTable*(x: var TStrTable) = - x.counter = 0 - newSeq(x.data, StartSize) +proc initStrTable*(): TStrTable = + result = TStrTable(counter: 0) + newSeq(result.data, StartSize) -proc newStrTable*: TStrTable = - result = default(TStrTable) - initStrTable(result) - -proc initIdTable*(x: var TIdTable) = - x.counter = 0 - newSeq(x.data, StartSize) - -proc newIdTable*: TIdTable = - result = default(TIdTable) - initIdTable(result) +proc initIdTable*(): TIdTable = + result = TIdTable(counter: 0) + newSeq(result.data, StartSize) proc resetIdTable*(x: var TIdTable) = x.counter = 0 @@ -1633,17 +1625,17 @@ proc resetIdTable*(x: var TIdTable) = setLen(x.data, 0) setLen(x.data, StartSize) -proc initObjectSet*(x: var TObjectSet) = - x.counter = 0 - newSeq(x.data, StartSize) +proc initObjectSet*(): TObjectSet = + result = TObjectSet(counter: 0) + newSeq(result.data, StartSize) -proc initIdNodeTable*(x: var TIdNodeTable) = - x.counter = 0 - newSeq(x.data, StartSize) +proc initIdNodeTable*(): TIdNodeTable = + result = TIdNodeTable(counter: 0) + newSeq(result.data, StartSize) -proc initNodeTable*(x: var TNodeTable) = - x.counter = 0 - newSeq(x.data, StartSize) +proc initNodeTable*(): TNodeTable = + result = TNodeTable(counter: 0) + newSeq(result.data, StartSize) proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType = result = t diff --git a/compiler/cgen.nim b/compiler/cgen.nim index de15e8ca4f..5aafc506b2 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1981,7 +1981,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule result.preInitProc = newProc(nil, result) result.preInitProc.flags.incl nimErrorFlagDisabled result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated - initNodeTable(result.dataCache) + result.dataCache = initNodeTable() result.typeStack = @[] result.typeNodesName = getTempName(result) result.nimTypesName = getTempName(result) diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 933fe57f6f..a6f75b6263 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -373,7 +373,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef, result.seenSymbols = newStringTable(modeCaseInsensitive) result.id = 100 result.jEntriesFinal = newJArray() - initStrTable result.types + result.types = initStrTable() result.onTestSnippet = proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) {.gcsafe.} = if conf.docCmd == docCmdSkip: return diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index ff5c311549..a5d888858f 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -187,7 +187,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; ctx.genSymOwner = genSymOwner ctx.config = conf ctx.ic = ic - initIdTable(ctx.mapping) + ctx.mapping = initIdTable() ctx.instID = instID[] ctx.idgen = idgen diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 8b9dd71fdc..3cf759981f 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -72,7 +72,7 @@ proc addUniqueSym*(scope: PScope, s: PSym): PSym = proc openScope*(c: PContext): PScope {.discardable.} = result = PScope(parent: c.currentScope, - symbols: newStrTable(), + symbols: initStrTable(), depthLevel: c.scopeDepth + 1) c.currentScope = result @@ -404,7 +404,7 @@ proc openShadowScope*(c: PContext) = ## opens a shadow scope, just like any other scope except the depth is the ## same as the parent -- see `isShadowScope`. c.currentScope = PScope(parent: c.currentScope, - symbols: newStrTable(), + symbols: initStrTable(), depthLevel: c.scopeDepth) proc closeShadowScope*(c: PContext) = diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 1b692f5d62..1a9daa9f2b 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -81,8 +81,8 @@ proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType = proc resetSysTypes*(g: ModuleGraph) = g.systemModule = nil - initStrTable(g.compilerprocs) - initStrTable(g.exposed) + g.compilerprocs = initStrTable() + g.exposed = initStrTable() for i in low(g.sysTypes)..high(g.sysTypes): g.sysTypes[i] = nil @@ -124,7 +124,7 @@ proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) = proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym = strTableGet(g.exposed, getIdent(g.cache, name)) -proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed) +proc resetNimScriptSymbols*(g: ModuleGraph) = g.exposed = initStrTable() proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym = case t.kind diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index f9d0578b5c..b983334535 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -142,7 +142,7 @@ type isFrontend: bool] proc resetForBackend*(g: ModuleGraph) = - initStrTable(g.compilerprocs) + g.compilerprocs = initStrTable() g.typeInstCache.clear() g.procInstCache.clear() for a in mitems(g.attachedOps): @@ -196,8 +196,8 @@ template semtabAll*(g: ModuleGraph, m: PSym): TStrTable = g.ifaces[m.position].interfHidden proc initStrTables*(g: ModuleGraph, m: PSym) = - initStrTable(semtab(g, m)) - initStrTable(semtabAll(g, m)) + semtab(g, m) = initStrTable() + semtabAll(g, m) = initStrTable() proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) = strTableAdd(semtab(g, m), s) @@ -459,7 +459,7 @@ proc initModuleGraphFields(result: ModuleGraph) = # A module ID of -1 means that the symbol is not attached to a module at all, # but to the module graph: result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32) - initStrTable(result.packageSyms) + result.packageSyms = initStrTable() result.deps = initIntSet() result.importDeps = initTable[FileIndex, seq[FileIndex]]() result.ifaces = @[] @@ -469,9 +469,9 @@ proc initModuleGraphFields(result: ModuleGraph) = result.suggestSymbols = initTable[FileIndex, seq[SymInfoPair]]() result.suggestErrors = initTable[FileIndex, seq[Suggest]]() result.methods = @[] - initStrTable(result.compilerprocs) - initStrTable(result.exposed) - initStrTable(result.packageTypes) + result.compilerprocs = initStrTable() + result.exposed = initStrTable() + result.packageTypes = initStrTable() result.emptyNode = newNode(nkEmpty) result.cacheSeqs = initTable[string, PNode]() result.cacheCounters = initTable[string, BiggestInt]() @@ -488,7 +488,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph = initModuleGraphFields(result) proc resetAllModules*(g: ModuleGraph) = - initStrTable(g.packageSyms) + g.packageSyms = initStrTable() g.deps = initIntSet() g.ifaces = @[] g.importStack = @[] @@ -496,8 +496,8 @@ proc resetAllModules*(g: ModuleGraph) = g.usageSym = nil g.owners = @[] g.methods = @[] - initStrTable(g.compilerprocs) - initStrTable(g.exposed) + g.compilerprocs = initStrTable() + g.exposed = initStrTable() initModuleGraphFields(g) proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = diff --git a/compiler/sem.nim b/compiler/sem.nim index 42e6313581..f19f273b5d 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -462,7 +462,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, # e.g. template foo(T: typedesc): seq[T] # We will instantiate the return type here, because # we now know the supplied arguments - var paramTypes = newIdTable() + var paramTypes = initIdTable() for param, value in genericParamsInMacroCall(s, call): idTablePut(paramTypes, param.typ, value.typ) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index e783e2168e..0446da6760 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -251,7 +251,7 @@ proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next proc put*(p: PProcCon; key, val: PSym) = if not p.mappingExists: - initIdTable(p.mapping) + p.mapping = initIdTable() p.mappingExists = true #echo "put into table ", key.info p.mapping.idTablePut(key, val) @@ -317,13 +317,13 @@ proc newContext*(graph: ModuleGraph; module: PSym): PContext = result.converters = @[] result.patterns = @[] result.includedFiles = initIntSet() - initStrTable(result.pureEnumFields) - initStrTable(result.userPragmas) + result.pureEnumFields = initStrTable() + result.userPragmas = initStrTable() result.generics = @[] result.unknownIdents = initIntSet() result.cache = graph.cache result.graph = graph - initStrTable(result.signatures) + result.signatures = initStrTable() result.features = graph.config.features if graph.config.symbolFiles != disabledSf: let id = module.position @@ -388,7 +388,7 @@ proc reexportSym*(c: PContext; s: PSym) = proc newLib*(kind: TLibKind): PLib = new(result) - result.kind = kind #initObjectSet(result.syms) + result.kind = kind #result.syms = initObjectSet() proc addToLib*(lib: PLib, sym: PSym) = #if sym.annex != nil and not isGenericRoutine(sym): diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index dca4ce6e0d..52eef76316 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2361,8 +2361,7 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType; let sym = magicsys.getCompilerProc(c.graph, "nimCreateFlowVar") if sym == nil: localError(c.config, info, "system needs: nimCreateFlowVar") - var bindings: TIdTable = default(TIdTable) - initIdTable(bindings) + var bindings: TIdTable = initIdTable() bindings.idTablePut(sym.ast[genericParamsPos][0].typ, t) result = c.semGenerateInstance(c, sym, bindings, info) # since it's an instantiation, we unmark it as a compilerproc. Otherwise diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 0dc3e3cfc9..c7735903e0 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -122,8 +122,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) = inc c.inGenericInst # add it here, so that recursive generic procs are possible: var b = n[bodyPos] - var symMap: TIdTable - initIdTable symMap + var symMap: TIdTable = initIdTable() if params != nil: for i in 1.. Date: Fri, 11 Aug 2023 17:08:51 +0800 Subject: [PATCH 427/489] modernize lambdalifting (#22449) * modernize lambdalifting * follow @beef331's suggestions --- compiler/lambdalifting.nim | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 37c913fe2e..ee1e5b7976 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -320,12 +320,10 @@ type idgen: IdGenerator proc initDetectionPass(g: ModuleGraph; fn: PSym; idgen: IdGenerator): DetectionPass = - result.processed = initIntSet() - result.capturedVars = initIntSet() - result.ownerToType = initTable[int, PType]() - result.processed.incl(fn.id) - result.graph = g - result.idgen = idgen + result = DetectionPass(processed: toIntSet([fn.id]), + capturedVars: initIntSet(), ownerToType: initTable[int, PType](), + graph: g, idgen: idgen + ) discard """ proc outer = @@ -530,9 +528,8 @@ type unownedEnvVars: Table[int, PNode] # only required for --newruntime proc initLiftingPass(fn: PSym): LiftingPass = - result.processed = initIntSet() - result.processed.incl(fn.id) - result.envVars = initTable[int, PNode]() + result = LiftingPass(processed: toIntSet([fn.id]), + envVars: initTable[int, PNode]()) proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode = let s = n.sym From 3bb75f2dea1c65ee6b4b7fdca48748c97088cf76 Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 11 Aug 2023 18:50:31 +0800 Subject: [PATCH 428/489] close #18103 internal error: inconsistent environment type (#22451) --- tests/vm/t18103.nim | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/vm/t18103.nim diff --git a/tests/vm/t18103.nim b/tests/vm/t18103.nim new file mode 100644 index 0000000000..8622ab2906 --- /dev/null +++ b/tests/vm/t18103.nim @@ -0,0 +1,35 @@ +discard """ + targets: "c cpp" + matrix: "--mm:refc; --mm:arc" +""" + +import base64, complex, sequtils, math, sugar + +type + + FP = float + T = object + index: int + arg: FP + val: Complex[FP] + M = object + alpha, beta: FP + +func a(s: openArray[T], model: M): seq[T] = + let f = (tn: int) => model.alpha + FP(tn) * model.beta; + return mapIt s: + block: + let s = it.val * rect(1.0, - f(it.index)) + T(index: it.index, arg: phase(s), val: s) + +proc b(): float64 = + var s = toSeq(0..10).mapIt(T(index: it, arg: 1.0, val: complex.complex(1.0))) + discard a(s, M(alpha: 1, beta: 1)) + return 1.0 + +func cc(str: cstring, offset: ptr[cdouble]): cint {.exportc.} = + offset[] = b() + return 0 + +static: + echo b() From 277393d0f1c06c422afb6fae581069960609b730 Mon Sep 17 00:00:00 2001 From: Bung Date: Fri, 11 Aug 2023 19:11:47 +0800 Subject: [PATCH 429/489] =?UTF-8?q?close=20#17045;Compiler=20crash=20when?= =?UTF-8?q?=20a=20tuple=20iterator=20with=20when=20nimvm=20is=20=E2=80=A6?= =?UTF-8?q?=20(#22452)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #17045;Compiler crash when a tuple iterator with when nimvm is iterated in a closure iterator --- tests/async/t17045.nim | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/async/t17045.nim diff --git a/tests/async/t17045.nim b/tests/async/t17045.nim new file mode 100644 index 0000000000..2b5acf48a4 --- /dev/null +++ b/tests/async/t17045.nim @@ -0,0 +1,28 @@ +discard """ + targets: "c cpp" + matrix: "--mm:refc; --mm:arc" +""" + +type Future = ref object + +iterator paths: string = + # without "when nimvm" everything works + when nimvm: + yield "test.md" + else: + yield "test.md" + +template await(f: Future): string = + # need this yield, also the template has to return something + yield f + "hello world" + +proc generatePostContextsAsync() = + iterator generatePostContextsAsyncIter(): Future {.closure.} = + for filePath in paths(): + var temp = await Future() + + # need this line + var nameIterVar = generatePostContextsAsyncIter + +generatePostContextsAsync() \ No newline at end of file From 72bc72bf9ea470603420a0b56f63dad063f808a9 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 11 Aug 2023 22:16:58 +0800 Subject: [PATCH 430/489] refactor `result = default(...)` into object construction (#22455) --- compiler/semtypinst.nim | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index aef1e03748..e3c8c1c0a7 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -96,9 +96,7 @@ proc initLayeredTypeMap*(pt: TIdTable): LayeredIdTable = copyIdTable(result.topLayer, pt) proc newTypeMapLayer*(cl: var TReplTypeVars): LayeredIdTable = - result = LayeredIdTable() - result.nextLayer = cl.typeMap - result.topLayer = initIdTable() + result = LayeredIdTable(nextLayer: cl.typeMap, topLayer: initIdTable()) proc lookup(typeMap: LayeredIdTable, key: PType): PType = result = nil @@ -685,13 +683,9 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = proc initTypeVars*(p: PContext, typeMap: LayeredIdTable, info: TLineInfo; owner: PSym): TReplTypeVars = - result = default(TReplTypeVars) - result.symMap = initIdTable() - result.localCache = initIdTable() - result.typeMap = typeMap - result.info = info - result.c = p - result.owner = owner + result = TReplTypeVars(symMap: initIdTable(), + localCache: initIdTable(), typeMap: typeMap, + info: info, c: p, owner: owner) proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode; owner: PSym, allowMetaTypes = false, From 469c9cfab487380ba85520c90a2fad7d658c3023 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 11 Aug 2023 22:18:24 +0800 Subject: [PATCH 431/489] unpublic the sons field of PType; the precursor to PType refactorings (#22446) * unpublic the sons field of PType * tiny fixes * fixes an omittance * fixes IC * fixes --- compiler/ast.nim | 22 +++++++++++++++++++--- compiler/ccgexprs.nim | 4 ++-- compiler/ccgtypes.nim | 4 ++-- compiler/concepts.nim | 6 +++--- compiler/docgen.nim | 4 ++-- compiler/ic/ic.nim | 4 ++-- compiler/liftdestructors.nim | 2 +- compiler/magicsys.nim | 2 +- compiler/pragmas.nim | 4 ++-- compiler/semcall.nim | 5 ++--- compiler/semdata.nim | 30 +++++++++++++++--------------- compiler/semexprs.nim | 2 +- compiler/sempass2.nim | 2 +- compiler/semstmts.nim | 14 +++++++------- compiler/semtypes.nim | 18 ++++++++++++------ compiler/semtypinst.nim | 10 ++++------ compiler/sighashes.nim | 2 +- compiler/sigmatch.nim | 19 +++++++++---------- compiler/types.nim | 10 +++++----- compiler/varpartitions.nim | 4 ++-- compiler/vmdeps.nim | 2 +- 21 files changed, 94 insertions(+), 76 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 35e334b6ab..ce5ad0f292 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -958,7 +958,7 @@ type kind*: TTypeKind # kind of type callConv*: TCallingConvention # for procs flags*: TTypeFlags # flags of the type - sons*: TTypeSeq # base types, etc. + sons: TTypeSeq # base types, etc. n*: PNode # node for types: # for range types a nkRange node # for record types a nkRecord node @@ -1537,15 +1537,31 @@ proc `$`*(s: PSym): string = else: result = "" -proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType = +iterator items*(t: PType): PType = + for i in 0.. 0: result.add ", " - getDefaultValue(p, t.sons[1], info, result) + getDefaultValue(p, t[1], info, result) result.add "}" #result = rope"{}" of tyOpenArray, tyVarargs: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index c2c1d63180..eb5e906e42 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1178,9 +1178,9 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = var memberOp = "#." #only virtual var typ: PType if isCtor: - typ = prc.typ.sons[0] + typ = prc.typ[0] else: - typ = prc.typ.sons[1] + typ = prc.typ[1] if typ.kind == tyPtr: typ = typ[0] memberOp = "#->" diff --git a/compiler/concepts.nim b/compiler/concepts.nim index c3d8d265d8..681e4eace9 100644 --- a/compiler/concepts.nim +++ b/compiler/concepts.nim @@ -167,9 +167,9 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool = # modifiers in the concept must be there in the actual implementation # too but not vice versa. if a.kind == f.kind: - result = matchType(c, f.sons[0], a.sons[0], m) + result = matchType(c, f[0], a[0], m) elif m.magic == mArrPut: - result = matchType(c, f.sons[0], a, m) + result = matchType(c, f[0], a, m) else: result = false of tyEnum, tyObject, tyDistinct: @@ -264,7 +264,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool = m.inferred.setLen oldLen return false - if not matchReturnType(c, n[0].sym.typ.sons[0], candidate.typ.sons[0], m): + if not matchReturnType(c, n[0].sym.typ[0], candidate.typ[0], m): m.inferred.setLen oldLen return false diff --git a/compiler/docgen.nim b/compiler/docgen.nim index a6f75b6263..7edee1663f 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1196,9 +1196,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): result.json["signature"]["genericParams"] = newJArray() for genericParam in n[genericParamsPos]: var param = %{"name": %($genericParam)} - if genericParam.sym.typ.sons.len > 0: + if genericParam.sym.typ.len > 0: param["types"] = newJArray() - for kind in genericParam.sym.typ.sons: + for kind in genericParam.sym.typ: param["types"].add %($kind) result.json["signature"]["genericParams"].add param if optGenIndex in d.conf.globalOptions: diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index c2f3f793c3..845e3d1fa6 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -359,7 +359,7 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI paddingAtEnd: t.paddingAtEnd) storeNode(p, t, n) p.typeInst = t.typeInst.storeType(c, m) - for kid in items t.sons: + for kid in items t: p.types.add kid.storeType(c, m) c.addMissing t.sym p.sym = t.sym.safeItemId(c, m) @@ -917,7 +917,7 @@ proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph; result.attachedOps[op] = loadSym(c, g, si, item) result.typeInst = loadType(c, g, si, t.typeInst) for son in items t.types: - result.sons.add loadType(c, g, si, son) + result.addSon loadType(c, g, si, son) loadAstBody(t, n) when false: for gen, id in items t.methods: diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 6ae4173477..f28586addb 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -302,7 +302,7 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode = result.add newSymNode(op) if sfNeverRaises notin op.flags: c.canRaise = true - if op.typ.sons[1].kind == tyVar: + if op.typ[1].kind == tyVar: result.add genAddr(c, x) else: result.add x diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 1a9daa9f2b..bb8c6a5b98 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -100,7 +100,7 @@ proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} = proc addSonSkipIntLit*(father, son: PType; id: IdGenerator) = let s = son.skipIntLit(id) - father.sons.add(s) + father.add(s) propagateToOwner(father, s) proc getCompilerProc*(g: ModuleGraph; name: string): PSym = diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 56e25c0b43..6a371ba067 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -140,9 +140,9 @@ proc pragmaEnsures(c: PContext, n: PNode) = else: openScope(c) let o = getCurrOwner(c) - if o.kind in routineKinds and o.typ != nil and o.typ.sons[0] != nil: + if o.kind in routineKinds and o.typ != nil and o.typ[0] != nil: var s = newSym(skResult, getIdent(c.cache, "result"), c.idgen, o, n.info) - s.typ = o.typ.sons[0] + s.typ = o.typ[0] incl(s.flags, sfUsed) addDecl(c, s) n[1] = c.semExpr(c, n[1]) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 073c00c37e..e7c9226dd2 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -598,7 +598,7 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) = # nested, add all the types to stack let startIdx = if u.kind in ConcreteTypes: 0 else: 1 - endIdx = min(u.sons.len() - startIdx, t.sons.len()) + endIdx = min(u.len() - startIdx, t.len()) for i in startIdx ..< endIdx: # early exit with current impl @@ -717,8 +717,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = if formal.kind == tyStatic and arg.kind != tyStatic: let evaluated = c.semTryConstExpr(c, n[i]) if evaluated != nil: - arg = newTypeS(tyStatic, c) - arg.sons = @[evaluated.typ] + arg = newTypeS(tyStatic, c, sons = @[evaluated.typ]) arg.n = evaluated let tm = typeRel(m, formal, arg) if tm in {isNone, isConvertible}: return nil diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 0446da6760..db3b8370ee 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -395,8 +395,8 @@ proc addToLib*(lib: PLib, sym: PSym) = # LocalError(sym.info, errInvalidPragma) sym.annex = lib -proc newTypeS*(kind: TTypeKind, c: PContext): PType = - result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c)) +proc newTypeS*(kind: TTypeKind, c: PContext, sons: seq[PType] = @[]): PType = + result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c), sons = sons) proc makePtrType*(owner: PSym, baseType: PType; idgen: IdGenerator): PType = result = newType(tyPtr, nextTypeId(idgen), owner) @@ -446,13 +446,15 @@ proc makeTypeFromExpr*(c: PContext, n: PNode): PType = proc newTypeWithSons*(owner: PSym, kind: TTypeKind, sons: seq[PType]; idgen: IdGenerator): PType = - result = newType(kind, nextTypeId(idgen), owner) - result.sons = sons + result = newType(kind, nextTypeId(idgen), owner, sons = sons) proc newTypeWithSons*(c: PContext, kind: TTypeKind, sons: seq[PType]): PType = - result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c)) - result.sons = sons + result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c), sons = sons) + +proc newTypeWithSons*(c: PContext, kind: TTypeKind, + parent: PType): PType = + result = newType(kind, nextTypeId(c.idgen), getCurrOwner(c), parent = parent) proc makeStaticExpr*(c: PContext, n: PNode): PNode = result = newNodeI(nkStaticExpr, n.info) @@ -461,21 +463,21 @@ proc makeStaticExpr*(c: PContext, n: PNode): PNode = else: newTypeWithSons(c, tyStatic, @[n.typ]) proc makeAndType*(c: PContext, t1, t2: PType): PType = - result = newTypeS(tyAnd, c) - result.sons = @[t1, t2] + result = newTypeS(tyAnd, c, sons = @[t1, t2]) propagateToOwner(result, t1) propagateToOwner(result, t2) result.flags.incl((t1.flags + t2.flags) * {tfHasStatic}) result.flags.incl tfHasMeta proc makeOrType*(c: PContext, t1, t2: PType): PType = - result = newTypeS(tyOr, c) + if t1.kind != tyOr and t2.kind != tyOr: - result.sons = @[t1, t2] + result = newTypeS(tyOr, c, sons = @[t1, t2]) else: + result = newTypeS(tyOr, c) template addOr(t1) = if t1.kind == tyOr: - for x in t1.sons: result.rawAddSon x + for x in t1: result.rawAddSon x else: result.rawAddSon t1 addOr(t1) @@ -486,8 +488,7 @@ proc makeOrType*(c: PContext, t1, t2: PType): PType = result.flags.incl tfHasMeta proc makeNotType*(c: PContext, t1: PType): PType = - result = newTypeS(tyNot, c) - result.sons = @[t1] + result = newTypeS(tyNot, c, sons = @[t1]) propagateToOwner(result, t1) result.flags.incl(t1.flags * {tfHasStatic}) result.flags.incl tfHasMeta @@ -498,8 +499,7 @@ proc nMinusOne(c: PContext; n: PNode): PNode = # Remember to fix the procs below this one when you make changes! proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType = let intType = getSysType(c.graph, n.info, tyInt) - result = newTypeS(tyRange, c) - result.sons = @[intType] + result = newTypeS(tyRange, c, sons = @[intType]) if n.typ != nil and n.typ.n == nil: result.flags.incl tfUnresolved result.n = newTreeI(nkRange, n.info, newIntTypeNode(0, intType), diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 52eef76316..df65b33712 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1422,7 +1422,7 @@ proc tryReadingTypeField(c: PContext, n: PNode, i: PIdent, ty: PType): PNode = while ty != nil: f = getSymFromList(ty.n, i) if f != nil: break - ty = ty.sons[0] # enum inheritance + ty = ty[0] # enum inheritance if f != nil: result = newSymNode(f) result.info = n.info diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 0aa8080597..854247095e 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1327,7 +1327,7 @@ proc track(tracked: PEffects, n: PNode) = proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool = if spec.typ.kind == tyOr: - for t in spec.typ.sons: + for t in spec.typ: if safeInheritanceDiff(g.excType(real), t) <= 0: return true else: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index e64cd8db63..39c37f4fb2 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -45,7 +45,7 @@ proc hasEmpty(typ: PType): bool = result = typ.lastSon.kind == tyEmpty elif typ.kind == tyTuple: result = false - for s in typ.sons: + for s in typ: result = result or hasEmpty(s) else: result = false @@ -1344,7 +1344,7 @@ proc checkCovariantParamsUsages(c: PContext; genericType: PType) = of tyArray: return traverseSubTypes(c, t[1]) of tyProc: - for subType in t.sons: + for subType in t: if subType != nil: subresult traverseSubTypes(c, subType) if result: @@ -1377,7 +1377,7 @@ proc checkCovariantParamsUsages(c: PContext; genericType: PType) = of tyUserTypeClass, tyUserTypeClassInst: error("non-invariant type parameters are not supported in concepts") of tyTuple: - for fieldType in t.sons: + for fieldType in t: subresult traverseSubTypes(c, fieldType) of tyPtr, tyRef, tyVar, tyLent: if t.base.kind == tyGenericParam: return true @@ -2283,18 +2283,18 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, let isCtor = sfConstructor in s.flags let pragmaName = if isVirtual: "virtual" elif isCtor: "constructor" else: "member" if c.config.backend == backendCpp: - if s.typ.sons.len < 2 and not isCtor: + if s.typ.len < 2 and not isCtor: localError(c.config, n.info, pragmaName & " must have at least one parameter") - for son in s.typ.sons: + for son in s.typ: if son!=nil and son.isMetaType: localError(c.config, n.info, pragmaName & " unsupported for generic routine") var typ: PType if isCtor: - typ = s.typ.sons[0] + typ = s.typ[0] if typ == nil or typ.kind != tyObject: localError(c.config, n.info, "constructor must return an object") else: - typ = s.typ.sons[1] + typ = s.typ[1] if typ.kind == tyPtr and not isCtor: typ = typ[0] if typ.kind != tyObject: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index fcab8f1c98..8e304288b6 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -38,13 +38,20 @@ const errNoGenericParamsAllowedForX = "no generic parameters allowed for $1" errInOutFlagNotExtern = "the '$1' modifier can be used only with imported types" +proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext, sons: seq[PType]): PType = + if prev == nil or prev.kind == tyGenericBody: + result = newTypeS(kind, c, sons = sons) + else: + result = newType(prev, sons) + if result.kind == tyForward: result.kind = kind + #if kind == tyError: result.flags.incl tfCheckedForDestructor + proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType = if prev == nil or prev.kind == tyGenericBody: result = newTypeS(kind, c) else: result = prev if result.kind == tyForward: result.kind = kind - #if kind == tyError: result.flags.incl tfCheckedForDestructor proc newConstraint(c: PContext, k: TTypeKind): PType = result = newTypeS(tyBuiltInTypeClass, c) @@ -245,7 +252,7 @@ proc isRecursiveType*(t: PType): bool = proc addSonSkipIntLitChecked(c: PContext; father, son: PType; it: PNode, id: IdGenerator) = let s = son.skipIntLit(id) - father.sons.add(s) + father.add(s) if isRecursiveType(s): localError(c.config, it.info, "illegal recursion in type '" & typeToString(s) & "'") else: @@ -1012,7 +1019,7 @@ proc findEnforcedStaticType(t: PType): PType = if t == nil: return nil if t.kind == tyStatic: return t if t.kind == tyAnd: - for s in t.sons: + for s in t: let t = findEnforcedStaticType(s) if t != nil: return t @@ -1658,11 +1665,10 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = pragmas = n[1] inherited = n[2] - result = newOrPrevType(tyUserTypeClass, prev, c) - result.flags.incl tfCheckedForDestructor var owner = getCurrOwner(c) var candidateTypeSlot = newTypeWithSons(owner, tyAlias, @[c.errorType], c.idgen) - result.sons = @[candidateTypeSlot] + result = newOrPrevType(tyUserTypeClass, prev, c, sons = @[candidateTypeSlot]) + result.flags.incl tfCheckedForDestructor result.n = n if inherited.kind != nkEmpty: diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index e3c8c1c0a7..56b922fdaf 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -52,7 +52,7 @@ proc searchInstTypes*(g: ModuleGraph; key: PType): PType = continue block matchType: - for j in 1..high(key.sons): + for j in 1.. 0: + if t.len > 0: c.hashType t.lastSon, flags, conf if tfVarIsPtr in t.flags: c &= ".varisptr" of tyFromExpr: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 199d8bae98..048b74547f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -228,7 +228,7 @@ proc sumGeneric(t: PType): int = inc result of tyOr: var maxBranch = 0 - for branch in t.sons: + for branch in t: let branchSum = sumGeneric(branch) if branchSum > maxBranch: maxBranch = branchSum inc result, maxBranch @@ -904,7 +904,7 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool = else: discard elif lhs.kind == nkSym and lhs.typ.kind == tyStatic and lhs.typ.n == nil: - var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ.sons) + var inferred = newTypeWithSons(c.c, tyStatic, lhs.typ) inferred.n = newIntNode(nkIntLit, rhs) put(c, lhs.typ, inferred) if c.c.matchedConcept != nil: @@ -1109,7 +1109,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, # both int and string must match against number # but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219): result = isGeneric - for branch in a.sons: + for branch in a: let x = typeRel(c, f, branch, flags + {trDontBind}) if x == isNone: return isNone if x < result: result = x @@ -1120,7 +1120,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, c.typedescMatched = true # seq[Sortable and Iterable] vs seq[Sortable] # only one match is enough - for branch in a.sons: + for branch in a: let x = typeRel(c, f, branch, flags + {trDontBind}) if x != isNone: return if x >= isGeneric: isGeneric else: x @@ -1622,7 +1622,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyAnd: considerPreviousT: result = isEqual - for branch in f.sons: + for branch in f: let x = typeRel(c, branch, aOrig, flags) if x < isSubtype: return isNone # 'and' implies minimum matching result: @@ -1635,7 +1635,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, result = isNone let oldInheritancePenalty = c.inheritancePenalty var maxInheritance = 0 - for branch in f.sons: + for branch in f: c.inheritancePenalty = 0 let x = typeRel(c, branch, aOrig, flags) maxInheritance = max(maxInheritance, c.inheritancePenalty) @@ -1650,7 +1650,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, of tyNot: considerPreviousT: - for branch in f.sons: + for branch in f: if typeRel(c, branch, aOrig, flags) != isNone: return isNone @@ -2121,8 +2121,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, if evaluated != nil: # Don't build the type in-place because `evaluated` and `arg` may point # to the same object and we'd end up creating recursive types (#9255) - let typ = newTypeS(tyStatic, c) - typ.sons = @[evaluated.typ] + let typ = newTypeS(tyStatic, c, sons = @[evaluated.typ]) typ.n = evaluated arg = copyTree(arg) # fix #12864 arg.typ = typ @@ -2714,7 +2713,7 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = # forget all inferred types if the overload matching failed if m.state == csNoMatch: for t in m.inferredTypes: - if t.len > 1: t.sons.setLen 1 + if t.len > 1: t.newSons 1 proc argtypeMatches*(c: PContext, f, a: PType, fromHlo = false): bool = var m = newCandidate(c, f) diff --git a/compiler/types.nim b/compiler/types.nim index a385a291fe..3160583787 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -566,7 +566,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if t.kind == tyGenericParam and t.len > 0: result.add ": " var first = true - for son in t.sons: + for son in t: if not first: result.add " or " result.add son.typeToString first = false @@ -637,14 +637,14 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result.add(typeToString(t[i])) result.add "]" of tyAnd: - for i, son in t.sons: + for i, son in t: result.add(typeToString(son)) - if i < t.sons.high: + if i < t.len - 1: result.add(" and ") of tyOr: - for i, son in t.sons: + for i, son in t: result.add(typeToString(son)) - if i < t.sons.high: + if i < t.len - 1: result.add(" or ") of tyNot: result = "not " & typeToString(t[0]) diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 4dd51b63bc..74bf63da8f 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -407,8 +407,8 @@ proc allRoots(n: PNode; result: var seq[(PSym, int)]; level: int) = if typ != nil and i < typ.len: assert(typ.n[i].kind == nkSym) let paramType = typ.n[i].typ - if not paramType.isCompileTimeOnly and not typ.sons[0].isEmptyType and - canAlias(paramType, typ.sons[0]): + if not paramType.isCompileTimeOnly and not typ[0].isEmptyType and + canAlias(paramType, typ[0]): allRoots(it, result, RootEscapes) else: allRoots(it, result, RootEscapes) diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 75692fcc0e..863896419e 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -199,7 +199,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; # only named tuples have a node, unnamed tuples don't if t.n.isNil: result = newNodeX(nkTupleConstr) - for subType in t.sons: + for subType in t: result.add mapTypeToAst(subType, info) else: result = newNodeX(nkTupleTy) From 48da472dd2e625d2d794907afd33a4a153fa2dc1 Mon Sep 17 00:00:00 2001 From: Pylgos <43234674+Pylgos@users.noreply.github.com> Date: Sat, 12 Aug 2023 01:23:09 +0900 Subject: [PATCH 432/489] fix #22448 Remove `structuredErrorHook` temporary in `tryConstExpr` (#22450) * fix #22448 * add test --- compiler/sem.nim | 9 +++++++++ nimsuggest/tests/t22448.nim | 11 +++++++++++ 2 files changed, 20 insertions(+) create mode 100644 nimsuggest/tests/t22448.nim diff --git a/compiler/sem.nim b/compiler/sem.nim index f19f273b5d..f69e7a69d0 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -353,6 +353,11 @@ proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode = c.config.m.errorOutputs = {} c.config.errorMax = high(int) # `setErrorMaxHighMaybe` not appropriate here + when defined(nimsuggest): + # Remove the error hook so nimsuggest doesn't report errors there + let tempHook = c.graph.config.structuredErrorHook + c.graph.config.structuredErrorHook = nil + try: result = evalConstExpr(c.module, c.idgen, c.graph, e) if result == nil or result.kind == nkEmpty: @@ -363,6 +368,10 @@ proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode = except ERecoverableError: result = nil + when defined(nimsuggest): + # Restore the error hook + c.graph.config.structuredErrorHook = tempHook + c.config.errorCounter = oldErrorCount c.config.errorMax = oldErrorMax c.config.m.errorOutputs = oldErrorOutputs diff --git a/nimsuggest/tests/t22448.nim b/nimsuggest/tests/t22448.nim new file mode 100644 index 0000000000..8664bbbc3c --- /dev/null +++ b/nimsuggest/tests/t22448.nim @@ -0,0 +1,11 @@ +proc fn(a: static float) = discard +proc fn(a: int) = discard + +let x = 1 +fn(x) + +discard """ +$nimsuggest --tester --v3 $file +>chk $file +chk;;skUnknown;;;;Hint;;* +""" From 3f7e1d7daadf4002da1a155d7b98ff7fcca9e2fa Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 12 Aug 2023 00:24:46 +0800 Subject: [PATCH 433/489] replace `doAssert false` with `raiseAssert` in lib, which works better with strictdefs (#22458) --- lib/impure/re.nim | 2 +- lib/js/dom.nim | 6 +++--- lib/packages/docutils/rstgen.nim | 2 +- lib/pure/coro.nim | 4 ++-- lib/pure/hashes.nim | 8 ++++---- lib/pure/osproc.nim | 2 +- lib/pure/parseopt.nim | 2 +- lib/pure/streams.nim | 2 +- lib/pure/strformat.nim | 2 +- lib/pure/times.nim | 2 +- lib/pure/typetraits.nim | 2 +- lib/pure/unittest.nim | 2 +- lib/std/formatfloat.nim | 4 ++-- lib/std/genasts.nim | 2 +- lib/std/jsbigints.nim | 6 +++--- lib/std/jsonutils.nim | 6 +++--- lib/std/private/globs.nim | 2 +- lib/std/private/osfiles.nim | 2 +- lib/std/private/ospaths2.nim | 4 ++-- lib/std/sysrand.nim | 2 +- lib/system.nim | 2 +- testament/lib/stdtest/specialpaths.nim | 2 +- 22 files changed, 34 insertions(+), 34 deletions(-) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index f97a31d218..5e84091c77 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -460,7 +460,7 @@ template `=~` *(s: string, pattern: Regex): untyped = elif line =~ re"\s*(\#.*)": # matches a comment # note that the implicit `matches` array is different from 1st branch result = $(matches[0],) - else: doAssert false + else: raiseAssert "unreachable" doAssert not declared(matches) doAssert parse("NAME = LENA") == """("NAME", "LENA")""" doAssert parse(" # comment ... ") == """("# comment ... ",)""" diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 0a825865b3..ceb0375b7c 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1423,7 +1423,7 @@ when defined(nodejs): parent.childNodes[i] = newNode return inc i - doAssert false, "old node not in node list" + raiseAssert "old node not in node list" proc removeChild*(parent, child: Node) = child.parentNode = nil @@ -1433,7 +1433,7 @@ when defined(nodejs): parent.childNodes.delete(i) return inc i - doAssert false, "old node not in node list" + raiseAssert "old node not in node list" proc insertBefore*(parent, newNode, before: Node) = appendChild(parent, newNode) @@ -1445,7 +1445,7 @@ when defined(nodejs): parent.childNodes[i-1] = newNode return inc i - #doAssert false, "before not in node list" + #raiseAssert "before not in node list" proc createElement*(d: Document, identifier: cstring): Element = new(result) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 008dff60aa..f06e11de25 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1175,7 +1175,7 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) = renderAux(d, n, "
      $1
      ", " $1\n", result) of rnOption, rnOptionString, rnOptionArgument: - doAssert false, "renderRstToOut" + raiseAssert "renderRstToOut" of rnLiteralBlock: renderAux(d, n, "$1\n", "\n\n$2\\begin{rstpre}\n$1\n\\end{rstpre}\n\n", result) diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim index 7f0f551e60..5cdcb75fe7 100644 --- a/lib/pure/coro.nim +++ b/lib/pure/coro.nim @@ -224,7 +224,7 @@ proc switchTo(current, to: CoroutinePtr) = elif to.state == CORO_CREATED: # Coroutine is started. coroExecWithStack(runCurrentTask, to.stack.bottom) - #doAssert false + #raiseAssert "unreachable" else: {.error: "Invalid coroutine backend set.".} # Execution was just resumed. Restore frame information and set active stack. @@ -266,7 +266,7 @@ proc runCurrentTask() = current.state = CORO_FINISHED nimGC_setStackBottom(ctx.ncbottom) suspend(0) # Exit coroutine without returning from coroExecWithStack() - doAssert false + raiseAssert "unreachable" proc start*(c: proc(), stacksize: int = defaultStackSize): CoroutineRef {.discardable.} = ## Schedule coroutine for execution. It does not run immediately. diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index ad164d6d31..6d246d5b9b 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -368,16 +368,16 @@ proc murmurHash(x: openArray[byte]): Hash = return cast[Hash](h1) proc hashVmImpl(x: cstring, sPos, ePos: int): Hash = - doAssert false, "implementation override in compiler/vmops.nim" + raiseAssert "implementation override in compiler/vmops.nim" proc hashVmImpl(x: string, sPos, ePos: int): Hash = - doAssert false, "implementation override in compiler/vmops.nim" + raiseAssert "implementation override in compiler/vmops.nim" proc hashVmImplChar(x: openArray[char], sPos, ePos: int): Hash = - doAssert false, "implementation override in compiler/vmops.nim" + raiseAssert "implementation override in compiler/vmops.nim" proc hashVmImplByte(x: openArray[byte], sPos, ePos: int): Hash = - doAssert false, "implementation override in compiler/vmops.nim" + raiseAssert "implementation override in compiler/vmops.nim" proc hash*(x: string): Hash = ## Efficient hashing of strings. diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index e30f1da737..91c45e0539 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1348,7 +1348,7 @@ elif not defined(useNimRtl): p.exitStatus = status break else: - doAssert false, "unreachable!" + raiseAssert "unreachable!" result = exitStatusLikeShell(p.exitStatus) diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index 059f8e0f5d..2d039f1e4a 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -251,7 +251,7 @@ proc initOptParser*(cmdline: seq[string], shortNoVal: set[char] = {}, else: # we cannot provide this for NimRtl creation on Posix, because we can't # access the command line arguments then! - doAssert false, "empty command line given but" & + raiseAssert "empty command line given but" & " real command line is not accessible" result.kind = cmdEnd result.key = "" diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 003f8ca4c2..e18e2d43a6 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -1530,7 +1530,7 @@ when false: of fmReadWrite: flags = O_RDWR or int(O_CREAT) of fmReadWriteExisting: flags = O_RDWR of fmAppend: flags = O_WRONLY or int(O_CREAT) or O_APPEND - static: doAssert false # handle bug #17888 + static: raiseAssert "unreachable" # handle bug #17888 var handle = open(filename, flags) if handle < 0: raise newEOS("posix.open() call failed") result = newFileHandleStream(handle) diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 3fedff07b5..1cebefee10 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -663,7 +663,7 @@ proc strformatImpl(f: string; openChar, closeChar: char, strlit.add closeChar inc i, 2 else: - doAssert false, "invalid format string: '$1' instead of '$1$1'" % $closeChar + raiseAssert "invalid format string: '$1' instead of '$1$1'" % $closeChar inc i else: strlit.add f[i] diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 4f7af657cf..f5775e4d95 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -2089,7 +2089,7 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int, i.inc 2 else: result = false - of Lit: doAssert false, "Can't happen" + of Lit: raiseAssert "Can't happen" proc toDateTime(p: ParsedTime, zone: Timezone, f: TimeFormat, input: string): DateTime = diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index c20f9e6451..70eb1b81c0 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -225,7 +225,7 @@ macro genericParamsImpl(T: typedesc): untyped = case ai.typeKind of ntyTypeDesc: ret = ai - of ntyStatic: doAssert false + of ntyStatic: raiseAssert "unreachable" else: # getType from a resolved symbol might return a typedesc symbol. # If so, use it directly instead of wrapping it in StaticParam. diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index afe98ca4e2..3b3684789b 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -235,7 +235,7 @@ proc colorOutput(): bool = else: result = false of "on": result = true of "off": result = false - else: doAssert false, $color + else: raiseAssert $color when declared(stdout): if existsEnv("NIMTEST_COLOR"): diff --git a/lib/std/formatfloat.nim b/lib/std/formatfloat.nim index b216d1fd06..48973aa558 100644 --- a/lib/std/formatfloat.nim +++ b/lib/std/formatfloat.nim @@ -86,7 +86,7 @@ proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat | float32 proc addFloatRoundtrip*(result: var string; x: float | float32) = when nimvm: - doAssert false + raiseAssert "unreachable" else: var buffer {.noinit.}: array[65, char] let n = writeFloatToBufferRoundtrip(buffer, x) @@ -94,7 +94,7 @@ proc addFloatRoundtrip*(result: var string; x: float | float32) = proc addFloatSprintf*(result: var string; x: float) = when nimvm: - doAssert false + raiseAssert "unreachable" else: var buffer {.noinit.}: array[65, char] let n = writeFloatToBufferSprintf(buffer, x) diff --git a/lib/std/genasts.nim b/lib/std/genasts.nim index 05b2823efc..04257533db 100644 --- a/lib/std/genasts.nim +++ b/lib/std/genasts.nim @@ -24,7 +24,7 @@ macro genAstOpt*(options: static set[GenAstOpt], args: varargs[untyped]): untype result = genAst(cond, s = repr(cond), lhs = cond[1], rhs = cond[2]): # each local symbol we access must be explicitly captured if not cond: - doAssert false, "'$#'' failed: lhs: '$#', rhs: '$#'" % [s, $lhs, $rhs] + raiseAssert "'$#'' failed: lhs: '$#', rhs: '$#'" % [s, $lhs, $rhs] let a = 3 check2 a*2 == a+3 if false: check2 a*2 < a+1 # would error with: 'a * 2 < a + 1'' failed: lhs: '6', rhs: '4' diff --git a/lib/std/jsbigints.nim b/lib/std/jsbigints.nim index 067de78b5b..4e996ea7b9 100644 --- a/lib/std/jsbigints.nim +++ b/lib/std/jsbigints.nim @@ -14,7 +14,7 @@ func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".} = runnableExamples: doAssert big(1234567890) == big"1234567890" doAssert 0b1111100111.big == 0o1747.big and 0o1747.big == 999.big - when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard + when nimvm: raiseAssert "JsBigInt can not be used at compile-time nor static context" else: discard func `'big`*(num: cstring): JsBigInt {.importjs: "BigInt(#)".} = ## Constructor for `JsBigInt`. @@ -28,11 +28,11 @@ func `'big`*(num: cstring): JsBigInt {.importjs: "BigInt(#)".} = doAssert 0xdeadbeaf'big == 0xdeadbeaf.big doAssert 0xffffffffffffffff'big == (1'big shl 64'big) - 1'big doAssert not compiles(static(12'big)) - when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard + when nimvm: raiseAssert "JsBigInt can not be used at compile-time nor static context" else: discard func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".} = ## Alias for `'big` - when nimvm: doAssert false, "JsBigInt can not be used at compile-time nor static context" else: discard + when nimvm: raiseAssert "JsBigInt can not be used at compile-time nor static context" else: discard func toCstring*(this: JsBigInt; radix: 2..36): cstring {.importjs: "#.toString(#)".} = ## Converts from `JsBigInt` to `cstring` representation. diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim index 847761e2f8..b1025d24b3 100644 --- a/lib/std/jsonutils.nim +++ b/lib/std/jsonutils.nim @@ -95,7 +95,7 @@ macro getDiscriminants(a: typedesc): seq[string] = result = quote do: seq[string].default else: - doAssert false, "unexpected kind: " & $t2.kind + raiseAssert "unexpected kind: " & $t2.kind macro initCaseObject(T: typedesc, fun: untyped): untyped = ## does the minimum to construct a valid case object, only initializing @@ -109,7 +109,7 @@ macro initCaseObject(T: typedesc, fun: untyped): untyped = case t.kind of nnkObjectTy: t2 = t[2] of nnkRefTy: t2 = t[0].getTypeImpl[2] - else: doAssert false, $t.kind # xxx `nnkPtrTy` could be handled too + else: raiseAssert $t.kind # xxx `nnkPtrTy` could be handled too doAssert t2.kind == nnkRecList result = newTree(nnkObjConstr) result.add sym @@ -289,7 +289,7 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) = i.inc else: # checkJson not appropriate here - static: doAssert false, "not yet implemented: " & $T + static: raiseAssert "not yet implemented: " & $T proc jsonTo*(b: JsonNode, T: typedesc, opt = Joptions()): T = ## reverse of `toJson` diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim index 5e3e33cb4c..64065aac81 100644 --- a/lib/std/private/globs.nim +++ b/lib/std/private/globs.nim @@ -60,7 +60,7 @@ proc nativeToUnixPath*(path: string): string = result[0] = '/' result[1] = path[0] if path.len > 2 and path[2] != '\\': - doAssert false, "paths like `C:foo` are currently unsupported, path: " & path + raiseAssert "paths like `C:foo` are currently unsupported, path: " & path when DirSep == '\\': result = replace(result, '\\', '/') diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim index 78afd35dac..f2e7bf11d2 100644 --- a/lib/std/private/osfiles.nim +++ b/lib/std/private/osfiles.nim @@ -396,7 +396,7 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", if not tryMoveFSObject(source, dest, isDir = false): when defined(windows): - doAssert false + raiseAssert "unreachable" else: # Fallback to copy & del copyFile(source, dest, {cfSymlinkAsIs}) diff --git a/lib/std/private/ospaths2.nim b/lib/std/private/ospaths2.nim index 18a01b1049..421def62b3 100644 --- a/lib/std/private/ospaths2.nim +++ b/lib/std/private/ospaths2.nim @@ -259,7 +259,7 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1", raise # This works around the problem for posix, but Windows is still broken with nim js -d:nodejs result = path[0] == '/' else: - doAssert false # if ever hits here, adapt as needed + raiseAssert "unreachable" # if ever hits here, adapt as needed when FileSystemCaseSensitive: template `!=?`(a, b: char): bool = a != b @@ -859,7 +859,7 @@ when not defined(nimscript): {.emit: "`ret` = process.cwd();".} return $ret elif defined(js): - doAssert false, "use -d:nodejs to have `getCurrentDir` defined" + raiseAssert "use -d:nodejs to have `getCurrentDir` defined" elif defined(windows): var bufsize = MAX_PATH.int32 var res = newWideCString("", bufsize) diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim index 7943f2e1ba..8526336ad3 100644 --- a/lib/std/sysrand.nim +++ b/lib/std/sysrand.nim @@ -192,7 +192,7 @@ elif defined(linux) and not defined(nimNoGetRandom) and not defined(emscripten): while result < size: let readBytes = syscall(SYS_getrandom, addr dest[result], cint(size - result), 0).int if readBytes == 0: - doAssert false + raiseAssert "unreachable" elif readBytes > 0: inc(result, readBytes) else: diff --git a/lib/system.nim b/lib/system.nim index 3076fe2fda..521380a578 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2289,7 +2289,7 @@ elif defined(nimdoc): ## `quit(int(0x100000000))` is equal to `quit(127)` on Linux. ## ## .. danger:: In almost all cases, in particular in library code, prefer - ## alternatives, e.g. `doAssert false` or raise a `Defect`. + ## alternatives, e.g. `raiseAssert` or raise a `Defect`. ## `quit` bypasses regular control flow in particular `defer`, ## `try`, `catch`, `finally` and `destructors`, and exceptions that may have been ## raised by an `addExitProc` proc, as well as cleanup code in other threads. diff --git a/testament/lib/stdtest/specialpaths.nim b/testament/lib/stdtest/specialpaths.nim index 7df63666f9..e214d113df 100644 --- a/testament/lib/stdtest/specialpaths.nim +++ b/testament/lib/stdtest/specialpaths.nim @@ -48,7 +48,7 @@ proc splitTestFile*(file: string): tuple[cat: string, path: string] = else: result.path = file return result - doAssert false, "file must match this pattern: '/pathto/tests/dir/**/tfile.nim', got: '" & file & "'" + raiseAssert "file must match this pattern: '/pathto/tests/dir/**/tfile.nim', got: '" & file & "'" static: # sanity check From 23f3f9ae2ccb28cd5f9a6feaff92b9d26f4244e8 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 12 Aug 2023 08:30:17 +0800 Subject: [PATCH 434/489] better initialization patterns for seminst (#22456) * better initialization patterns for seminst * Update compiler/seminst.nim * Update compiler/seminst.nim --- compiler/seminst.nim | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index c7735903e0..61480494b2 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -29,11 +29,7 @@ proc addObjFieldsToLocalScope(c: PContext; n: PNode) = else: discard proc pushProcCon*(c: PContext; owner: PSym) = - var x: PProcCon - new(x) - x.owner = owner - x.next = c.p - c.p = x + c.p = PProcCon(owner: owner, next: c.p) const errCannotInstantiateX = "cannot instantiate: '$1'" @@ -172,18 +168,13 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType, allowMetaTypes = false): PType = internalAssert c.config, header.kind == tyGenericInvocation - var - cl: TReplTypeVars = default(TReplTypeVars) + var cl: TReplTypeVars = TReplTypeVars(symMap: initIdTable(), + localCache: initIdTable(), typeMap: LayeredIdTable(), + info: info, c: c, allowMetaTypes: allowMetaTypes + ) - cl.symMap = initIdTable() - cl.localCache = initIdTable() - cl.typeMap = LayeredIdTable() cl.typeMap.topLayer = initIdTable() - cl.info = info - cl.c = c - cl.allowMetaTypes = allowMetaTypes - # We must add all generic params in scope, because the generic body # may include tyFromExpr nodes depending on these generic params. # XXX: This looks quite similar to the code in matchUserTypeClass, From f642c9dbf112eb3a6fa993c8f1eee8a454c1c8ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Sat, 12 Aug 2023 09:37:52 +0100 Subject: [PATCH 435/489] documents member (#22460) * documents member * Apply suggestions from code review Co-authored-by: Juan Carlos * Update doc/manual_experimental.md * Update doc/manual_experimental.md * Update doc/manual_experimental.md * Update doc/manual_experimental.md * Update doc/manual_experimental.md * Update doc/manual_experimental.md --------- Co-authored-by: Juan Carlos Co-authored-by: Andreas Rumpf --- doc/manual_experimental.md | 59 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index 8cddce4f14..b0ce775ee1 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -2381,3 +2381,62 @@ proc makeCppClass(): NimClass {.constructor: "NimClass() : CppClass(0, 0)".} = In the example above `CppClass` has a deleted default constructor. Notice how by using the constructor syntax, one can call the appropiate constructor. Notice when calling a constructor in the section of a global variable initialization, it will be called before `NimMain` meaning Nim is not fully initialized. + +Member pragma +============= + +Similar to the `constructor` and `virtual` pragmas, the `member` pragma can be used to attach a `proc` or `func` to a type in C++. +It is more flexible than `virtual` in the sense that it accepts not only names but also operators or destructors. + +For example: + +```nim +proc print(s: cstring) {.importcpp: "printf(@)", header: "".} + +type + Doo {.exportc.} = object + test: int + +proc memberProc(f: Doo) {.member.} = + echo $f.test + +proc destructor(f: Doo) {.member: "~'1()", used.} = + print "destructing\n" + +proc `==`(self, other: Doo): bool {.member: "operator==('2 const & #2) const -> '0".} = + self.test == other.test + +let doo = Doo(test: 2) +doo.memberProc() +echo doo == Doo(test: 1) + +``` + +Will print: +``` +2 +false +destructing +destructing +``` + +Notice how the C++ destructor is called automatically. Also notice the double implementation of `==` as an operator in Nim but also in C++. This is useful if you need the type to match some C++ `concept` or `trait` when interoping. + +A side effect of being able to declare C++ operators, is that you can now also create a +C++ functor to have seamless interop with C++ lambdas (syntactic sugar for functors). + +For example: + +```nim +type + NimFunctor = object + discard +proc invoke(f: NimFunctor; n: int) {.member: "operator ()('2 #2)".} = + echo "FunctorSupport!" + +{.experimental: "callOperator".} +proc `()`(f: NimFunctor; n:int) {.importcpp: "#(@)" .} +NimFunctor()(1) +``` +Notice we use the overload of `()` to have the same semantics in Nim, but on the `importcpp` we import the functor as a function. +This allows to easy interop with functions that accepts for example a `const` operator in its signature. \ No newline at end of file From 4c892231714fb64942b5014df0424de8fb732b73 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sat, 12 Aug 2023 19:23:54 +0800 Subject: [PATCH 436/489] relax the parameter of `ensureMove`; allow let statements (#22466) * relax the parameter of `ensureMove`; allow let statements * fixes the test --- compiler/semmagic.nim | 5 +++-- tests/system/tensuremove.nim | 3 ++- tests/system/tensuremove2.nim | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index bee2a983ed..d06b32e47a 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -667,7 +667,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode, result.typ = expectedType # type inference for empty sequence # bug #21377 of mEnsureMove: result = n - if isAssignable(c, n[1]) notin {arLValue, arLocalLValue}: - localError(c.config, n.info, "'" & $n[1] & "'" & " is not a mutable location; it cannot be moved") + if n[1].kind in {nkStmtListExpr, nkBlockExpr, + nkIfExpr, nkCaseStmt, nkTryStmt}: + localError(c.config, n.info, "Nested expressions cannot be moved: '" & $n[1] & "'") else: result = n diff --git a/tests/system/tensuremove.nim b/tests/system/tensuremove.nim index 980f2ea582..52d9a43a85 100644 --- a/tests/system/tensuremove.nim +++ b/tests/system/tensuremove.nim @@ -20,7 +20,8 @@ block: discard x.s proc main = - var x = X(s: "abcdefg") + let m = "abcdefg" + var x = X(s: ensureMove m) consume(ensureMove x) static: main() diff --git a/tests/system/tensuremove2.nim b/tests/system/tensuremove2.nim index 1fcbc1c0fa..39bbeb22e7 100644 --- a/tests/system/tensuremove2.nim +++ b/tests/system/tensuremove2.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "'if true: s else: String()' is not a mutable location; it cannot be moved" + errormsg: "Nested expressions cannot be moved: 'if true: s else: String()'" """ type From 9207d77848d6f5db3635ae64f3cd4972cdbe3296 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Sun, 13 Aug 2023 06:02:36 +0800 Subject: [PATCH 437/489] fixes bareExcept warnings; catch specific exceptions (#21119) * fixes bareExcept warnings; catch specific exceptions * Update lib/pure/coro.nim --- lib/pure/asynchttpserver.nim | 2 +- lib/std/private/osdirs.nim | 2 +- lib/std/private/osfiles.nim | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 9b369c4bc7..0638d21aac 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -381,7 +381,7 @@ const proc listen*(server: AsyncHttpServer; port: Port; address = ""; domain = AF_INET) = ## Listen to the given port and address. when declared(maxDescriptors): - server.maxFDs = try: maxDescriptors() except: nimMaxDescriptorsFallback + server.maxFDs = try: maxDescriptors() except OSError: nimMaxDescriptorsFallback else: server.maxFDs = nimMaxDescriptorsFallback server.socket = newAsyncSocket(domain) diff --git a/lib/std/private/osdirs.nim b/lib/std/private/osdirs.nim index a4318367d8..e204b25e48 100644 --- a/lib/std/private/osdirs.nim +++ b/lib/std/private/osdirs.nim @@ -515,7 +515,7 @@ proc copyDirWithPermissions*(source, dest: string, try: setFilePermissions(dest, getFilePermissions(source), followSymlinks = false) - except: + except OSError: if not ignorePermissionErrors: raise for kind, path in walkDir(source): diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim index f2e7bf11d2..69a5af1381 100644 --- a/lib/std/private/osfiles.nim +++ b/lib/std/private/osfiles.nim @@ -311,7 +311,7 @@ proc copyFileWithPermissions*(source, dest: string, try: setFilePermissions(dest, getFilePermissions(source), followSymlinks = (cfSymlinkFollow in options)) - except: + except OSError: if not ignorePermissionErrors: raise @@ -402,6 +402,6 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", copyFile(source, dest, {cfSymlinkAsIs}) try: removeFile(source) - except: + except OSError: discard tryRemoveFile(dest) raise From 9bf605cf9801673eca96057935306ddd7fafbfe9 Mon Sep 17 00:00:00 2001 From: Nan Xiao Date: Mon, 14 Aug 2023 08:44:50 +0800 Subject: [PATCH 438/489] fixes syncio document (#22467) --- lib/std/syncio.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/syncio.nim b/lib/std/syncio.nim index 77d4fa04c8..a2a5c305b6 100644 --- a/lib/std/syncio.nim +++ b/lib/std/syncio.nim @@ -38,8 +38,8 @@ type ## at the end. If the file does not exist, it ## will be created. - FileHandle* = cint ## type that represents an OS file handle; this is - ## useful for low-level file access + FileHandle* = cint ## The type that represents an OS file handle; this is + ## useful for low-level file access. FileSeekPos* = enum ## Position relative to which seek should happen. # The values are ordered so that they match with stdio From 7bb2462d06b039b70e13b68ee2b23c39a881ca26 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 14 Aug 2023 15:04:02 +0800 Subject: [PATCH 439/489] fixes CI (#22471) Revert "fixes bareExcept warnings; catch specific exceptions (#21119)" This reverts commit 9207d77848d6f5db3635ae64f3cd4972cdbe3296. --- lib/pure/asynchttpserver.nim | 2 +- lib/std/private/osdirs.nim | 2 +- lib/std/private/osfiles.nim | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 0638d21aac..9b369c4bc7 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -381,7 +381,7 @@ const proc listen*(server: AsyncHttpServer; port: Port; address = ""; domain = AF_INET) = ## Listen to the given port and address. when declared(maxDescriptors): - server.maxFDs = try: maxDescriptors() except OSError: nimMaxDescriptorsFallback + server.maxFDs = try: maxDescriptors() except: nimMaxDescriptorsFallback else: server.maxFDs = nimMaxDescriptorsFallback server.socket = newAsyncSocket(domain) diff --git a/lib/std/private/osdirs.nim b/lib/std/private/osdirs.nim index e204b25e48..a4318367d8 100644 --- a/lib/std/private/osdirs.nim +++ b/lib/std/private/osdirs.nim @@ -515,7 +515,7 @@ proc copyDirWithPermissions*(source, dest: string, try: setFilePermissions(dest, getFilePermissions(source), followSymlinks = false) - except OSError: + except: if not ignorePermissionErrors: raise for kind, path in walkDir(source): diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim index 69a5af1381..f2e7bf11d2 100644 --- a/lib/std/private/osfiles.nim +++ b/lib/std/private/osfiles.nim @@ -311,7 +311,7 @@ proc copyFileWithPermissions*(source, dest: string, try: setFilePermissions(dest, getFilePermissions(source), followSymlinks = (cfSymlinkFollow in options)) - except OSError: + except: if not ignorePermissionErrors: raise @@ -402,6 +402,6 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", copyFile(source, dest, {cfSymlinkAsIs}) try: removeFile(source) - except OSError: + except: discard tryRemoveFile(dest) raise From 09d0fda7fde69087c75a102b219d5eebf1b86db2 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 14 Aug 2023 19:08:01 +0800 Subject: [PATCH 440/489] fixes #22469; generates nimTestErrorFlag for top level statements (#22472) fixes #22469; generates `nimTestErrorFlag` for top level statements --- compiler/cgen.nim | 4 ++-- tests/exception/m22469.nim | 4 ++++ tests/exception/t22469.nim | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 tests/exception/m22469.nim create mode 100644 tests/exception/t22469.nim diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 5aafc506b2..811f899834 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1875,13 +1875,13 @@ proc genInitCode(m: BModule) = if beforeRetNeeded in m.initProc.flags: prc.add("\tBeforeRet_: ;\n") - if sfMainModule in m.module.flags and m.config.exc == excGoto: + if m.config.exc == excGoto: if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil: m.appcg(prc, "\t#nimTestErrorFlag();$n", []) if optStackTrace in m.initProc.options and preventStackTrace notin m.flags: prc.add(deinitFrame(m.initProc)) - elif sfMainModule in m.module.flags and m.config.exc == excGoto: + elif m.config.exc == excGoto: if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil: m.appcg(prc, "\t#nimTestErrorFlag();$n", []) diff --git a/tests/exception/m22469.nim b/tests/exception/m22469.nim new file mode 100644 index 0000000000..2016987015 --- /dev/null +++ b/tests/exception/m22469.nim @@ -0,0 +1,4 @@ +# ModuleB +echo "First top-level statement of ModuleB" +echo high(int) + 1 +echo "ModuleB last statement" \ No newline at end of file diff --git a/tests/exception/t22469.nim b/tests/exception/t22469.nim new file mode 100644 index 0000000000..a76c749678 --- /dev/null +++ b/tests/exception/t22469.nim @@ -0,0 +1,16 @@ +discard """ + exitcode: 1 + output: ''' +First top-level statement of ModuleB +m22469.nim(3) m22469 +fatal.nim(53) sysFatal +Error: unhandled exception: over- or underflow [OverflowDefect] +''' +""" + +# bug #22469 + +# ModuleA +import m22469 +echo "ModuleA about to have exception" +echo high(int) + 1 From 1927ae72d093d5e13bef6fd3fdf4700aa072f6bc Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Mon, 14 Aug 2023 20:00:48 +0100 Subject: [PATCH 441/489] Add Linux constant SO_BINDTODEVICE (#22468) --- lib/posix/posix_linux_amd64_consts.nim | 1 + lib/posix/posix_other_consts.nim | 1 + tools/detect/detect.nim | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim index 6ac0279fcc..fbe8d0666d 100644 --- a/lib/posix/posix_linux_amd64_consts.nim +++ b/lib/posix/posix_linux_amd64_consts.nim @@ -465,6 +465,7 @@ const MSG_EOR* = cint(128) const MSG_OOB* = cint(1) const SCM_RIGHTS* = cint(1) const SO_ACCEPTCONN* = cint(30) +const SO_BINDTODEVICE* = cint(25) const SO_BROADCAST* = cint(6) const SO_DEBUG* = cint(1) const SO_DONTROUTE* = cint(5) diff --git a/lib/posix/posix_other_consts.nim b/lib/posix/posix_other_consts.nim index f4809a9c27..d346b4150d 100644 --- a/lib/posix/posix_other_consts.nim +++ b/lib/posix/posix_other_consts.nim @@ -482,6 +482,7 @@ var MSG_EOR* {.importc: "MSG_EOR", header: "".}: cint var MSG_OOB* {.importc: "MSG_OOB", header: "".}: cint var SCM_RIGHTS* {.importc: "SCM_RIGHTS", header: "".}: cint var SO_ACCEPTCONN* {.importc: "SO_ACCEPTCONN", header: "".}: cint +var SO_BINDTODEVICE* {.importc: "SO_BINDTODEVICE", header: "".}: cint var SO_BROADCAST* {.importc: "SO_BROADCAST", header: "".}: cint var SO_DEBUG* {.importc: "SO_DEBUG", header: "".}: cint var SO_DONTROUTE* {.importc: "SO_DONTROUTE", header: "".}: cint diff --git a/tools/detect/detect.nim b/tools/detect/detect.nim index fe233420b5..ed9438494c 100644 --- a/tools/detect/detect.nim +++ b/tools/detect/detect.nim @@ -630,6 +630,7 @@ v("MSG_EOR") v("MSG_OOB") v("SCM_RIGHTS") v("SO_ACCEPTCONN") +v("SO_BINDTODEVICE") v("SO_BROADCAST") v("SO_DEBUG") v("SO_DONTROUTE") From a660c17d309e2b077c610fd8c8c697944cff676d Mon Sep 17 00:00:00 2001 From: Andrey Makarov Date: Mon, 14 Aug 2023 22:27:36 -0600 Subject: [PATCH 442/489] Markdown code blocks migration part 8 (#22478) --- lib/pure/asynchttpserver.nim | 20 +-- lib/pure/collections/sets.nim | 20 ++- lib/pure/collections/sharedtables.nim | 4 +- lib/pure/collections/tables.nim | 33 ++-- lib/pure/colors.nim | 3 +- lib/pure/distros.nim | 5 +- lib/pure/htmlgen.nim | 3 +- lib/pure/htmlparser.nim | 10 +- lib/pure/httpclient.nim | 134 ++++++++------ lib/pure/json.nim | 18 +- lib/pure/logging.nim | 57 ++++-- lib/pure/memfiles.nim | 15 +- lib/pure/options.nim | 3 +- lib/pure/os.nim | 12 +- lib/pure/osproc.nim | 30 ++-- lib/pure/parsecfg.nim | 5 +- lib/pure/parsecsv.nim | 6 +- lib/pure/parseopt.nim | 25 +-- lib/pure/parseutils.nim | 39 ++-- lib/pure/parsexml.nim | 168 +++++++++--------- lib/pure/pegs.nim | 133 +++++++------- lib/pure/selectors.nim | 10 +- lib/pure/streams.nim | 88 ++++----- lib/pure/streamwrapper.nim | 4 +- lib/pure/strformat.nim | 9 +- lib/pure/strscans.nim | 32 ++-- lib/pure/strutils.nim | 114 +++++++----- lib/pure/times.nim | 12 +- lib/pure/unittest.nim | 86 +++++---- lib/pure/xmltree.nim | 3 +- lib/std/cmdline.nim | 9 +- lib/std/private/digitsutils.nim | 3 +- lib/std/private/since.nim | 8 +- lib/std/socketstreams.nim | 57 +++--- lib/std/typedthreads.nim | 32 ++-- lib/system.nim | 6 +- lib/system/channels_builtin.nim | 6 +- lib/system/dollars.nim | 27 +-- lib/system/gc.nim | 6 +- lib/system/nimscript.nim | 40 ++--- lib/system/repr_v2.nim | 19 +- lib/wrappers/openssl.nim | 3 +- nimpretty/tests/exhaustive.nim | 10 +- nimpretty/tests/expected/exhaustive.nim | 10 +- testament/specs.nim | 13 +- .../argument_parser/argument_parser.nim | 4 +- 46 files changed, 725 insertions(+), 629 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 9b369c4bc7..07eed9a514 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -110,16 +110,16 @@ proc respond*(req: Request, code: HttpCode, content: string, ## This procedure will **not** close the client socket. ## ## Example: - ## - ## .. code-block:: Nim - ## import std/json - ## proc handler(req: Request) {.async.} = - ## if req.url.path == "/hello-world": - ## let msg = %* {"message": "Hello World"} - ## let headers = newHttpHeaders([("Content-Type","application/json")]) - ## await req.respond(Http200, $msg, headers) - ## else: - ## await req.respond(Http404, "Not Found") + ## ```Nim + ## import std/json + ## proc handler(req: Request) {.async.} = + ## if req.url.path == "/hello-world": + ## let msg = %* {"message": "Hello World"} + ## let headers = newHttpHeaders([("Content-Type","application/json")]) + ## await req.respond(Http200, $msg, headers) + ## else: + ## await req.respond(Http404, "Not Found") + ## ``` var msg = "HTTP/1.1 " & $code & "\c\L" if headers != nil: diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 7e193af1a7..62abd68d44 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -25,7 +25,9 @@ ## `difference <#difference,HashSet[A],HashSet[A]>`_, and ## `symmetric difference <#symmetricDifference,HashSet[A],HashSet[A]>`_ ## -## .. code-block:: +## **Examples:** +## +## ```Nim ## echo toHashSet([9, 5, 1]) # {9, 1, 5} ## echo toOrderedSet([9, 5, 1]) # {9, 5, 1} ## @@ -37,7 +39,7 @@ ## echo s1 - s2 # {1, 9} ## echo s1 * s2 # {5} ## echo s1 -+- s2 # {9, 1, 3, 7} -## +## ``` ## ## Note: The data types declared here have *value semantics*: This means ## that `=` performs a copy of the set. @@ -249,7 +251,7 @@ iterator items*[A](s: HashSet[A]): A = ## If you need a sequence with the elements you can use `sequtils.toSeq ## template `_. ## - ## .. code-block:: + ## ```Nim ## type ## pair = tuple[a, b: int] ## var @@ -262,6 +264,7 @@ iterator items*[A](s: HashSet[A]): A = ## assert a.len == 2 ## echo b ## # --> {(a: 1, b: 3), (a: 0, b: 4)} + ## ``` let length = s.len for h in 0 .. high(s.data): if isFilled(s.data[h].hcode): @@ -586,12 +589,12 @@ proc `$`*[A](s: HashSet[A]): string = ## any moment and values are not escaped. ## ## **Examples:** - ## - ## .. code-block:: + ## ```Nim ## echo toHashSet([2, 4, 5]) ## # --> {2, 4, 5} ## echo toHashSet(["no", "esc'aping", "is \" provided"]) ## # --> {no, esc'aping, is " provided} + ## ``` dollarImpl() @@ -874,12 +877,12 @@ proc `$`*[A](s: OrderedSet[A]): string = ## any moment and values are not escaped. ## ## **Examples:** - ## - ## .. code-block:: + ## ```Nim ## echo toOrderedSet([2, 4, 5]) ## # --> {2, 4, 5} ## echo toOrderedSet(["no", "esc'aping", "is \" provided"]) ## # --> {no, esc'aping, is " provided} + ## ``` dollarImpl() @@ -890,7 +893,7 @@ iterator items*[A](s: OrderedSet[A]): A = ## If you need a sequence with the elements you can use `sequtils.toSeq ## template `_. ## - ## .. code-block:: + ## ```Nim ## var a = initOrderedSet[int]() ## for value in [9, 2, 1, 5, 1, 8, 4, 2]: ## a.incl(value) @@ -902,6 +905,7 @@ iterator items*[A](s: OrderedSet[A]): A = ## # --> Got 5 ## # --> Got 8 ## # --> Got 4 + ## ``` let length = s.len forAllOrderedPairs: yield s.data[h].key diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim index 816ab49abb..8b49066aca 100644 --- a/lib/pure/collections/sharedtables.nim +++ b/lib/pure/collections/sharedtables.nim @@ -191,8 +191,7 @@ proc withKey*[A, B](t: var SharedTable[A, B], key: A, ## ## Example usage: ## - ## .. code-block:: nim - ## + ## ```nim ## # If value exists, decrement it. ## # If it becomes zero or less, delete the key ## t.withKey(1'i64) do (k: int64, v: var int, pairExists: var bool): @@ -200,6 +199,7 @@ proc withKey*[A, B](t: var SharedTable[A, B], key: A, ## dec v ## if v <= 0: ## pairExists = false + ## ``` withLock t: var hc: Hash var index = rawGet(t, key, hc) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index d4056897db..39dcddb5a9 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -136,14 +136,11 @@ runnableExamples: ## a more complex object as a key you will be greeted by a strange compiler ## error: ## -## .. code:: -## -## Error: type mismatch: got (Person) -## but expected one of: -## hashes.hash(x: openArray[A]): Hash -## hashes.hash(x: int): Hash -## hashes.hash(x: float): Hash -## … +## Error: type mismatch: got (Person) +## but expected one of: +## hashes.hash(x: openArray[A]): Hash +## hashes.hash(x: int): Hash +## hashes.hash(x: float): Hash ## ## What is happening here is that the types used for table keys require to have ## a `hash()` proc which will convert them to a `Hash `_ @@ -678,7 +675,7 @@ iterator pairs*[A, B](t: Table[A, B]): (A, B) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## let a = { ## 'o': [1, 5, 7, 9], ## 'e': [2, 4, 6, 8] @@ -692,6 +689,7 @@ iterator pairs*[A, B](t: Table[A, B]): (A, B) = ## # value: [2, 4, 6, 8] ## # key: o ## # value: [1, 5, 7, 9] + ## ``` let L = len(t) for h in 0 .. high(t.data): if isFilled(t.data[h].hcode): @@ -1127,7 +1125,7 @@ iterator pairs*[A, B](t: TableRef[A, B]): (A, B) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## let a = { ## 'o': [1, 5, 7, 9], ## 'e': [2, 4, 6, 8] @@ -1141,6 +1139,7 @@ iterator pairs*[A, B](t: TableRef[A, B]): (A, B) = ## # value: [2, 4, 6, 8] ## # key: o ## # value: [1, 5, 7, 9] + ## ``` let L = len(t) for h in 0 .. high(t.data): if isFilled(t.data[h].hcode): @@ -1703,7 +1702,7 @@ iterator pairs*[A, B](t: OrderedTable[A, B]): (A, B) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## let a = { ## 'o': [1, 5, 7, 9], ## 'e': [2, 4, 6, 8] @@ -1717,6 +1716,7 @@ iterator pairs*[A, B](t: OrderedTable[A, B]): (A, B) = ## # value: [1, 5, 7, 9] ## # key: e ## # value: [2, 4, 6, 8] + ## ``` let L = len(t) forAllOrderedPairs: @@ -2113,7 +2113,7 @@ iterator pairs*[A, B](t: OrderedTableRef[A, B]): (A, B) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## let a = { ## 'o': [1, 5, 7, 9], ## 'e': [2, 4, 6, 8] @@ -2127,6 +2127,7 @@ iterator pairs*[A, B](t: OrderedTableRef[A, B]): (A, B) = ## # value: [1, 5, 7, 9] ## # key: e ## # value: [2, 4, 6, 8] + ## ``` let L = len(t) forAllOrderedPairs: @@ -2526,7 +2527,7 @@ iterator pairs*[A](t: CountTable[A]): (A, int) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## let a = toCountTable("abracadabra") ## ## for k, v in pairs(a): @@ -2543,6 +2544,7 @@ iterator pairs*[A](t: CountTable[A]): (A, int) = ## # value: 1 ## # key: r ## # value: 2 + ## ``` let L = len(t) for h in 0 .. high(t.data): if t.data[h].val != 0: @@ -2806,7 +2808,7 @@ iterator pairs*[A](t: CountTableRef[A]): (A, int) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## let a = newCountTable("abracadabra") ## ## for k, v in pairs(a): @@ -2823,6 +2825,7 @@ iterator pairs*[A](t: CountTableRef[A]): (A, int) = ## # value: 1 ## # key: r ## # value: 2 + ## ``` let L = len(t) for h in 0 .. high(t.data): if t.data[h].val != 0: @@ -2915,4 +2918,4 @@ proc hash*[K,V](s: OrderedTable[K,V]): Hash = proc hash*[V](s: CountTable[V]): Hash = for p in pairs(s): result = result xor hash(p) - result = !$result \ No newline at end of file + result = !$result diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index 685b68b360..eccccbfafc 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -18,13 +18,14 @@ type proc `==`*(a, b: Color): bool {.borrow.} ## Compares two colors. ## - ## .. code-block:: + ## ```Nim ## var ## a = Color(0xff_00_ff) ## b = colFuchsia ## c = Color(0x00_ff_cc) ## assert a == b ## assert not (a == c) + ## ``` template extract(a: Color, r, g, b: untyped) = var r = a.int shr 16 and 0xff diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim index 25c961197b..58eacf6334 100644 --- a/lib/pure/distros.nim +++ b/lib/pure/distros.nim @@ -18,12 +18,11 @@ ## ## The above output could be the result of a code snippet like: ## -## .. code-block:: nim -## +## ```nim ## if detectOs(Ubuntu): ## foreignDep "lbiblas-dev" ## foreignDep "libvoodoo" -## +## ``` ## ## See `packaging `_ for hints on distributing Nim using OS packages. diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index bf31c02397..be9e1fe90f 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -30,9 +30,10 @@ ## Examples ## ======== ## -## .. code-block:: Nim +## ```Nim ## var nim = "Nim" ## echo h1(a(href="https://nim-lang.org", nim)) +## ``` ## ## Writes the string: ## diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index 24eab3abb9..0de384a8e6 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -12,10 +12,9 @@ ## ## It can be used to parse a wild HTML document and output it as valid XHTML ## document (well, if you are lucky): -## -## .. code-block:: Nim -## +## ```Nim ## echo loadHtml("mydirty.html") +## ``` ## ## Every tag in the resulting tree is in lower case. ## @@ -29,9 +28,7 @@ ## and write back the modified version. In this case we look for hyperlinks ## ending with the extension `.rst` and convert them to `.html`. ## -## .. code-block:: Nim -## :test: -## +## ```Nim test ## import std/htmlparser ## import std/xmltree # To use '$' for XmlNode ## import std/strtabs # To access XmlAttributes @@ -48,6 +45,7 @@ ## a.attrs["href"] = dir / filename & ".html" ## ## writeFile("output.html", $html) +## ``` import strutils, streams, parsexml, xmltree, unicode, strtabs diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index fd0ef38564..ddf208e4e3 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -18,18 +18,19 @@ ## This example uses HTTP GET to retrieve ## `http://google.com`: ## -## .. code-block:: Nim +## ```Nim ## import std/httpclient ## var client = newHttpClient() ## try: ## echo client.getContent("http://google.com") ## finally: ## client.close() +## ``` ## ## The same action can also be performed asynchronously, simply use the ## `AsyncHttpClient`: ## -## .. code-block:: Nim +## ```Nim ## import std/[asyncdispatch, httpclient] ## ## proc asyncProc(): Future[string] {.async.} = @@ -40,6 +41,7 @@ ## client.close() ## ## echo waitFor asyncProc() +## ``` ## ## The functionality implemented by `HttpClient` and `AsyncHttpClient` ## is the same, so you can use whichever one suits you best in the examples @@ -59,7 +61,7 @@ ## uses `multipart/form-data` as the `Content-Type` to send the HTML to be ## validated to the server. ## -## .. code-block:: Nim +## ```Nim ## var client = newHttpClient() ## var data = newMultipartData() ## data["output"] = "soap12" @@ -69,13 +71,14 @@ ## echo client.postContent("http://validator.w3.org/check", multipart=data) ## finally: ## client.close() +## ``` ## ## To stream files from disk when performing the request, use `addFiles`. ## ## **Note:** This will allocate a new `Mimetypes` database every time you call ## it, you can pass your own via the `mimeDb` parameter to avoid this. ## -## .. code-block:: Nim +## ```Nim ## let mimes = newMimetypes() ## var client = newHttpClient() ## var data = newMultipartData() @@ -84,12 +87,13 @@ ## echo client.postContent("http://validator.w3.org/check", multipart=data) ## finally: ## client.close() +## ``` ## ## You can also make post requests with custom headers. ## This example sets `Content-Type` to `application/json` ## and uses a json object for the body ## -## .. code-block:: Nim +## ```Nim ## import std/[httpclient, json] ## ## let client = newHttpClient() @@ -102,6 +106,7 @@ ## echo response.status ## finally: ## client.close() +## ``` ## ## Progress reporting ## ================== @@ -110,27 +115,29 @@ ## This callback will be executed every second with information about the ## progress of the HTTP request. ## -## .. code-block:: Nim -## import std/[asyncdispatch, httpclient] +## ```Nim +## import std/[asyncdispatch, httpclient] ## -## proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} = -## echo("Downloaded ", progress, " of ", total) -## echo("Current rate: ", speed div 1000, "kb/s") +## proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} = +## echo("Downloaded ", progress, " of ", total) +## echo("Current rate: ", speed div 1000, "kb/s") ## -## proc asyncProc() {.async.} = -## var client = newAsyncHttpClient() -## client.onProgressChanged = onProgressChanged -## try: -## discard await client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test") -## finally: -## client.close() +## proc asyncProc() {.async.} = +## var client = newAsyncHttpClient() +## client.onProgressChanged = onProgressChanged +## try: +## discard await client.getContent("http://speedtest-ams2.digitalocean.com/100mb.test") +## finally: +## client.close() ## -## waitFor asyncProc() +## waitFor asyncProc() +## ``` ## ## If you would like to remove the callback simply set it to `nil`. ## -## .. code-block:: Nim +## ```Nim ## client.onProgressChanged = nil +## ``` ## ## .. warning:: The `total` reported by httpclient may be 0 in some cases. ## @@ -152,9 +159,10 @@ ## ## Example of setting SSL verification parameters in a new client: ## -## .. code-block:: Nim -## import httpclient -## var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer)) +## ```Nim +## import httpclient +## var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer)) +## ``` ## ## There are three options for verify mode: ## @@ -183,10 +191,11 @@ ## ## Here is how to set a timeout when creating an `HttpClient` instance: ## -## .. code-block:: Nim -## import std/httpclient +## ```Nim +## import std/httpclient ## -## let client = newHttpClient(timeout = 42) +## let client = newHttpClient(timeout = 42) +## ``` ## ## Proxy ## ===== @@ -197,36 +206,39 @@ ## ## Some examples on how to configure a Proxy for `HttpClient`: ## -## .. code-block:: Nim -## import std/httpclient +## ```Nim +## import std/httpclient ## -## let myProxy = newProxy("http://myproxy.network") -## let client = newHttpClient(proxy = myProxy) +## let myProxy = newProxy("http://myproxy.network") +## let client = newHttpClient(proxy = myProxy) +## ``` ## ## Use proxies with basic authentication: ## -## .. code-block:: Nim -## import std/httpclient -## -## let myProxy = newProxy("http://myproxy.network", auth="user:password") -## let client = newHttpClient(proxy = myProxy) +## ```Nim +## import std/httpclient +## +## let myProxy = newProxy("http://myproxy.network", auth="user:password") +## let client = newHttpClient(proxy = myProxy) +## ``` ## ## Get Proxy URL from environment variables: ## -## .. code-block:: Nim -## import std/httpclient +## ```Nim +## import std/httpclient ## -## var url = "" -## try: -## if existsEnv("http_proxy"): -## url = getEnv("http_proxy") -## elif existsEnv("https_proxy"): -## url = getEnv("https_proxy") -## except ValueError: -## echo "Unable to parse proxy from environment variables." +## var url = "" +## try: +## if existsEnv("http_proxy"): +## url = getEnv("http_proxy") +## elif existsEnv("https_proxy"): +## url = getEnv("https_proxy") +## except ValueError: +## echo "Unable to parse proxy from environment variables." ## -## let myProxy = newProxy(url = url) -## let client = newHttpClient(proxy = myProxy) +## let myProxy = newProxy(url = url) +## let client = newHttpClient(proxy = myProxy) +## ``` ## ## Redirects ## ========= @@ -237,10 +249,11 @@ ## ## Here you can see an example about how to set the `maxRedirects` of `HttpClient`: ## -## .. code-block:: Nim -## import std/httpclient +## ```Nim +## import std/httpclient ## -## let client = newHttpClient(maxRedirects = 0) +## let client = newHttpClient(maxRedirects = 0) +## ``` ## import std/private/since @@ -429,8 +442,9 @@ proc add*(p: MultipartData, xs: MultipartEntries): MultipartData ## Add a list of multipart entries to the multipart data `p`. All values are ## added without a filename and without a content type. ## - ## .. code-block:: Nim + ## ```Nim ## data.add({"action": "login", "format": "json"}) + ## ``` for name, content in xs.items: p.add(name, content) result = p @@ -439,8 +453,9 @@ proc newMultipartData*(xs: MultipartEntries): MultipartData = ## Create a new multipart data object and fill it with the entries `xs` ## directly. ## - ## .. code-block:: Nim + ## ```Nim ## var data = newMultipartData({"action": "login", "format": "json"}) + ## ``` result = MultipartData() for entry in xs: result.add(entry.name, entry.content) @@ -455,8 +470,9 @@ proc addFiles*(p: MultipartData, xs: openArray[tuple[name, file: string]], ## Raises an `IOError` if the file cannot be opened or reading fails. To ## manually specify file content, filename and MIME type, use `[]=` instead. ## - ## .. code-block:: Nim + ## ```Nim ## data.addFiles({"uploaded_file": "public/test.html"}) + ## ``` for name, file in xs.items: var contentType: string let (_, fName, ext) = splitFile(file) @@ -470,8 +486,9 @@ proc `[]=`*(p: MultipartData, name, content: string) {.inline.} = ## Add a multipart entry to the multipart data `p`. The value is added ## without a filename and without a content type. ## - ## .. code-block:: Nim + ## ```Nim ## data["username"] = "NimUser" + ## ``` p.add(name, content) proc `[]=`*(p: MultipartData, name: string, @@ -479,9 +496,10 @@ proc `[]=`*(p: MultipartData, name: string, ## Add a file to the multipart data `p`, specifying filename, contentType ## and content manually. ## - ## .. code-block:: Nim + ## ```Nim ## data["uploaded_file"] = ("test.html", "text/html", ## "

      test

      ") + ## ``` p.add(name, file.content, file.name, file.contentType, useStream = false) proc getBoundary(p: MultipartData): string = @@ -688,15 +706,15 @@ proc close*(client: HttpClient | AsyncHttpClient) = client.connected = false proc getSocket*(client: HttpClient): Socket {.inline.} = - ## Get network socket, useful if you want to find out more details about the connection + ## Get network socket, useful if you want to find out more details about the connection. ## - ## this example shows info about local and remote endpoints + ## This example shows info about local and remote endpoints: ## - ## .. code-block:: Nim + ## ```Nim ## if client.connected: ## echo client.getSocket.getLocalAddr ## echo client.getSocket.getPeerAddr - ## + ## ``` return client.socket proc getSocket*(client: AsyncHttpClient): AsyncSocket {.inline.} = diff --git a/lib/pure/json.nim b/lib/pure/json.nim index fcb9eae41b..8c1f19fd34 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -41,13 +41,14 @@ ## For a `JsonNode` who's kind is `JObject`, you can access its fields using ## the `[]` operator. The following example shows how to do this: ## -## .. code-block:: Nim +## ```Nim ## import std/json ## ## let jsonNode = parseJson("""{"key": 3.14}""") ## ## doAssert jsonNode.kind == JObject ## doAssert jsonNode["key"].kind == JFloat +## ``` ## ## Reading values ## -------------- @@ -62,12 +63,13 @@ ## ## To retrieve the value of `"key"` you can do the following: ## -## .. code-block:: Nim +## ```Nim ## import std/json ## ## let jsonNode = parseJson("""{"key": 3.14}""") ## ## doAssert jsonNode["key"].getFloat() == 3.14 +## ``` ## ## **Important:** The `[]` operator will raise an exception when the ## specified field does not exist. @@ -79,7 +81,7 @@ ## when the field is not found. The `get`-family of procedures will return a ## type's default value when called on `nil`. ## -## .. code-block:: Nim +## ```Nim ## import std/json ## ## let jsonNode = parseJson("{}") @@ -88,6 +90,7 @@ ## doAssert jsonNode{"nope"}.getFloat() == 0 ## doAssert jsonNode{"nope"}.getStr() == "" ## doAssert jsonNode{"nope"}.getBool() == false +## ``` ## ## Using default values ## -------------------- @@ -95,7 +98,7 @@ ## The `get`-family helpers also accept an additional parameter which allow ## you to fallback to a default value should the key's values be `null`: ## -## .. code-block:: Nim +## ```Nim ## import std/json ## ## let jsonNode = parseJson("""{"key": 3.14, "key2": null}""") @@ -103,6 +106,7 @@ ## doAssert jsonNode["key"].getFloat(6.28) == 3.14 ## doAssert jsonNode["key2"].getFloat(3.14) == 3.14 ## doAssert jsonNode{"nope"}.getFloat(3.14) == 3.14 # note the {} +## ``` ## ## Unmarshalling ## ------------- @@ -113,7 +117,7 @@ ## Note: Use `Option `_ for keys sometimes missing in json ## responses, and backticks around keys with a reserved keyword as name. ## -## .. code-block:: Nim +## ```Nim ## import std/json ## import std/options ## @@ -127,6 +131,7 @@ ## let user = to(userJson, User) ## if user.`type`.isSome(): ## assert user.`type`.get() != "robot" +## ``` ## ## Creating JSON ## ============= @@ -134,7 +139,7 @@ ## This module can also be used to comfortably create JSON using the `%*` ## operator: ## -## .. code-block:: nim +## ```nim ## import std/json ## ## var hisName = "John" @@ -148,6 +153,7 @@ ## var j2 = %* {"name": "Isaac", "books": ["Robot Dreams"]} ## j2["details"] = %* {"age":35, "pi":3.1415} ## echo j2 +## ``` ## ## See also: std/jsonutils for hookable json serialization/deserialization ## of arbitrary types. diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 46b59b750f..1767ee3f68 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -17,10 +17,11 @@ ## ## To get started, first create a logger: ## -## .. code-block:: +## ```Nim ## import std/logging ## ## var logger = newConsoleLogger() +## ``` ## ## The logger that was created above logs to the console, but this module ## also provides loggers that log to files, such as the @@ -30,9 +31,10 @@ ## Once a logger has been created, call its `log proc ## <#log.e,ConsoleLogger,Level,varargs[string,]>`_ to log a message: ## -## .. code-block:: +## ```Nim ## logger.log(lvlInfo, "a log message") ## # Output: INFO a log message +## ``` ## ## The ``INFO`` within the output is the result of a format string being ## prepended to the message, and it will differ depending on the message's @@ -58,7 +60,7 @@ ## used with the `addHandler proc<#addHandler,Logger>`_, which is demonstrated ## in the following example: ## -## .. code-block:: +## ```Nim ## import std/logging ## ## var consoleLog = newConsoleLogger() @@ -68,17 +70,19 @@ ## addHandler(consoleLog) ## addHandler(fileLog) ## addHandler(rollingLog) +## ``` ## ## After doing this, use either the `log template ## <#log.t,Level,varargs[string,]>`_ or one of the level-specific templates, ## such as the `error template<#error.t,varargs[string,]>`_, to log messages ## to all registered handlers at once. ## -## .. code-block:: +## ```Nim ## # This example uses the loggers created above ## log(lvlError, "an error occurred") ## error("an error occurred") # Equivalent to the above line ## info("something normal happened") # Will not be written to errors.log +## ``` ## ## Note that a message's level is still checked against each handler's ## ``levelThreshold`` and the global log filter. @@ -116,12 +120,13 @@ ## ## The following example illustrates how to use format strings: ## -## .. code-block:: +## ```Nim ## import std/logging ## ## var logger = newConsoleLogger(fmtStr="[$time] - $levelname: ") ## logger.log(lvlInfo, "this is a message") ## # Output: [19:50:13] - INFO: this is a message +## ``` ## ## Notes when using multiple threads ## --------------------------------- @@ -372,10 +377,11 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var consoleLog = newConsoleLogger() ## consoleLog.log(lvlInfo, "this is a message") ## consoleLog.log(lvlError, "error code is: ", 404) + ## ``` if level >= logging.level and level >= logger.levelThreshold: let ln = substituteLog(logger.fmtStr, level, args) when defined(js): @@ -414,10 +420,11 @@ proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr, ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var normalLog = newConsoleLogger() ## var formatLog = newConsoleLogger(fmtStr=verboseFmtStr) ## var errorLog = newConsoleLogger(levelThreshold=lvlError, useStderr=true) + ## ``` new result result.fmtStr = fmtStr result.levelThreshold = levelThreshold @@ -450,10 +457,11 @@ when not defined(js): ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var fileLog = newFileLogger("messages.log") ## fileLog.log(lvlInfo, "this is a message") ## fileLog.log(lvlError, "error code is: ", 404) + ## ``` if level >= logging.level and level >= logger.levelThreshold: writeLine(logger.file, substituteLog(logger.fmtStr, level, args)) if level >= logger.flushThreshold: flushFile(logger.file) @@ -481,7 +489,7 @@ when not defined(js): ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var messages = open("messages.log", fmWrite) ## var formatted = open("formatted.log", fmWrite) ## var errors = open("errors.log", fmWrite) @@ -489,6 +497,7 @@ when not defined(js): ## var normalLog = newFileLogger(messages) ## var formatLog = newFileLogger(formatted, fmtStr=verboseFmtStr) ## var errorLog = newFileLogger(errors, levelThreshold=lvlError) + ## ``` new(result) result.file = file result.levelThreshold = levelThreshold @@ -519,10 +528,11 @@ when not defined(js): ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var normalLog = newFileLogger("messages.log") ## var formatLog = newFileLogger("formatted.log", fmtStr=verboseFmtStr) ## var errorLog = newFileLogger("errors.log", levelThreshold=lvlError) + ## ``` let file = open(filename, mode, bufSize = bufSize) newFileLogger(file, levelThreshold, fmtStr, flushThreshold) @@ -579,11 +589,12 @@ when not defined(js): ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var normalLog = newRollingFileLogger("messages.log") ## var formatLog = newRollingFileLogger("formatted.log", fmtStr=verboseFmtStr) ## var shortLog = newRollingFileLogger("short.log", maxLines=200) ## var errorLog = newRollingFileLogger("errors.log", levelThreshold=lvlError) + ## ``` new(result) result.levelThreshold = levelThreshold result.fmtStr = fmtStr @@ -633,10 +644,11 @@ when not defined(js): ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var rollingLog = newRollingFileLogger("messages.log") ## rollingLog.log(lvlInfo, "this is a message") ## rollingLog.log(lvlError, "error code is: ", 404) + ## ``` if level >= logging.level and level >= logger.levelThreshold: if logger.curLine >= logger.maxLines: logger.file.close() @@ -666,11 +678,12 @@ template log*(level: Level, args: varargs[string, `$`]) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var logger = newConsoleLogger() ## addHandler(logger) ## ## log(lvlInfo, "This is an example.") + ## ``` ## ## See also: ## * `debug template<#debug.t,varargs[string,]>`_ @@ -695,11 +708,12 @@ template debug*(args: varargs[string, `$`]) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var logger = newConsoleLogger() ## addHandler(logger) ## ## debug("myProc called with arguments: foo, 5") + ## ``` ## ## See also: ## * `log template<#log.t,Level,varargs[string,]>`_ @@ -716,11 +730,12 @@ template info*(args: varargs[string, `$`]) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var logger = newConsoleLogger() ## addHandler(logger) ## ## info("Application started successfully.") + ## ``` ## ## See also: ## * `log template<#log.t,Level,varargs[string,]>`_ @@ -737,11 +752,12 @@ template notice*(args: varargs[string, `$`]) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var logger = newConsoleLogger() ## addHandler(logger) ## ## notice("An important operation has completed.") + ## ``` ## ## See also: ## * `log template<#log.t,Level,varargs[string,]>`_ @@ -757,11 +773,12 @@ template warn*(args: varargs[string, `$`]) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var logger = newConsoleLogger() ## addHandler(logger) ## ## warn("The previous operation took too long to process.") + ## ``` ## ## See also: ## * `log template<#log.t,Level,varargs[string,]>`_ @@ -779,11 +796,12 @@ template error*(args: varargs[string, `$`]) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var logger = newConsoleLogger() ## addHandler(logger) ## ## error("An exception occurred while processing the form.") + ## ``` ## ## See also: ## * `log template<#log.t,Level,varargs[string,]>`_ @@ -800,11 +818,12 @@ template fatal*(args: varargs[string, `$`]) = ## ## **Examples:** ## - ## .. code-block:: + ## ```Nim ## var logger = newConsoleLogger() ## addHandler(logger) ## ## fatal("Can't open database -- exiting.") + ## ``` ## ## See also: ## * `log template<#log.t,Level,varargs[string,]>`_ diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 74065bc2e8..e27f9a79c3 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -150,7 +150,7 @@ proc open*(filename: string, mode: FileMode = fmRead, ## ## Example: ## - ## .. code-block:: nim + ## ```nim ## var ## mm, mm_full, mm_half: MemFile ## @@ -162,6 +162,7 @@ proc open*(filename: string, mode: FileMode = fmRead, ## ## # Read the first 512 bytes ## mm_half = memfiles.open("/tmp/test.mmap", mode = fmReadWrite, mappedSize = 512) + ## ``` # The file can be resized only when write mode is used: if mode == fmAppend: @@ -443,13 +444,13 @@ iterator memSlices*(mfile: MemFile, delim = '\l', eat = '\r'): MemSlice {.inline ## functions, not str* functions). ## ## Example: - ## - ## .. code-block:: nim + ## ```nim ## var count = 0 ## for slice in memSlices(memfiles.open("foo")): ## if slice.size > 0 and cast[cstring](slice.data)[0] != '#': ## inc(count) ## echo count + ## ``` proc c_memchr(cstr: pointer, c: char, n: csize_t): pointer {. importc: "memchr", header: "".} @@ -479,11 +480,11 @@ iterator lines*(mfile: MemFile, buf: var string, delim = '\l', ## <#memSlices.i,MemFile,char,char>`_, but Nim strings are returned. ## ## Example: - ## - ## .. code-block:: nim + ## ```nim ## var buffer: string = "" ## for line in lines(memfiles.open("foo"), buffer): ## echo line + ## ``` for ms in memSlices(mfile, delim, eat): setLen(buf, ms.size) @@ -498,10 +499,10 @@ iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): string {.inline.} = ## <#memSlices.i,MemFile,char,char>`_, but Nim strings are returned. ## ## Example: - ## - ## .. code-block:: nim + ## ```nim ## for line in lines(memfiles.open("foo")): ## echo line + ## ``` var buf = newStringOfCap(80) for line in lines(mfile, buf, delim, eat): diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 9dc4e096b3..ec384ceb4b 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -53,7 +53,7 @@ Pattern matching supports pattern matching on `Option`s, with the `Some()` and `None()` patterns. -.. code-block:: nim + ```nim {.experimental: "caseStmtMacros".} import fusion/matching @@ -65,6 +65,7 @@ supports pattern matching on `Option`s, with the `Some()` and assert false assertMatch(some(some(none(int))), Some(Some(None()))) + ``` ]## # xxx pending https://github.com/timotheecour/Nim/issues/376 use `runnableExamples` and `whichModule` diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 13c6d6113a..77dc3ca8f8 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -411,9 +411,9 @@ proc execShellCmd*(command: string): int {.rtl, extern: "nos$1", ## `_. ## ## **Examples:** - ## - ## .. code-block:: + ## ```Nim ## discard execShellCmd("ls -la") + ## ``` result = exitStatusLikeShell(c_system(command)) proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", @@ -482,18 +482,18 @@ proc inclFilePermissions*(filename: string, permissions: set[FilePermission]) {. rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noWeirdTarget.} = ## A convenience proc for: - ## - ## .. code-block:: nim + ## ```nim ## setFilePermissions(filename, getFilePermissions(filename)+permissions) + ## ``` setFilePermissions(filename, getFilePermissions(filename)+permissions) proc exclFilePermissions*(filename: string, permissions: set[FilePermission]) {. rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noWeirdTarget.} = ## A convenience proc for: - ## - ## .. code-block:: nim + ## ```nim ## setFilePermissions(filename, getFilePermissions(filename)-permissions) + ## ``` setFilePermissions(filename, getFilePermissions(filename)-permissions) when not weirdTarget and (defined(freebsd) or defined(dragonfly) or defined(netbsd)): diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 91c45e0539..b8dd153f24 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -91,12 +91,12 @@ proc execProcess*(command: string, workingDir: string = "", ## * `execCmd proc <#execCmd,string>`_ ## ## Example: - ## - ## .. code-block:: Nim - ## let outp = execProcess("nim", args=["c", "-r", "mytestfile.nim"], options={poUsePath}) - ## let outp_shell = execProcess("nim c -r mytestfile.nim") - ## # Note: outp may have an interleave of text from the nim compile - ## # and any output from mytestfile when it runs + ## ```Nim + ## let outp = execProcess("nim", args=["c", "-r", "mytestfile.nim"], options={poUsePath}) + ## let outp_shell = execProcess("nim c -r mytestfile.nim") + ## # Note: outp may have an interleave of text from the nim compile + ## # and any output from mytestfile when it runs + ## ``` proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadIOEffect, RootEffect].} @@ -113,9 +113,9 @@ proc execCmd*(command: string): int {.rtl, extern: "nosp$1", ## <#execProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_ ## ## Example: - ## - ## .. code-block:: Nim - ## let errC = execCmd("nim c -r mytestfile.nim") + ## ```Nim + ## let errC = execCmd("nim c -r mytestfile.nim") + ## ``` proc startProcess*(command: string, workingDir: string = "", args: openArray[string] = [], env: StringTableRef = nil, @@ -465,8 +465,7 @@ iterator lines*(p: Process, keepNewLines = false): string {.since: (1, 3), raise ## * `readLines proc <#readLines,Process>`_ ## ## Example: - ## - ## .. code-block:: Nim + ## ```Nim ## const opts = {poUsePath, poDaemon, poStdErrToStdOut} ## var ps: seq[Process] ## for prog in ["a", "b"]: # run 2 progs in parallel @@ -478,6 +477,7 @@ iterator lines*(p: Process, keepNewLines = false): string {.since: (1, 3), raise ## i.inc ## if i > 100: break ## p.close + ## ``` var outp = p.outputStream var line = newStringOfCap(120) while outp.readLine(line): @@ -495,8 +495,7 @@ proc readLines*(p: Process): (seq[string], int) {.since: (1, 3), ## * `lines iterator <#lines.i,Process>`_ ## ## Example: - ## - ## .. code-block:: Nim + ## ```Nim ## const opts = {poUsePath, poDaemon, poStdErrToStdOut} ## var ps: seq[Process] ## for prog in ["a", "b"]: # run 2 progs in parallel @@ -506,6 +505,7 @@ proc readLines*(p: Process): (seq[string], int) {.since: (1, 3), ## if exCode != 0: ## for line in lines: echo line ## p.close + ## ``` for line in p.lines: result[0].add(line) result[1] = p.peekExitCode @@ -1587,8 +1587,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { ## <#execProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_ ## ## Example: - ## - ## .. code-block:: Nim + ## ```Nim ## var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") ## import std/[strutils, strtabs] ## stripLineEnd(result[0]) ## portable way to remove trailing newline, if any @@ -1597,6 +1596,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { ## when defined(posix): ## assert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0) ## assert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0) + ## ``` when (NimMajor, NimMinor, NimPatch) < (1, 3, 5): doAssert input.len == 0 diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 54584a2536..3ba62ebd14 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -45,9 +45,7 @@ runnableExamples("-r:off"): ## Configuration file example ]## -## -## .. code-block:: nim -## +## ```none ## charset = "utf-8" ## [Package] ## name = "hello" @@ -55,6 +53,7 @@ runnableExamples("-r:off"): ## [Author] ## name = "nim-lang" ## website = "nim-lang.org" +## ``` ##[ ## Creating a configuration file diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim index a8d1cfaabc..dcd486c089 100644 --- a/lib/pure/parsecsv.nim +++ b/lib/pure/parsecsv.nim @@ -13,7 +13,7 @@ ## Basic usage ## =========== ## -## .. code-block:: nim +## ```nim ## import std/parsecsv ## from std/os import paramStr ## from std/streams import newFileStream @@ -29,11 +29,12 @@ ## for val in items(x.row): ## echo "##", val, "##" ## close(x) +## ``` ## ## For CSV files with a header row, the header can be read and then used as a ## reference for item access with `rowEntry <#rowEntry,CsvParser,string>`_: ## -## .. code-block:: nim +## ```nim ## import std/parsecsv ## ## # Prepare a file @@ -52,6 +53,7 @@ ## for col in items(p.headers): ## echo "##", col, ":", p.rowEntry(col), "##" ## p.close() +## ``` ## ## See also ## ======== diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index 2d039f1e4a..6674a7272a 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -48,7 +48,7 @@ ## ## Here is an example: ## -## .. code-block:: +## ```Nim ## import std/parseopt ## ## var p = initOptParser("-ab -e:5 --foo --bar=20 file.txt") @@ -71,6 +71,7 @@ ## # Option: foo ## # Option and value: bar, 20 ## # Argument: file.txt +## ``` ## ## The `getopt iterator<#getopt.i,OptParser>`_, which is provided for ## convenience, can be used to iterate through all command line options as well. @@ -80,7 +81,8 @@ ## Then set the variable to the new value while parsing. ## ## Here is an example: -## .. code-block:: +## +## ```Nim ## import std/parseopt ## ## var varName: string = "defaultValue" @@ -95,6 +97,7 @@ ## varName = val # do input sanitization in production systems ## of cmdEnd: ## discard +## ``` ## ## `shortNoVal` and `longNoVal` ## ============================ @@ -119,7 +122,7 @@ ## `shortNoVal` and `longNoVal`, which is the default, and providing ## arguments for those two parameters: ## -## .. code-block:: +## ```Nim ## import std/parseopt ## ## proc printToken(kind: CmdLineKind, key: string, val: string) = @@ -153,6 +156,7 @@ ## # Output: ## # Option and value: j, 4 ## # Option and value: first, bar +## ``` ## ## See also ## ======== @@ -387,14 +391,14 @@ when declared(quoteShellCommand): ## * `remainingArgs proc<#remainingArgs,OptParser>`_ ## ## **Examples:** - ## - ## .. code-block:: + ## ```Nim ## var p = initOptParser("--left -r:2 -- foo.txt bar.txt") ## while true: ## p.next() ## if p.kind == cmdLongOption and p.key == "": # Look for "--" ## break ## doAssert p.cmdLineRest == "foo.txt bar.txt" + ## ``` result = p.cmds[p.idx .. ^1].quoteShellCommand proc remainingArgs*(p: OptParser): seq[string] {.rtl, extern: "npo$1".} = @@ -404,14 +408,14 @@ proc remainingArgs*(p: OptParser): seq[string] {.rtl, extern: "npo$1".} = ## * `cmdLineRest proc<#cmdLineRest,OptParser>`_ ## ## **Examples:** - ## - ## .. code-block:: + ## ```Nim ## var p = initOptParser("--left -r:2 -- foo.txt bar.txt") ## while true: ## p.next() ## if p.kind == cmdLongOption and p.key == "": # Look for "--" ## break ## doAssert p.remainingArgs == @["foo.txt", "bar.txt"] + ## ``` result = @[] for i in p.idx..`_ module. ## -## .. code-block:: nim -## :test: +## ```nim test +## let logs = @["2019-01-10: OK_", "2019-01-11: FAIL_", "2019-01: aaaa"] +## var outp: seq[string] ## -## let logs = @["2019-01-10: OK_", "2019-01-11: FAIL_", "2019-01: aaaa"] -## var outp: seq[string] +## for log in logs: +## var res: string +## if parseUntil(log, res, ':') == 10: # YYYY-MM-DD == 10 +## outp.add(res & " - " & captureBetween(log, ' ', '_')) +## doAssert outp == @["2019-01-10 - OK", "2019-01-11 - FAIL"] +## ``` ## -## for log in logs: -## var res: string -## if parseUntil(log, res, ':') == 10: # YYYY-MM-DD == 10 -## outp.add(res & " - " & captureBetween(log, ' ', '_')) -## doAssert outp == @["2019-01-10 - OK", "2019-01-11 - FAIL"] +## ```nim test +## from std/strutils import Digits, parseInt ## -## .. code-block:: nim -## :test: -## from std/strutils import Digits, parseInt -## -## let -## input1 = "2019 school start" -## input2 = "3 years back" -## startYear = input1[0 .. skipWhile(input1, Digits)-1] # 2019 -## yearsBack = input2[0 .. skipWhile(input2, Digits)-1] # 3 -## examYear = parseInt(startYear) + parseInt(yearsBack) -## doAssert "Examination is in " & $examYear == "Examination is in 2022" +## let +## input1 = "2019 school start" +## input2 = "3 years back" +## startYear = input1[0 .. skipWhile(input1, Digits)-1] # 2019 +## yearsBack = input2[0 .. skipWhile(input2, Digits)-1] # 3 +## examYear = parseInt(startYear) + parseInt(yearsBack) +## doAssert "Examination is in " & $examYear == "Examination is in 2022" +## ``` ## ## **See also:** ## * `strutils module`_ for combined and identical parsing proc's diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index 884f258f38..88cb6d9c06 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -36,43 +36,43 @@ The file ``examples/htmltitle.nim`` demonstrates how to use the XML parser to accomplish a simple task: To determine the title of an HTML document. -.. code-block:: nim + ```nim + # Example program to show the parsexml module + # This program reads an HTML file and writes its title to stdout. + # Errors and whitespace are ignored. - # Example program to show the parsexml module - # This program reads an HTML file and writes its title to stdout. - # Errors and whitespace are ignored. + import os, streams, parsexml, strutils - import os, streams, parsexml, strutils + if paramCount() < 1: + quit("Usage: htmltitle filename[.html]") - if paramCount() < 1: - quit("Usage: htmltitle filename[.html]") + var filename = addFileExt(paramStr(1), "html") + var s = newFileStream(filename, fmRead) + if s == nil: quit("cannot open the file " & filename) + var x: XmlParser + open(x, s, filename) + while true: + x.next() + case x.kind + of xmlElementStart: + if cmpIgnoreCase(x.elementName, "title") == 0: + var title = "" + x.next() # skip "" + while x.kind == xmlCharData: + title.add(x.charData) + x.next() + if x.kind == xmlElementEnd and cmpIgnoreCase(x.elementName, "title") == 0: + echo("Title: " & title) + quit(0) # Success! + else: + echo(x.errorMsgExpected("/title")) - var filename = addFileExt(paramStr(1), "html") - var s = newFileStream(filename, fmRead) - if s == nil: quit("cannot open the file " & filename) - var x: XmlParser - open(x, s, filename) - while true: - x.next() - case x.kind - of xmlElementStart: - if cmpIgnoreCase(x.elementName, "title") == 0: - var title = "" - x.next() # skip "<title>" - while x.kind == xmlCharData: - title.add(x.charData) - x.next() - if x.kind == xmlElementEnd and cmpIgnoreCase(x.elementName, "title") == 0: - echo("Title: " & title) - quit(0) # Success! - else: - echo(x.errorMsgExpected("/title")) + of xmlEof: break # end of file reached + else: discard # ignore other events - of xmlEof: break # end of file reached - else: discard # ignore other events - - x.close() - quit("Could not determine title!") + x.close() + quit("Could not determine title!") + ``` ]## @@ -85,64 +85,64 @@ The file ``examples/htmlrefs.nim`` demonstrates how to use the XML parser to accomplish another simple task: To determine all the links an HTML document contains. -.. code-block:: nim + ```nim + # Example program to show the new parsexml module + # This program reads an HTML file and writes all its used links to stdout. + # Errors and whitespace are ignored. - # Example program to show the new parsexml module - # This program reads an HTML file and writes all its used links to stdout. - # Errors and whitespace are ignored. + import os, streams, parsexml, strutils - import os, streams, parsexml, strutils + proc `=?=` (a, b: string): bool = + # little trick: define our own comparator that ignores case + return cmpIgnoreCase(a, b) == 0 - proc `=?=` (a, b: string): bool = - # little trick: define our own comparator that ignores case - return cmpIgnoreCase(a, b) == 0 + if paramCount() < 1: + quit("Usage: htmlrefs filename[.html]") - if paramCount() < 1: - quit("Usage: htmlrefs filename[.html]") - - var links = 0 # count the number of links - var filename = addFileExt(paramStr(1), "html") - var s = newFileStream(filename, fmRead) - if s == nil: quit("cannot open the file " & filename) - var x: XmlParser - open(x, s, filename) - next(x) # get first event - block mainLoop: - while true: - case x.kind - of xmlElementOpen: - # the <a href = "xyz"> tag we are interested in always has an attribute, - # thus we search for ``xmlElementOpen`` and not for ``xmlElementStart`` - if x.elementName =?= "a": - x.next() - if x.kind == xmlAttribute: - if x.attrKey =?= "href": - var link = x.attrValue - inc(links) - # skip until we have an ``xmlElementClose`` event - while true: - x.next() - case x.kind - of xmlEof: break mainLoop - of xmlElementClose: break - else: discard - x.next() # skip ``xmlElementClose`` - # now we have the description for the ``a`` element - var desc = "" - while x.kind == xmlCharData: - desc.add(x.charData) - x.next() - echo(desc & ": " & link) - else: - x.next() - of xmlEof: break # end of file reached - of xmlError: - echo(errorMsg(x)) + var links = 0 # count the number of links + var filename = addFileExt(paramStr(1), "html") + var s = newFileStream(filename, fmRead) + if s == nil: quit("cannot open the file " & filename) + var x: XmlParser + open(x, s, filename) + next(x) # get first event + block mainLoop: + while true: + case x.kind + of xmlElementOpen: + # the <a href = "xyz"> tag we are interested in always has an attribute, + # thus we search for ``xmlElementOpen`` and not for ``xmlElementStart`` + if x.elementName =?= "a": x.next() - else: x.next() # skip other events + if x.kind == xmlAttribute: + if x.attrKey =?= "href": + var link = x.attrValue + inc(links) + # skip until we have an ``xmlElementClose`` event + while true: + x.next() + case x.kind + of xmlEof: break mainLoop + of xmlElementClose: break + else: discard + x.next() # skip ``xmlElementClose`` + # now we have the description for the ``a`` element + var desc = "" + while x.kind == xmlCharData: + desc.add(x.charData) + x.next() + echo(desc & ": " & link) + else: + x.next() + of xmlEof: break # end of file reached + of xmlError: + echo(errorMsg(x)) + x.next() + else: x.next() # skip other events - echo($links & " link(s) found!") - x.close() + echo($links & " link(s) found!") + x.close() + ``` ]## diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 11683bbff9..7f0f532fe5 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -889,7 +889,7 @@ macro mkHandlerTplts(handlers: untyped): untyped = # Transforms the handler spec in *handlers* into handler templates. # The AST structure of *handlers[0]*: # - # .. code-block:: + # ``` # StmtList # Call # Ident "pkNonTerminal" @@ -910,6 +910,7 @@ macro mkHandlerTplts(handlers: untyped): untyped = # StmtList # <handler code block> # ... + # ``` func mkEnter(hdName, body: NimNode): NimNode = template helper(hdName, body) {.dirty.} = template hdName(s, p, start) = @@ -959,60 +960,61 @@ template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) = ## match, else the length of the total match. The following example code ## evaluates an arithmetic expression defined by a simple PEG: ## - ## .. code-block:: nim - ## import std/[strutils, pegs] + ## ```nim + ## import std/[strutils, pegs] ## - ## let - ## pegAst = """ - ## Expr <- Sum - ## Sum <- Product (('+' / '-')Product)* - ## Product <- Value (('*' / '/')Value)* - ## Value <- [0-9]+ / '(' Expr ')' - ## """.peg - ## txt = "(5+3)/2-7*22" + ## let + ## pegAst = """ + ## Expr <- Sum + ## Sum <- Product (('+' / '-')Product)* + ## Product <- Value (('*' / '/')Value)* + ## Value <- [0-9]+ / '(' Expr ')' + ## """.peg + ## txt = "(5+3)/2-7*22" ## - ## var - ## pStack: seq[string] = @[] - ## valStack: seq[float] = @[] - ## opStack = "" - ## let - ## parseArithExpr = pegAst.eventParser: - ## pkNonTerminal: - ## enter: - ## pStack.add p.nt.name - ## leave: - ## pStack.setLen pStack.high - ## if length > 0: - ## let matchStr = s.substr(start, start+length-1) - ## case p.nt.name - ## of "Value": - ## try: - ## valStack.add matchStr.parseFloat - ## echo valStack - ## except ValueError: - ## discard - ## of "Sum", "Product": - ## try: - ## let val = matchStr.parseFloat - ## except ValueError: - ## if valStack.len > 1 and opStack.len > 0: - ## valStack[^2] = case opStack[^1] - ## of '+': valStack[^2] + valStack[^1] - ## of '-': valStack[^2] - valStack[^1] - ## of '*': valStack[^2] * valStack[^1] - ## else: valStack[^2] / valStack[^1] - ## valStack.setLen valStack.high - ## echo valStack - ## opStack.setLen opStack.high - ## echo opStack - ## pkChar: - ## leave: - ## if length == 1 and "Value" != pStack[^1]: - ## let matchChar = s[start] - ## opStack.add matchChar - ## echo opStack + ## var + ## pStack: seq[string] = @[] + ## valStack: seq[float] = @[] + ## opStack = "" + ## let + ## parseArithExpr = pegAst.eventParser: + ## pkNonTerminal: + ## enter: + ## pStack.add p.nt.name + ## leave: + ## pStack.setLen pStack.high + ## if length > 0: + ## let matchStr = s.substr(start, start+length-1) + ## case p.nt.name + ## of "Value": + ## try: + ## valStack.add matchStr.parseFloat + ## echo valStack + ## except ValueError: + ## discard + ## of "Sum", "Product": + ## try: + ## let val = matchStr.parseFloat + ## except ValueError: + ## if valStack.len > 1 and opStack.len > 0: + ## valStack[^2] = case opStack[^1] + ## of '+': valStack[^2] + valStack[^1] + ## of '-': valStack[^2] - valStack[^1] + ## of '*': valStack[^2] * valStack[^1] + ## else: valStack[^2] / valStack[^1] + ## valStack.setLen valStack.high + ## echo valStack + ## opStack.setLen opStack.high + ## echo opStack + ## pkChar: + ## leave: + ## if length == 1 and "Value" != pStack[^1]: + ## let matchChar = s[start] + ## opStack.add matchChar + ## echo opStack ## - ## let pLen = parseArithExpr(txt) + ## let pLen = parseArithExpr(txt) + ## ``` ## ## The *handlers* parameter consists of code blocks for *PegKinds*, ## which define the grammar elements of interest. Each block can contain @@ -1181,8 +1183,7 @@ template `=~`*(s: string, pattern: Peg): bool = ## This calls ``match`` with an implicit declared ``matches`` array that ## can be used in the scope of the ``=~`` call: ## - ## .. code-block:: nim - ## + ## ```nim ## if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}": ## # matches a key=value pair: ## echo("Key: ", matches[0]) @@ -1194,7 +1195,7 @@ template `=~`*(s: string, pattern: Peg): bool = ## echo("comment: ", matches[0]) ## else: ## echo("syntax error") - ## + ## ``` bind MaxSubpatterns when not declaredInScope(matches): var matches {.inject.}: array[0..MaxSubpatterns-1, string] @@ -1230,14 +1231,15 @@ func replacef*(s: string, sub: Peg, by: string): string {. ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by` ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples: ## - ## .. code-block:: nim + ## ```nim ## "var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") + ## ``` ## ## Results in: ## - ## .. code-block:: nim - ## + ## ```nim ## "var1<-keykey; val2<-key2key2" + ## ``` result = "" var i = 0 var caps: array[0..MaxSubpatterns-1, string] @@ -1305,8 +1307,7 @@ func replace*(s: string, sub: Peg, cb: proc( ## The callback proc receives the index of the current match (starting with 0), ## the count of captures and an open array with the captures of each match. Examples: ## - ## .. code-block:: nim - ## + ## ```nim ## func handleMatches*(m: int, n: int, c: openArray[string]): string = ## result = "" ## if m > 0: @@ -1318,12 +1319,13 @@ func replace*(s: string, sub: Peg, cb: proc( ## ## let s = "Var1=key1;var2=Key2; VAR3" ## echo s.replace(peg"{\ident}('='{\ident})* ';'* \s*", handleMatches) + ## ``` ## ## Results in: ## - ## .. code-block:: nim - ## + ## ```nim ## "var1: 'key1', var2: 'Key2', var3: ''" + ## ``` result = "" var i = 0 var caps: array[0..MaxSubpatterns-1, string] @@ -1361,18 +1363,19 @@ iterator split*(s: string, sep: Peg): string = ## Substrings are separated by the PEG `sep`. ## Examples: ## - ## .. code-block:: nim + ## ```nim ## for word in split("00232this02939is39an22example111", peg"\d+"): ## writeLine(stdout, word) + ## ``` ## ## Results in: ## - ## .. code-block:: nim + ## ```nim ## "this" ## "is" ## "an" ## "example" - ## + ## ``` var c: Captures var first = 0 diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index fcee22c09f..1b4ae992de 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -205,12 +205,11 @@ when defined(nimdoc): ## to `value`. This `value` can be modified in the scope of ## the `withData` call. ## - ## .. code-block:: nim - ## + ## ```nim ## s.withData(fd, value) do: ## # block is executed only if `fd` registered in selector `s` ## value.uid = 1000 - ## + ## ``` template withData*[T](s: Selector[T], fd: SocketHandle|int, value, body1, body2: untyped) = @@ -218,15 +217,14 @@ when defined(nimdoc): ## to `value`. This `value` can be modified in the scope of ## the `withData` call. ## - ## .. code-block:: nim - ## + ## ```nim ## s.withData(fd, value) do: ## # block is executed only if `fd` registered in selector `s`. ## value.uid = 1000 ## do: ## # block is executed if `fd` not registered in selector `s`. ## raise - ## + ## ``` proc contains*[T](s: Selector[T], fd: SocketHandle|int): bool {.inline.} = ## Determines whether selector contains a file descriptor. diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index e18e2d43a6..d3aeacee55 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -27,67 +27,67 @@ ## StringStream example ## -------------------- ## -## .. code-block:: Nim +## ```Nim +## import std/streams ## -## import std/streams +## var strm = newStringStream("""The first line +## the second line +## the third line""") ## -## var strm = newStringStream("""The first line -## the second line -## the third line""") +## var line = "" ## -## var line = "" +## while strm.readLine(line): +## echo line ## -## while strm.readLine(line): -## echo line +## # Output: +## # The first line +## # the second line +## # the third line ## -## # Output: -## # The first line -## # the second line -## # the third line -## -## strm.close() +## strm.close() +## ``` ## ## FileStream example ## ------------------ ## ## Write file stream example: ## -## .. code-block:: Nim +## ```Nim +## import std/streams ## -## import std/streams +## var strm = newFileStream("somefile.txt", fmWrite) +## var line = "" ## -## var strm = newFileStream("somefile.txt", fmWrite) -## var line = "" +## if not isNil(strm): +## strm.writeLine("The first line") +## strm.writeLine("the second line") +## strm.writeLine("the third line") +## strm.close() ## -## if not isNil(strm): -## strm.writeLine("The first line") -## strm.writeLine("the second line") -## strm.writeLine("the third line") -## strm.close() -## -## # Output (somefile.txt): -## # The first line -## # the second line -## # the third line +## # Output (somefile.txt): +## # The first line +## # the second line +## # the third line +## ``` ## ## Read file stream example: ## -## .. code-block:: Nim +## ```Nim +## import std/streams ## -## import std/streams +## var strm = newFileStream("somefile.txt", fmRead) +## var line = "" ## -## var strm = newFileStream("somefile.txt", fmRead) -## var line = "" +## if not isNil(strm): +## while strm.readLine(line): +## echo line +## strm.close() ## -## if not isNil(strm): -## while strm.readLine(line): -## echo line -## strm.close() -## -## # Output: -## # The first line -## # the second line -## # the third line +## # Output: +## # The first line +## # the second line +## # the third line +## ``` ## ## See also ## ======== @@ -348,9 +348,9 @@ proc write*[T](s: Stream, x: T) = ## **Note:** Not available for JS backend. Use `write(Stream, string) ## <#write,Stream,string>`_ for now. ## - ## .. code-block:: Nim - ## - ## s.writeData(s, unsafeAddr(x), sizeof(x)) + ## ```Nim + ## s.writeData(s, unsafeAddr(x), sizeof(x)) + ## ``` runnableExamples: var strm = newStringStream("") strm.write("abcde") diff --git a/lib/pure/streamwrapper.nim b/lib/pure/streamwrapper.nim index a6c1901d2b..9f5c0f28ae 100644 --- a/lib/pure/streamwrapper.nim +++ b/lib/pure/streamwrapper.nim @@ -91,14 +91,14 @@ proc newPipeOutStream*[T](s: sink (ref T)): owned PipeOutStream[T] = ## when setPosition/getPosition is called or write operation is performed. ## ## Example: - ## - ## .. code-block:: Nim + ## ```Nim ## import std/[osproc, streamwrapper] ## var ## p = startProcess(exePath) ## outStream = p.outputStream().newPipeOutStream() ## echo outStream.peekChar ## p.close() + ## ``` assert s.readDataImpl != nil diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 1cebefee10..2668ad66ca 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -133,13 +133,14 @@ runnableExamples: An expression like `&"{key} is {value:arg} {{z}}"` is transformed into: -.. code-block:: nim + ```nim var temp = newStringOfCap(educatedCapGuess) temp.formatValue(key, "") temp.add(" is ") temp.formatValue(value, arg) temp.add(" {z}") temp + ``` Parts of the string that are enclosed in the curly braces are interpreted as Nim code. To escape a `{` or `}`, double it. @@ -272,13 +273,14 @@ The available floating point presentation types are: Because of the well defined order how templates and macros are expanded, strformat cannot expand template arguments: -.. code-block:: nim + ```nim template myTemplate(arg: untyped): untyped = echo "arg is: ", arg echo &"--- {arg} ---" let x = "abc" myTemplate(x) + ``` First the template `myTemplate` is expanded, where every identifier `arg` is substituted with its argument. The `arg` inside the @@ -289,12 +291,13 @@ identifier that cannot be resolved anymore. The workaround for this is to bind the template argument to a new local variable. -.. code-block:: nim + ```nim template myTemplate(arg: untyped): untyped = block: let arg1 {.inject.} = arg echo "arg is: ", arg1 echo &"--- {arg1} ---" + ``` The use of `{.inject.}` here is necessary again because of template expansion order and hygienic templates. But since we generally want to diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 8a1ea125fa..775c4244ac 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -12,7 +12,7 @@ This module contains a `scanf`:idx: macro that can be used for extracting substrings from an input string. This is often easier than regular expressions. Some examples as an appetizer: -.. code-block:: nim + ```nim # check if input string matches a triple of integers: const input = "(1,2,4)" var x, y, z: int @@ -26,6 +26,7 @@ Some examples as an appetizer: var myfloat: float if scanf(input, "$i-$i-$i $w$s$f", year, month, day, identifier, myfloat): echo "yes, we have a match!" + ``` As can be seen from the examples, strings are matched verbatim except for substrings starting with ``$``. These constructions are available: @@ -83,8 +84,7 @@ matches optional tokens without any result binding. In this example, we define a helper proc ``someSep`` that skips some separators which we then use in our scanf pattern to help us in the matching process: -.. code-block:: nim - + ```nim proc someSep(input: string; start: int; seps: set[char] = {':','-','.'}): int = # Note: The parameters and return value must match to what ``scanf`` requires result = 0 @@ -92,11 +92,11 @@ which we then use in our scanf pattern to help us in the matching process: if scanf(input, "$w$[someSep]$w", key, value): ... + ``` It also possible to pass arguments to a user definable matcher: -.. code-block:: nim - + ```nim proc ndigits(input: string; intVal: var int; start: int; n: int): int = # matches exactly ``n`` digits. Matchers need to return 0 if nothing # matched or otherwise the number of processed chars. @@ -115,6 +115,7 @@ It also possible to pass arguments to a user definable matcher: var year, month, day: int if scanf("2013-01-03", "${ndigits(4)}-${ndigits(2)}-${ndigits(2)}$.", year, month, day): ... + ``` The scanp macro @@ -145,8 +146,7 @@ not implemented. Simple example that parses the ``/etc/passwd`` file line by line: -.. code-block:: nim - + ```nim const etc_passwd = """root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh @@ -165,6 +165,7 @@ Simple example that parses the ``/etc/passwd`` file line by line: result.add entry else: break + ``` The ``scanp`` maps the grammar code into Nim code that performs the parsing. The parsing is performed with the help of 3 helper templates that that can be @@ -173,8 +174,7 @@ implemented for a custom type. These templates need to be named ``atom`` and ``nxt``. ``atom`` should be overloaded to handle both single characters and sets of character. -.. code-block:: nim - + ```nim import std/streams template atom(input: Stream; idx: int; c: char): bool = @@ -190,11 +190,11 @@ overloaded to handle both single characters and sets of character. if scanp(content, idx, +( ~{'\L', '\0'} -> entry.add(peekChar($input))), '\L'): result.add entry + ``` Calling ordinary Nim procs inside the macro is possible: -.. code-block:: nim - + ```nim proc digits(s: string; intVal: var int; start: int): int = var x = 0 while result+start < s.len and s[result+start] in {'0'..'9'} and s[result+start] != ':': @@ -220,12 +220,12 @@ Calling ordinary Nim procs inside the macro is possible: result.add login & " " & homedir else: break + ``` When used for matching, keep in mind that likewise scanf, no backtracking is performed. -.. code-block:: nim - + ```nim proc skipUntil(s: string; until: string; unless = '\0'; start: int): int = # Skips all characters until the string `until` is found. Returns 0 # if the char `unless` is found first or the end is reached. @@ -256,12 +256,12 @@ is performed. for r in collectLinks(body): echo r + ``` In this example both macros are combined seamlessly in order to maximise efficiency and perform different checks. -.. code-block:: nim - + ```nim iterator parseIps*(soup: string): string = ## ipv4 only! const digits = {'0'..'9'} @@ -279,7 +279,7 @@ efficiency and perform different checks. yield buf buf.setLen(0) # need to clear `buf` each time, cause it might contain garbage idx.inc - + ``` ]## diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 6c1e495648..7ab3d37c80 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -129,11 +129,11 @@ const ## Not very useful by its own, you can use it to create *inverted* sets to ## make the `find func<#find,string,set[char],Natural,int>`_ ## find **invalid** characters in strings. Example: - ## - ## .. code-block:: nim + ## ```nim ## let invalid = AllChars - Digits ## doAssert "01234".find(invalid) == -1 ## doAssert "01A34".find(invalid) == 2 + ## ``` func isAlphaAscii*(c: char): bool {.rtl, extern: "nsuIsAlphaAsciiChar".} = ## Checks whether or not character `c` is alphabetical. @@ -423,14 +423,12 @@ iterator split*(s: string, sep: char, maxsplit: int = -1): string = ## ## Substrings are separated by the character `sep`. ## The code: - ## - ## .. code-block:: nim + ## ```nim ## for word in split(";;this;is;an;;example;;;", ';'): ## writeLine(stdout, word) - ## + ## ``` ## Results in: - ## - ## .. code-block:: + ## ``` ## "" ## "" ## "this" @@ -441,6 +439,7 @@ iterator split*(s: string, sep: char, maxsplit: int = -1): string = ## "" ## "" ## "" + ## ``` ## ## See also: ## * `rsplit iterator<#rsplit.i,string,char,int>`_ @@ -455,41 +454,46 @@ iterator split*(s: string, seps: set[char] = Whitespace, ## ## Substrings are separated by a substring containing only `seps`. ## - ## .. code-block:: nim + ## ```nim ## for word in split("this\lis an\texample"): ## writeLine(stdout, word) + ## ``` ## ## ...generates this output: ## - ## .. code-block:: + ## ``` ## "this" ## "is" ## "an" ## "example" + ## ``` ## ## And the following code: ## - ## .. code-block:: nim + ## ```nim ## for word in split("this:is;an$example", {';', ':', '$'}): ## writeLine(stdout, word) + ## ``` ## ## ...produces the same output as the first example. The code: ## - ## .. code-block:: nim + ## ```nim ## let date = "2012-11-20T22:08:08.398990" ## let separators = {' ', '-', ':', 'T'} ## for number in split(date, separators): ## writeLine(stdout, number) + ## ``` ## ## ...results in: ## - ## .. code-block:: + ## ``` ## "2012" ## "11" ## "20" ## "22" ## "08" ## "08.398990" + ## ``` ## ## .. note:: Empty separator set results in returning an original string, ## following the interpretation "split by no element". @@ -507,16 +511,18 @@ iterator split*(s: string, sep: string, maxsplit: int = -1): string = ## Substrings are separated by the string `sep`. ## The code: ## - ## .. code-block:: nim + ## ```nim ## for word in split("thisDATAisDATAcorrupted", "DATA"): ## writeLine(stdout, word) + ## ``` ## ## Results in: ## - ## .. code-block:: + ## ``` ## "this" ## "is" ## "corrupted" + ## ``` ## ## .. note:: Empty separator string results in returning an original string, ## following the interpretation "split by no element". @@ -561,15 +567,17 @@ iterator rsplit*(s: string, sep: char, ## string separator. Works exactly the same as `split iterator ## <#split.i,string,char,int>`_ except in reverse order. ## - ## .. code-block:: nim + ## ```nim ## for piece in "foo:bar".rsplit(':'): ## echo piece + ## ``` ## ## Results in: ## - ## .. code-block:: nim + ## ``` ## "bar" ## "foo" + ## ``` ## ## Substrings are separated from the right by the char `sep`. ## @@ -586,15 +594,17 @@ iterator rsplit*(s: string, seps: set[char] = Whitespace, ## string separator. Works exactly the same as `split iterator ## <#split.i,string,char,int>`_ except in reverse order. ## - ## .. code-block:: nim + ## ```nim ## for piece in "foo bar".rsplit(WhiteSpace): ## echo piece + ## ``` ## ## Results in: ## - ## .. code-block:: nim + ## ``` ## "bar" ## "foo" + ## ``` ## ## Substrings are separated from the right by the set of chars `seps` ## @@ -614,15 +624,17 @@ iterator rsplit*(s: string, sep: string, maxsplit: int = -1, ## string separator. Works exactly the same as `split iterator ## <#split.i,string,string,int>`_ except in reverse order. ## - ## .. code-block:: nim + ## ```nim ## for piece in "foothebar".rsplit("the"): ## echo piece + ## ``` ## ## Results in: ## - ## .. code-block:: nim + ## ``` ## "bar" ## "foo" + ## ``` ## ## Substrings are separated from the right by the string `sep` ## @@ -648,13 +660,14 @@ iterator splitLines*(s: string, keepEol = false): string = ## ## Example: ## - ## .. code-block:: nim + ## ```nim ## for line in splitLines("\nthis\nis\nan\n\nexample\n"): ## writeLine(stdout, line) + ## ``` ## ## Results in: ## - ## .. code-block:: nim + ## ```nim ## "" ## "this" ## "is" @@ -662,6 +675,7 @@ iterator splitLines*(s: string, keepEol = false): string = ## "" ## "example" ## "" + ## ``` ## ## See also: ## * `splitWhitespace iterator<#splitWhitespace.i,string,int>`_ @@ -694,16 +708,17 @@ iterator splitWhitespace*(s: string, maxsplit: int = -1): string = ## ## The following code: ## - ## .. code-block:: nim + ## ```nim ## let s = " foo \t bar baz " ## for ms in [-1, 1, 2, 3]: ## echo "------ maxsplit = ", ms, ":" ## for item in s.splitWhitespace(maxsplit=ms): ## echo '"', item, '"' + ## ``` ## ## ...results in: ## - ## .. code-block:: + ## ``` ## ------ maxsplit = -1: ## "foo" ## "bar" @@ -719,6 +734,7 @@ iterator splitWhitespace*(s: string, maxsplit: int = -1): string = ## "foo" ## "bar" ## "baz" + ## ``` ## ## See also: ## * `splitLines iterator<#splitLines.i,string>`_ @@ -797,13 +813,15 @@ func rsplit*(s: string, sep: char, maxsplit: int = -1): seq[string] {.rtl, ## For example, if a system had `#` as a delimiter, you could ## do the following to get the tail of the path: ## - ## .. code-block:: nim + ## ```nim ## var tailSplit = rsplit("Root#Object#Method#Index", '#', maxsplit=1) + ## ``` ## ## Results in `tailSplit` containing: ## - ## .. code-block:: nim + ## ```nim ## @["Root#Object#Method", "Index"] + ## ``` ## ## See also: ## * `rsplit iterator <#rsplit.i,string,char,int>`_ @@ -825,13 +843,15 @@ func rsplit*(s: string, seps: set[char] = Whitespace, ## For example, if a system had `#` as a delimiter, you could ## do the following to get the tail of the path: ## - ## .. code-block:: nim + ## ```nim ## var tailSplit = rsplit("Root#Object#Method#Index", {'#'}, maxsplit=1) + ## ``` ## ## Results in `tailSplit` containing: ## - ## .. code-block:: nim + ## ```nim ## @["Root#Object#Method", "Index"] + ## ``` ## ## .. note:: Empty separator set results in returning an original string, ## following the interpretation "split by no element". @@ -855,13 +875,15 @@ func rsplit*(s: string, sep: string, maxsplit: int = -1): seq[string] {.rtl, ## For example, if a system had `#` as a delimiter, you could ## do the following to get the tail of the path: ## - ## .. code-block:: nim + ## ```nim ## var tailSplit = rsplit("Root#Object#Method#Index", "#", maxsplit=1) + ## ``` ## ## Results in `tailSplit` containing: ## - ## .. code-block:: nim + ## ```nim ## @["Root#Object#Method", "Index"] + ## ``` ## ## .. note:: Empty separator string results in returning an original string, ## following the interpretation "split by no element". @@ -1786,8 +1808,9 @@ func addSep*(dest: var string, sep = ", ", startLen: Natural = 0) {.inline.} = ## ## A shorthand for: ## - ## .. code-block:: nim + ## ```nim ## if dest.len > startLen: add(dest, sep) + ## ``` ## ## This is often useful for generating some code where the items need to ## be *separated* by `sep`. `sep` is only added if `dest` is longer than @@ -2634,13 +2657,13 @@ func formatEng*(f: BiggestFloat, ## decimal point or (if `trim` is true) the maximum number of digits to be ## shown. ## - ## .. code-block:: nim - ## + ## ```nim ## formatEng(0, 2, trim=false) == "0.00" ## formatEng(0, 2) == "0" ## formatEng(0.053, 0) == "53e-3" ## formatEng(52731234, 2) == "52.73e6" ## formatEng(-52731234, 2) == "-52.73e6" + ## ``` ## ## If `siPrefix` is set to true, the number will be displayed with the SI ## prefix corresponding to the exponent. For example 4100 will be displayed @@ -2655,8 +2678,7 @@ func formatEng*(f: BiggestFloat, ## different to appending the unit to the result as the location of the space ## is altered depending on whether there is an exponent. ## - ## .. code-block:: nim - ## + ## ```nim ## formatEng(4100, siPrefix=true, unit="V") == "4.1 kV" ## formatEng(4.1, siPrefix=true, unit="V") == "4.1 V" ## formatEng(4.1, siPrefix=true) == "4.1" # Note lack of space @@ -2666,6 +2688,7 @@ func formatEng*(f: BiggestFloat, ## formatEng(4100) == "4.1e3" ## formatEng(4100, unit="V") == "4.1e3 V" ## formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 " # Space with useUnitSpace=true + ## ``` ## ## `decimalSep` is used as the decimal separator. ## @@ -2829,13 +2852,15 @@ func `%`*(formatstr: string, a: openArray[string]): string {.rtl, ## ## This is best explained by an example: ## - ## .. code-block:: nim + ## ```nim ## "$1 eats $2." % ["The cat", "fish"] + ## ``` ## ## Results in: ## - ## .. code-block:: nim + ## ```nim ## "The cat eats fish." + ## ``` ## ## The substitution variables (the thing after the `$`) are enumerated ## from 1 to `a.len`. @@ -2843,21 +2868,24 @@ func `%`*(formatstr: string, a: openArray[string]): string {.rtl, ## The notation `$#` can be used to refer to the next substitution ## variable: ## - ## .. code-block:: nim + ## ```nim ## "$# eats $#." % ["The cat", "fish"] + ## ``` ## ## Substitution variables can also be words (that is ## `[A-Za-z_]+[A-Za-z0-9_]*`) in which case the arguments in `a` with even ## indices are keys and with odd indices are the corresponding values. ## An example: ## - ## .. code-block:: nim + ## ```nim ## "$animal eats $food." % ["animal", "The cat", "food", "fish"] + ## ``` ## ## Results in: ## - ## .. code-block:: nim + ## ```nim ## "The cat eats fish." + ## ``` ## ## The variables are compared with `cmpIgnoreStyle`. `ValueError` is ## raised if an ill-formed format string has been passed to the `%` operator. @@ -2955,13 +2983,14 @@ iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[ ## Substrings are separated by a substring containing only `seps`. ## Example: ## - ## .. code-block:: nim + ## ```nim ## for word in tokenize(" this is an example "): ## writeLine(stdout, word) + ## ``` ## ## Results in: ## - ## .. code-block:: nim + ## ```nim ## (" ", true) ## ("this", false) ## (" ", true) @@ -2971,6 +3000,7 @@ iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[ ## (" ", true) ## ("example", false) ## (" ", true) + ## ``` var i = 0 while true: var j = i diff --git a/lib/pure/times.nim b/lib/pure/times.nim index f5775e4d95..9c32c7b211 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -20,7 +20,7 @@ Examples ======== - .. code-block:: nim + ```nim import std/[times, os] # Simple benchmarking let time = cpuTime() @@ -37,6 +37,7 @@ # Arithmetic using TimeInterval echo "One year from now : ", now() + 1.years echo "One month from now : ", now() + 1.months + ``` Parsing and Formatting Dates ============================ @@ -44,10 +45,10 @@ The `DateTime` type can be parsed and formatted using the different `parse` and `format` procedures. - .. code-block:: nim - + ```nim let dt = parse("2000-01-01", "yyyy-MM-dd") echo dt.format("yyyy-MM-dd") + ``` The different format patterns that are supported are documented below. @@ -652,11 +653,10 @@ template eqImpl(a: Duration|Time, b: Duration|Time): bool = const DurationZero* = Duration() ## \ ## Zero value for durations. Useful for comparisons. - ## - ## .. code-block:: nim - ## + ## ```nim ## doAssert initDuration(seconds = 1) > DurationZero ## doAssert initDuration(seconds = 0) == DurationZero + ## ``` proc initDuration*(nanoseconds, microseconds, milliseconds, seconds, minutes, hours, days, weeks: int64 = 0): Duration = diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 3b3684789b..a6b01d6447 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -34,9 +34,9 @@ ## ## Specify the test name as a command line argument. ## -## .. code:: -## +## ```cmd ## nim c -r test "my test name" "another test" +## ``` ## ## Multiple arguments can be used. ## @@ -45,9 +45,9 @@ ## ## Specify the suite name delimited by `"::"`. ## -## .. code:: -## +## ```cmd ## nim c -r test "my test name::" +## ``` ## ## Selecting tests by pattern ## ========================== @@ -58,19 +58,18 @@ ## ## Tests matching **any** of the arguments are executed. ## -## .. code:: -## +## ```cmd ## nim c -r test fast_suite::mytest1 fast_suite::mytest2 ## nim c -r test "fast_suite::mytest*" ## nim c -r test "auth*::" "crypto::hashing*" ## # Run suites starting with 'bug #' and standalone tests starting with '#' ## nim c -r test 'bug #*::' '::#*' +## ``` ## ## Examples ## ======== ## -## .. code:: nim -## +## ```nim ## suite "description for this stuff": ## echo "suite setup: run once before the tests" ## @@ -96,6 +95,7 @@ ## discard v[4] ## ## echo "suite teardown: run once after the tests" +## ``` ## ## Limitations/Bugs ## ================ @@ -473,27 +473,26 @@ template suite*(name, body) {.dirty.} = ## common fixture (``setup``, ``teardown``). The fixture is executed ## for EACH test. ## - ## .. code-block:: nim - ## suite "test suite for addition": - ## setup: - ## let result = 4 + ## ```nim + ## suite "test suite for addition": + ## setup: + ## let result = 4 ## - ## test "2 + 2 = 4": - ## check(2+2 == result) + ## test "2 + 2 = 4": + ## check(2+2 == result) ## - ## test "(2 + -2) != 4": - ## check(2 + -2 != result) + ## test "(2 + -2) != 4": + ## check(2 + -2 != result) ## - ## # No teardown needed + ## # No teardown needed + ## ``` ## ## The suite will run the individual test cases in the order in which ## they were listed. With default global settings the above code prints: ## - ## .. code-block:: - ## - ## [Suite] test suite for addition - ## [OK] 2 + 2 = 4 - ## [OK] (2 + -2) != 4 + ## [Suite] test suite for addition + ## [OK] 2 + 2 = 4 + ## [OK] (2 + -2) != 4 bind formatters, ensureInitialized, suiteEnded block: @@ -528,17 +527,15 @@ when not declared(setProgramResult): template test*(name, body) {.dirty.} = ## Define a single test case identified by `name`. ## - ## .. code-block:: nim - ## - ## test "roses are red": - ## let roses = "red" - ## check(roses == "red") + ## ```nim + ## test "roses are red": + ## let roses = "red" + ## check(roses == "red") + ## ``` ## ## The above code outputs: ## - ## .. code-block:: - ## - ## [OK] roses are red + ## [OK] roses are red bind shouldRun, checkpoints, formatters, ensureInitialized, testEnded, exceptionTypeName, setProgramResult ensureInitialized() @@ -585,11 +582,11 @@ proc checkpoint*(msg: string) = ## Set a checkpoint identified by `msg`. Upon test failure all ## checkpoints encountered so far are printed out. Example: ## - ## .. code-block:: nim - ## - ## checkpoint("Checkpoint A") - ## check((42, "the Answer to life and everything") == (1, "a")) - ## checkpoint("Checkpoint B") + ## ```nim + ## checkpoint("Checkpoint A") + ## check((42, "the Answer to life and everything") == (1, "a")) + ## checkpoint("Checkpoint B") + ## ``` ## ## outputs "Checkpoint A" once it fails. checkpoints.add(msg) @@ -601,11 +598,11 @@ template fail* = ## failed (change exit code and test status). This template is useful ## for debugging, but is otherwise mostly used internally. Example: ## - ## .. code-block:: nim - ## - ## checkpoint("Checkpoint A") - ## complicatedProcInThread() - ## fail() + ## ```nim + ## checkpoint("Checkpoint A") + ## complicatedProcInThread() + ## fail() + ## ``` ## ## outputs "Checkpoint A" before quitting. bind ensureInitialized, setProgramResult @@ -633,11 +630,10 @@ template skip* = ## for reasons depending on outer environment, ## or certain application logic conditions or configurations. ## The test code is still executed. - ## - ## .. code-block:: nim - ## - ## if not isGLContextCreated(): - ## skip() + ## ```nim + ## if not isGLContextCreated(): + ## skip() + ## ``` bind checkpoints testStatusIMPL = TestStatus.SKIPPED diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 186da4df81..e4cd407e29 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -935,8 +935,9 @@ proc xmlConstructor(a: NimNode): NimNode = macro `<>`*(x: untyped): untyped = ## Constructor macro for XML. Example usage: ## - ## .. code-block:: nim + ## ```nim ## <>a(href="http://nim-lang.org", newText("Nim rules.")) + ## ``` ## ## Produces an XML tree for: ## diff --git a/lib/std/cmdline.nim b/lib/std/cmdline.nim index 6788dacde2..e545ac599d 100644 --- a/lib/std/cmdline.nim +++ b/lib/std/cmdline.nim @@ -163,11 +163,12 @@ when defined(nimdoc): ## ## **Examples:** ## - ## .. code-block:: nim + ## ```nim ## when declared(paramCount): ## # Use paramCount() here ## else: ## # Do something else! + ## ``` proc paramStr*(i: int): string {.tags: [ReadIOEffect].} = ## Returns the `i`-th `command line argument`:idx: given to the application. @@ -195,11 +196,12 @@ when defined(nimdoc): ## ## **Examples:** ## - ## .. code-block:: nim + ## ```nim ## when declared(paramStr): ## # Use paramStr() here ## else: ## # Do something else! + ## ``` elif defined(nimscript): discard elif defined(nodejs): @@ -296,11 +298,12 @@ when declared(paramCount) or defined(nimdoc): ## ## **Examples:** ## - ## .. code-block:: nim + ## ```nim ## when declared(commandLineParams): ## # Use commandLineParams() here ## else: ## # Do something else! + ## ``` result = @[] for i in 1..paramCount(): result.add(paramStr(i)) diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim index 55ace35001..f2d0d25cba 100644 --- a/lib/std/private/digitsutils.nim +++ b/lib/std/private/digitsutils.nim @@ -19,7 +19,7 @@ const # Inspired by https://engineering.fb.com/2013/03/15/developer-tools/three-optimization-tips-for-c # Generates: -# .. code-block:: nim +# ```nim # var res = "" # for i in 0 .. 99: # if i < 10: @@ -27,6 +27,7 @@ const # else: # res.add $i # doAssert res == digits100 +# ``` proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} = buf[pos] = digits100[2 * digits] diff --git a/lib/std/private/since.nim b/lib/std/private/since.nim index 1a6dd02cb4..720120f117 100644 --- a/lib/std/private/since.nim +++ b/lib/std/private/since.nim @@ -15,19 +15,19 @@ The emulation cannot be 100% faithful and to avoid adding too much complexity, template since*(version: (int, int), body: untyped) {.dirty.} = ## Evaluates `body` if the ``(NimMajor, NimMinor)`` is greater than ## or equal to `version`. Usage: - ## - ## .. code-block:: Nim + ## ```Nim ## proc fun*() {.since: (1, 3).} ## since (1, 3): fun() + ## ``` when (NimMajor, NimMinor) >= version: body template since*(version: (int, int, int), body: untyped) {.dirty.} = ## Evaluates `body` if ``(NimMajor, NimMinor, NimPatch)`` is greater than ## or equal to `version`. Usage: - ## - ## .. code-block:: Nim + ## ```Nim ## proc fun*() {.since: (1, 3, 1).} ## since (1, 3, 1): fun() + ## ``` when (NimMajor, NimMinor, NimPatch) >= version: body diff --git a/lib/std/socketstreams.nim b/lib/std/socketstreams.nim index b53d6a5d35..41d46e58ae 100644 --- a/lib/std/socketstreams.nim +++ b/lib/std/socketstreams.nim @@ -31,37 +31,38 @@ ## Examples ## ======== ## -## .. code-block:: Nim -## import std/socketstreams +## ```Nim +## import std/socketstreams ## -## var -## socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) -## stream = newReadSocketStream(socket) -## socket.sendTo("127.0.0.1", Port(12345), "SOME REQUEST") -## echo stream.readLine() # Will call `recv` -## stream.setPosition(0) -## echo stream.readLine() # Will return the read line from the buffer -## stream.resetStream() # Buffer is now empty, position is 0 -## echo stream.readLine() # Will call `recv` again -## stream.close() # Closes the socket +## var +## socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) +## stream = newReadSocketStream(socket) +## socket.sendTo("127.0.0.1", Port(12345), "SOME REQUEST") +## echo stream.readLine() # Will call `recv` +## stream.setPosition(0) +## echo stream.readLine() # Will return the read line from the buffer +## stream.resetStream() # Buffer is now empty, position is 0 +## echo stream.readLine() # Will call `recv` again +## stream.close() # Closes the socket +## ``` ## -## .. code-block:: Nim +## ```Nim +## import std/socketstreams ## -## import std/socketstreams -## -## var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) -## socket.connect("127.0.0.1", Port(12345)) -## var sendStream = newWriteSocketStream(socket) -## sendStream.write "NOM" -## sendStream.setPosition(1) -## echo sendStream.peekStr(2) # OM -## sendStream.write "I" -## sendStream.setPosition(0) -## echo sendStream.readStr(3) # NIM -## echo sendStream.getPosition() # 3 -## sendStream.flush() # This actually performs the writing to the socket -## sendStream.setPosition(1) -## sendStream.write "I" # Throws an error as we can't write into an already sent buffer +## var socket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP) +## socket.connect("127.0.0.1", Port(12345)) +## var sendStream = newWriteSocketStream(socket) +## sendStream.write "NOM" +## sendStream.setPosition(1) +## echo sendStream.peekStr(2) # OM +## sendStream.write "I" +## sendStream.setPosition(0) +## echo sendStream.readStr(3) # NIM +## echo sendStream.getPosition() # 3 +## sendStream.flush() # This actually performs the writing to the socket +## sendStream.setPosition(1) +## sendStream.write "I" # Throws an error as we can't write into an already sent buffer +## ``` import net, streams diff --git a/lib/std/typedthreads.nim b/lib/std/typedthreads.nim index 2c1cf6f1d6..501a0d0fab 100644 --- a/lib/std/typedthreads.nim +++ b/lib/std/typedthreads.nim @@ -12,27 +12,27 @@ ## Examples ## ======== ## -## .. code-block:: Nim +## ```Nim +## import std/locks ## -## import std/locks +## var +## thr: array[0..4, Thread[tuple[a,b: int]]] +## L: Lock ## -## var -## thr: array[0..4, Thread[tuple[a,b: int]]] -## L: Lock +## proc threadFunc(interval: tuple[a,b: int]) {.thread.} = +## for i in interval.a..interval.b: +## acquire(L) # lock stdout +## echo i +## release(L) ## -## proc threadFunc(interval: tuple[a,b: int]) {.thread.} = -## for i in interval.a..interval.b: -## acquire(L) # lock stdout -## echo i -## release(L) +## initLock(L) ## -## initLock(L) +## for i in 0..high(thr): +## createThread(thr[i], threadFunc, (i*10, i*10+5)) +## joinThreads(thr) ## -## for i in 0..high(thr): -## createThread(thr[i], threadFunc, (i*10, i*10+5)) -## joinThreads(thr) -## -## deinitLock(L) +## deinitLock(L) +## ``` diff --git a/lib/system.nim b/lib/system.nim index 521380a578..7b27f226a6 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2408,9 +2408,9 @@ when defined(nimV2): proc repr*[T, U](x: HSlice[T, U]): string = ## Generic `repr` operator for slices that is lifted from the components ## of `x`. Example: - ## - ## .. code-block:: Nim - ## $(1 .. 5) == "1 .. 5" + ## ```Nim + ## $(1 .. 5) == "1 .. 5" + ## ``` result = repr(x.a) result.add(" .. ") result.add(repr(x.b)) diff --git a/lib/system/channels_builtin.nim b/lib/system/channels_builtin.nim index e04f2a0db1..088003e4b2 100644 --- a/lib/system/channels_builtin.nim +++ b/lib/system/channels_builtin.nim @@ -26,7 +26,7 @@ ## The following is a simple example of two different ways to use channels: ## blocking and non-blocking. ## -## .. code-block:: Nim +## ```Nim ## # Be sure to compile with --threads:on. ## # The channels and threads modules are part of system and should not be ## # imported. @@ -87,6 +87,7 @@ ## ## # Clean up the channel. ## chan.close() +## ``` ## ## Sample output ## ------------- @@ -113,7 +114,7 @@ ## using e.g. `system.allocShared0` and pass these pointers through thread ## arguments: ## -## .. code-block:: Nim +## ```Nim ## proc worker(channel: ptr Channel[string]) = ## let greeting = channel[].recv() ## echo greeting @@ -135,6 +136,7 @@ ## deallocShared(channel) ## ## localChannelExample() # "Hello from the main thread!" +## ``` when not declared(ThisIsSystem): {.error: "You must not import this module explicitly".} diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index 4ff3d0ae6c..89a739d5a7 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -41,9 +41,9 @@ proc `$`*(x: bool): string {.magic: "BoolToStr", noSideEffect.} proc `$`*(x: char): string {.magic: "CharToStr", noSideEffect.} ## The stringify operator for a character argument. Returns `x` ## converted to a string. - ## - ## .. code-block:: Nim + ## ```Nim ## assert $'c' == "c" + ## ``` proc `$`*(x: cstring): string {.magic: "CStrToStr", noSideEffect.} ## The stringify operator for a CString argument. Returns `x` @@ -67,19 +67,20 @@ proc `$`*(t: typedesc): string {.magic: "TypeTrait".} ## For more procedures dealing with `typedesc`, see ## `typetraits module <typetraits.html>`_. ## - ## .. code-block:: Nim + ## ```Nim ## doAssert $(typeof(42)) == "int" ## doAssert $(typeof("Foo")) == "string" ## static: doAssert $(typeof(@['A', 'B'])) == "seq[char]" + ## ``` proc `$`*[T: tuple](x: T): string = ## Generic `$` operator for tuples that is lifted from the components ## of `x`. Example: - ## - ## .. code-block:: Nim + ## ```Nim ## $(23, 45) == "(23, 45)" ## $(a: 23, b: 45) == "(a: 23, b: 45)" ## $() == "()" + ## ``` tupleObjectDollar(result, x) when not defined(nimPreviewSlimSystem): @@ -108,25 +109,25 @@ proc collectionToString[T](x: T, prefix, separator, suffix: string): string = proc `$`*[T](x: set[T]): string = ## Generic `$` operator for sets that is lifted from the components ## of `x`. Example: - ## - ## .. code-block:: Nim + ## ```Nim ## ${23, 45} == "{23, 45}" + ## ``` collectionToString(x, "{", ", ", "}") proc `$`*[T](x: seq[T]): string = ## Generic `$` operator for seqs that is lifted from the components ## of `x`. Example: - ## - ## .. code-block:: Nim + ## ```Nim ## $(@[23, 45]) == "@[23, 45]" + ## ``` collectionToString(x, "@[", ", ", "]") proc `$`*[T, U](x: HSlice[T, U]): string = ## Generic `$` operator for slices that is lifted from the components ## of `x`. Example: - ## - ## .. code-block:: Nim + ## ```Nim ## $(1 .. 5) == "1 .. 5" + ## ``` result = $x.a result.add(" .. ") result.add($x.b) @@ -140,7 +141,7 @@ when not defined(nimNoArrayToString): proc `$`*[T](x: openArray[T]): string = ## Generic `$` operator for openarrays that is lifted from the components ## of `x`. Example: - ## - ## .. code-block:: Nim + ## ```Nim ## $(@[23, 45].toOpenArray(0, 1)) == "[23, 45]" + ## ``` collectionToString(x, "[", ", ", "]") diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 7db2b65674..35ab269035 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -31,7 +31,7 @@ In Nim the compiler cannot always know if a reference is stored on the stack or not. This is caused by var parameters. Consider this example: -.. code-block:: Nim + ```Nim proc setRef(r: var ref TNode) = new(r) @@ -41,11 +41,12 @@ Consider this example: setRef(r) # here we should not update the reference counts, because # r is on the stack setRef(r.left) # here we should update the refcounts! + ``` We have to decide at runtime whether the reference is on the stack or not. The generated code looks roughly like this: -.. code-block:: C + ```C void setref(TNode** ref) { unsureAsgnRef(ref, newObj(TNode_TI, sizeof(TNode))) } @@ -53,6 +54,7 @@ The generated code looks roughly like this: setRef(&r) setRef(&r->left) } + ``` Note that for systems with a continuous stack (which most systems have) the check whether the ref is on the stack is very cheap (only two diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim index 9ce475e5b1..a2c897b04b 100644 --- a/lib/system/nimscript.nim +++ b/lib/system/nimscript.nim @@ -89,10 +89,9 @@ proc patchFile*(package, filename, replacement: string) = ## The compiler also performs `path substitution <nimc.html#compiler-usage-commandminusline-switches>`_ on `replacement`. ## ## Example: - ## - ## .. code-block:: nim - ## + ## ```nim ## patchFile("stdlib", "asyncdispatch", "patches/replacement") + ## ``` discard proc getCommand*(): string = @@ -159,20 +158,18 @@ proc strip(s: string): string = template `--`*(key, val: untyped) = ## A shortcut for `switch <#switch,string,string>`_ ## Example: - ## - ## .. code-block:: nim - ## + ## ```nim ## --path:somePath # same as switch("path", "somePath") ## --path:"someOtherPath" # same as switch("path", "someOtherPath") + ## ``` switch(strip(astToStr(key)), strip(astToStr(val))) template `--`*(key: untyped) = ## A shortcut for `switch <#switch,string,string>`_ ## Example: - ## - ## .. code-block:: nim - ## + ## ```nim ## --listCmd # same as switch("listCmd") + ## ``` switch(strip(astToStr(key))) type @@ -341,12 +338,12 @@ template withDir*(dir: string; body: untyped): untyped = ## ## If you need a permanent change, use the `cd() <#cd,string>`_ proc. ## Usage example: - ## - ## .. code-block:: nim + ## ```nim ## # inside /some/path/ ## withDir "foo": ## # move to /some/path/foo/ ## # back in /some/path/ + ## ``` let curDir = getCurrentDir() try: cd(dir) @@ -391,10 +388,10 @@ when not defined(nimble): ## Defines a task. Hidden tasks are supported via an empty description. ## ## Example: - ## - ## .. code-block:: nim - ## task build, "default build is via the C backend": - ## setCommand "c" + ## ```nim + ## task build, "default build is via the C backend": + ## setCommand "c" + ## ``` ## ## For a task named `foo`, this template generates a `proc` named ## `fooTask`. This is useful if you need to call one task in @@ -402,13 +399,14 @@ when not defined(nimble): ## ## Example: ## - ## .. code-block:: nim - ## task foo, "foo": # > nim foo - ## echo "Running foo" # Running foo + ## ```nim + ## task foo, "foo": # > nim foo + ## echo "Running foo" # Running foo ## - ## task bar, "bar": # > nim bar - ## echo "Running bar" # Running bar - ## fooTask() # Running foo + ## task bar, "bar": # > nim bar + ## echo "Running bar" # Running bar + ## fooTask() # Running foo + ## ``` proc `name Task`*() = setCommand "nop" body diff --git a/lib/system/repr_v2.nim b/lib/system/repr_v2.nim index 3a40ac5ad7..f81c615e91 100644 --- a/lib/system/repr_v2.nim +++ b/lib/system/repr_v2.nim @@ -38,8 +38,9 @@ proc repr*(x: char): string {.noSideEffect, raises: [].} = ## repr for a character argument. Returns `x` ## converted to an escaped string. ## - ## .. code-block:: Nim + ## ```Nim ## assert repr('c') == "'c'" + ## ``` result.add '\'' # Elides string creations if not needed if x in {'\\', '\0'..'\31', '\127'..'\255'}: @@ -132,11 +133,11 @@ proc reprObject[T: tuple|object](res: var string, x: T) {.noSideEffect, raises: proc repr*[T: tuple|object](x: T): string {.noSideEffect, raises: [].} = ## Generic `repr` operator for tuples that is lifted from the components ## of `x`. Example: - ## - ## .. code-block:: Nim + ## ```Nim ## $(23, 45) == "(23, 45)" ## $(a: 23, b: 45) == "(a: 23, b: 45)" ## $() == "()" + ## ``` when T is object: result = $typeof(x) reprObject(result, x) @@ -164,17 +165,17 @@ proc collectionToRepr[T](x: T, prefix, separator, suffix: string): string {.noSi proc repr*[T](x: set[T]): string = ## Generic `repr` operator for sets that is lifted from the components ## of `x`. Example: - ## - ## .. code-block:: Nim + ## ```Nim ## ${23, 45} == "{23, 45}" + ## ``` collectionToRepr(x, "{", ", ", "}") proc repr*[T](x: seq[T]): string = ## Generic `repr` operator for seqs that is lifted from the components ## of `x`. Example: - ## - ## .. code-block:: Nim + ## ```Nim ## $(@[23, 45]) == "@[23, 45]" + ## ``` collectionToRepr(x, "@[", ", ", "]") proc repr*[T, IDX](x: array[IDX, T]): string = @@ -184,9 +185,9 @@ proc repr*[T, IDX](x: array[IDX, T]): string = proc repr*[T](x: openArray[T]): string = ## Generic `repr` operator for openarrays that is lifted from the components ## of `x`. Example: - ## - ## .. code-block:: Nim + ## ```Nim ## $(@[23, 45].toOpenArray(0, 1)) == "[23, 45]" + ## ``` collectionToRepr(x, "[", ", ", "]") proc repr*[T](x: UncheckedArray[T]): string = diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index e659746eec..b94ddaa217 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -18,12 +18,13 @@ ## ## Build and test examples: ## -## .. code-block:: +## ```cmd ## ./bin/nim c -d:ssl -p:. -r tests/stdlib/tssl.nim ## ./bin/nim c -d:ssl --threads:on -p:. -r tests/stdlib/thttpclient_ssl.nim ## ./bin/nim c -d:ssl -p:. -r tests/untestable/tssl.nim ## ./bin/nim c -d:ssl -p:. --dynlibOverride:ssl --passl:-lcrypto --passl:-lssl -r tests/untestable/tssl.nim ## ./bin/nim r --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:ssl -p:testament/lib --threads:on tests/untestable/thttpclient_ssl_remotenetwork.nim +## ``` # https://www.feistyduck.com/library/openssl-cookbook/online/ch-testing-with-openssl.html # diff --git a/nimpretty/tests/exhaustive.nim b/nimpretty/tests/exhaustive.nim index bcf8256656..e5a73305b8 100644 --- a/nimpretty/tests/exhaustive.nim +++ b/nimpretty/tests/exhaustive.nim @@ -693,11 +693,11 @@ proc newRecordGen(ctx: Context; typ: TypRef): PNode = String `interpolation`:idx: / `format`:idx: inspired by Python's ``f``-strings. -.. code-block:: nim - - import strformat - let msg = "hello" - doAssert fmt"{msg}\n" == "hello\\n" + ```nim + import strformat + let msg = "hello" + doAssert fmt"{msg}\n" == "hello\\n" + ``` Because the literal is a raw string literal, the ``\n`` is not interpreted as an escape sequence. diff --git a/nimpretty/tests/expected/exhaustive.nim b/nimpretty/tests/expected/exhaustive.nim index 50ae92a62b..7f78b7e566 100644 --- a/nimpretty/tests/expected/exhaustive.nim +++ b/nimpretty/tests/expected/exhaustive.nim @@ -699,11 +699,11 @@ proc newRecordGen(ctx: Context; typ: TypRef): PNode = String `interpolation`:idx: / `format`:idx: inspired by Python's ``f``-strings. -.. code-block:: nim - - import strformat - let msg = "hello" - doAssert fmt"{msg}\n" == "hello\\n" + ```nim + import strformat + let msg = "hello" + doAssert fmt"{msg}\n" == "hello\\n" + ``` Because the literal is a raw string literal, the ``\n`` is not interpreted as an escape sequence. diff --git a/testament/specs.nim b/testament/specs.nim index 744d1f75ac..5107c9ed71 100644 --- a/testament/specs.nim +++ b/testament/specs.nim @@ -143,27 +143,26 @@ proc extractErrorMsg(s: string; i: int; line: var int; col: var int; spec: var T ## ## Can parse a single message for a line: ## - ## .. code-block:: nim - ## + ## ```nim ## proc generic_proc*[T] {.no_destroy, userPragma.} = #[tt.Error ## ^ 'generic_proc' should be: 'genericProc' [Name] ]# + ## ``` ## ## Can parse multiple messages for a line when they are separated by ';': ## - ## .. code-block:: nim - ## + ## ```nim ## proc generic_proc*[T] {.no_destroy, userPragma.} = #[tt.Error ## ^ 'generic_proc' should be: 'genericProc' [Name]; tt.Error ## ^ 'no_destroy' should be: 'nodestroy' [Name]; tt.Error ## ^ 'userPragma' should be: 'user_pragma' [template declared in mstyleCheck.nim(10, 9)] [Name] ]# + ## ``` ## - ## .. code-block:: nim - ## + ## ```nim ## proc generic_proc*[T] {.no_destroy, userPragma.} = #[tt.Error ## ^ 'generic_proc' should be: 'genericProc' [Name]; ## tt.Error ^ 'no_destroy' should be: 'nodestroy' [Name]; ## tt.Error ^ 'userPragma' should be: 'user_pragma' [template declared in mstyleCheck.nim(10, 9)] [Name] ]# - ## + ## ``` result = i + len(inlineErrorMarker) inc col, len(inlineErrorMarker) let msgLine = line diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index e2c1b0a045..0ad57167bb 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -168,14 +168,14 @@ template new_parsed_parameter*(tkind: Tparam_kind, expr): Tparsed_parameter = ## initialised with. The template figures out at compile time what field to ## assign the variable to, and thus you reduce code clutter and may use this ## to initialise single assignments variables in `let` blocks. Example: - ## - ## .. code-block:: nim + ## ```nim ## let ## parsed_param1 = new_parsed_parameter(PK_FLOAT, 3.41) ## parsed_param2 = new_parsed_parameter(PK_BIGGEST_INT, 2358123 * 23123) ## # The following line doesn't compile due to ## # type mismatch: got <string> but expected 'int' ## #parsed_param3 = new_parsed_parameter(PK_INT, "231") + ## ``` var result {.gensym.}: Tparsed_parameter result.kind = tkind when tkind == PK_EMPTY: discard From 9296b45de44eb371da970021d89499f0be04456b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 15 Aug 2023 21:42:26 +0800 Subject: [PATCH 443/489] update test command of important packages (#22485) --- testament/important_packages.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testament/important_packages.nim b/testament/important_packages.nim index 9016a0d3dc..f831311bee 100644 --- a/testament/important_packages.nim +++ b/testament/important_packages.nim @@ -46,7 +46,7 @@ pkg "BipBuffer" pkg "blscurve", allowFailure = true pkg "bncurve" pkg "brainfuck", "nim c -d:release -r tests/compile.nim" -pkg "bump", "nim c --gc:arc --path:. -r tests/tbump.nim", "https://github.com/disruptek/bump", allowFailure = true +pkg "bump", "nim c --mm:arc --path:. -r tests/tbump.nim", "https://github.com/disruptek/bump", allowFailure = true pkg "c2nim", "nim c testsuite/tester.nim" pkg "cascade" pkg "cello", url = "https://github.com/nim-lang/cello", useHead = true @@ -55,7 +55,7 @@ pkg "chroma" pkg "chronicles", "nim c -o:chr -r chronicles.nim" pkg "chronos", "nim c -r -d:release tests/testall" pkg "cligen", "nim c --path:. -r cligen.nim" -pkg "combparser", "nimble test --gc:orc" +pkg "combparser", "nimble test --mm:orc" pkg "compactdict" pkg "comprehension", "nimble test", "https://github.com/alehander92/comprehension" pkg "cowstrings" @@ -75,7 +75,7 @@ pkg "glob" pkg "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" pkg "gittyup", "nimble test", "https://github.com/disruptek/gittyup", allowFailure = true pkg "gnuplot", "nim c gnuplot.nim" -# pkg "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" +# pkg "gram", "nim c -r --mm:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" # pending https://github.com/nim-lang/Nim/issues/16509 pkg "hts", "nim c -o:htss src/hts.nim" pkg "httpauth" @@ -91,7 +91,7 @@ pkg "lockfreequeues" pkg "macroutils" pkg "manu" pkg "markdown" -pkg "measuremancer", "nimble install -y unchained@#HEAD; nimble -y test" +pkg "measuremancer", "nimble testDeps; nimble -y test" # when unchained is version 0.3.7 or higher, use `nimble testDeps;` pkg "memo" pkg "msgpack4nim", "nim c -r tests/test_spec.nim" @@ -121,7 +121,7 @@ pkg "nimsl" pkg "nimsvg" pkg "nimterop", "nimble minitest", url = "https://github.com/nim-lang/nimterop" pkg "nimwc", "nim c nimwc.nim", allowFailure = true -pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true +pkg "nimx", "nim c test/main.nim", allowFailure = true pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter" pkg "norm", "testament r tests/common/tmodel.nim" pkg "npeg", "nimble testarc" @@ -145,7 +145,7 @@ pkg "RollingHash", "nim c -r tests/test_cyclichash.nim" pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim" pkg "sdl1", "nim c -r src/sdl.nim" pkg "sdl2_nim", "nim c -r sdl2/sdl.nim" -pkg "sigv4", "nim c --gc:arc -r sigv4.nim", "https://github.com/disruptek/sigv4" +pkg "sigv4", "nim c --mm:arc -r sigv4.nim", "https://github.com/disruptek/sigv4" pkg "sim" pkg "smtp", "nimble compileExample" pkg "snip", "nimble test", "https://github.com/genotrance/snip" From 6c4e7835bf9c1fea608c1f9f55026095fcdd14b2 Mon Sep 17 00:00:00 2001 From: Jason Beetham <beefers331@gmail.com> Date: Tue, 15 Aug 2023 09:48:31 -0600 Subject: [PATCH 444/489] When in object handles procedure call again, fixes #22474 (#22480) Ping @narimiran please backport to the 2.0 line. --- compiler/semtypinst.nim | 2 +- tests/objects/twhen1.nim | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 56b922fdaf..d01ca28e43 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -204,7 +204,7 @@ proc hasValuelessStatics(n: PNode): bool = a proc doThing(_: MyThing) ]# - if n.safeLen == 0: + if n.safeLen == 0 and n.kind != nkEmpty: # Some empty nodes can get in here n.typ == nil or n.typ.kind == tyStatic else: for x in n: diff --git a/tests/objects/twhen1.nim b/tests/objects/twhen1.nim index 5b8eea3f46..fe072a46b1 100644 --- a/tests/objects/twhen1.nim +++ b/tests/objects/twhen1.nim @@ -55,3 +55,35 @@ type x: int when (NimMajor, NimMinor) >= (1, 1): y: int +discard MyObject(x: 100, y: 200) + +block: # Ensure when evaluates properly in objects + type X[bits: static int] = object #22474 + when bits >= 256: + data32: byte + else: + data16: byte + + static: + discard X[255]().data16 + discard X[256]().data32 + + + type ComplexExprObject[S: static string, I: static int, Y: static auto] = object + when 'h' in S and I < 10 and Y isnot float: + a: int + elif I > 30: + b: int + elif typeof(Y) is float: + c: int + else: + d: int + + static: + discard ComplexExprObject["hello", 9, 300i32]().a + discard ComplexExprObject["", 40, 30f]().b + discard ComplexExprObject["", 20, float 30]().c + discard ComplexExprObject["", 20, ""]().d + + + From ade75a148332e670244a719202f7f0337d2e469a Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 16 Aug 2023 05:31:44 +0800 Subject: [PATCH 445/489] fixes #22481; fixes `card` undefined misalignment behavior (#22484) * fixes `card` undefined misalignment behavior * Update lib/system/sets.nim --------- Co-authored-by: Andreas Rumpf <rumpf_a@web.de> --- lib/system/sets.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/system/sets.nim b/lib/system/sets.nim index 5f7c3e37b8..97431c2964 100644 --- a/lib/system/sets.nim +++ b/lib/system/sets.nim @@ -13,9 +13,11 @@ proc cardSetImpl(s: ptr UncheckedArray[uint8], len: int): int {.inline.} = var i = 0 result = 0 + var num = 0'u64 when defined(x86) or defined(amd64): while i < len - 8: - inc(result, countBits64((cast[ptr uint64](s[i].unsafeAddr))[])) + copyMem(addr num, addr s[i], 8) + inc(result, countBits64(num)) inc(i, 8) while i < len: From 940b1607b8459b4b7b7e20d316bec95c8de85809 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 16 Aug 2023 19:46:44 +0800 Subject: [PATCH 446/489] fixes #22357; don't sink elements of var tuple cursors (#22486) --- compiler/injectdestructors.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index aa6470d349..829076d493 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -185,7 +185,9 @@ proc isCursor(n: PNode): bool = template isUnpackedTuple(n: PNode): bool = ## we move out all elements of unpacked tuples, ## hence unpacked tuples themselves don't need to be destroyed - (n.kind == nkSym and n.sym.kind == skTemp and n.sym.typ.kind == tyTuple) + ## except it's already a cursor + (n.kind == nkSym and n.sym.kind == skTemp and + n.sym.typ.kind == tyTuple and sfCursor notin n.sym.flags) proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFromCopy = false) = var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">" From 299394d21a3b7f2af02c8cdede1dcd0cd5948a0e Mon Sep 17 00:00:00 2001 From: Amjad Ben Hedhili <amjadhedhili@outlook.com> Date: Thu, 17 Aug 2023 05:38:15 +0100 Subject: [PATCH 447/489] Fix `seq.capacity` (#22488) --- lib/system/seqs_v2.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index efc2919fd4..3a49142bf4 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -141,7 +141,7 @@ proc newSeq[T](s: var seq[T], len: Natural) = template capacityImpl(sek: NimSeqV2): int = - if sek.p != nil: (xu.p.cap and not strlitFlag) else: 0 + if sek.p != nil: (sek.p.cap and not strlitFlag) else: 0 func capacity*[T](self: seq[T]): int {.inline.} = ## Returns the current capacity of the seq. @@ -153,7 +153,7 @@ func capacity*[T](self: seq[T]): int {.inline.} = {.cast(noSideEffect).}: let sek = unsafeAddr self - result = capacityImpl(cast[ptr NimSeqV2](sek)[]) + result = capacityImpl(cast[ptr NimSeqV2[T]](sek)[]) {.pop.} # See https://github.com/nim-lang/Nim/issues/21401 From 60307cc373cf6bf794f4b3494f3cb8b983f2de43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= <info@jmgomez.me> Date: Thu, 17 Aug 2023 11:20:22 +0100 Subject: [PATCH 448/489] updates manual with codegenDecl on params docs (#22333) * documents member * Update doc/manual_experimental.md Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com> --------- Co-authored-by: Andreas Rumpf <rumpf_a@web.de> Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com> --- doc/manual_experimental.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md index b0ce775ee1..72e883cbc3 100644 --- a/doc/manual_experimental.md +++ b/doc/manual_experimental.md @@ -2385,8 +2385,7 @@ Notice when calling a constructor in the section of a global variable initializa Member pragma ============= -Similar to the `constructor` and `virtual` pragmas, the `member` pragma can be used to attach a `proc` or `func` to a type in C++. -It is more flexible than `virtual` in the sense that it accepts not only names but also operators or destructors. +Like the `constructor` and `virtual` pragmas, the `member` pragma can be used to attach a procedure to a C++ type. It's more flexible than the `virtual` pragma in the sense that it accepts not only names but also operators and destructors. For example: @@ -2439,4 +2438,4 @@ proc `()`(f: NimFunctor; n:int) {.importcpp: "#(@)" .} NimFunctor()(1) ``` Notice we use the overload of `()` to have the same semantics in Nim, but on the `importcpp` we import the functor as a function. -This allows to easy interop with functions that accepts for example a `const` operator in its signature. \ No newline at end of file +This allows to easy interop with functions that accepts for example a `const` operator in its signature. From ee817557ecccf0562cb3e6d4f4c72dcef4fe5e64 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 17 Aug 2023 19:33:19 +0800 Subject: [PATCH 449/489] =?UTF-8?q?close=20#22748;=20cursorinference=20+?= =?UTF-8?q?=20-d:nimNoLentIterators=20results=20in=20err=E2=80=A6=20(#2249?= =?UTF-8?q?5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closed #22748; cursorinference + -d:nimNoLentIterators results in erroneous recursion --- tests/arc/t22478.nim | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/arc/t22478.nim diff --git a/tests/arc/t22478.nim b/tests/arc/t22478.nim new file mode 100644 index 0000000000..5373fa1616 --- /dev/null +++ b/tests/arc/t22478.nim @@ -0,0 +1,46 @@ +discard """ + matrix: "-d:nimNoLentIterators --mm:arc" + output: '''PUSH DATA: {"test.message":{"test":{"nested":"v1"}}}''' + joinable: false +""" + +# bug #22748 +import std/[json, typetraits, times] + +# publish + +proc publish*[T](payload: T) = + discard + +type MetricsPoint* = JsonNode + +proc push*(stat: string, data: JsonNode, usec: int64 = 0) = + let payload = newJObject() + + # this results in a infinite recursion unless we deepCopy() + payload[stat] = data #.deepCopy + + echo "PUSH DATA: ", payload + + publish[MetricsPoint](payload) + +var scopes {.threadvar.}: seq[JsonNode] + +type WithTimeCallback*[T] = proc(data: var JsonNode): T + +proc pushScoped*[T](metric: string, blk: WithTimeCallback[T]): T {.gcsafe.} = + scopes.add newJObject() + defer: discard scopes.pop() + + let stc = (cpuTime() * 1000_000).int64 + result = blk(scopes[^1]) + let dfc = (cpuTime() * 1000_000).int64 - stc + + push(metric, scopes[^1], dfc) + +# demo code + +discard pushScoped[int]("test.message") do (data: var JsonNode) -> int: + data["test"] = %*{ + "nested": "v1" + } \ No newline at end of file From 2e3d9cdbee6c5ca7c439cfedf8bcb9f0f232a960 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 17 Aug 2023 19:54:00 +0800 Subject: [PATCH 450/489] fixes #22441; build documentation for more modules in the checksums (#22453) Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com> --- tools/kochdocs.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index 750f3dcd54..ce6b83980d 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -167,6 +167,9 @@ pkgs/db_connector/src/db_connector/db_postgres.nim pkgs/db_connector/src/db_connector/db_sqlite.nim pkgs/checksums/src/checksums/md5.nim pkgs/checksums/src/checksums/sha1.nim +pkgs/checksums/src/checksums/sha2.nim +pkgs/checksums/src/checksums/sha3.nim +pkgs/checksums/src/checksums/bcrypt.nim """.splitWhitespace() officialPackagesListWithoutIndex = """ From 019b488e1fcf1782b4452dac8a31965e1a4becae Mon Sep 17 00:00:00 2001 From: Nan Xiao <nan@chinadtrace.org> Date: Thu, 17 Aug 2023 20:26:33 +0800 Subject: [PATCH 451/489] fixes syncio document (#22498) --- lib/std/syncio.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/syncio.nim b/lib/std/syncio.nim index a2a5c305b6..879301f8af 100644 --- a/lib/std/syncio.nim +++ b/lib/std/syncio.nim @@ -359,12 +359,12 @@ proc getOsFileHandle*(f: File): FileHandle = when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(windows): proc setInheritable*(f: FileHandle, inheritable: bool): bool = - ## control whether a file handle can be inherited by child processes. Returns + ## Controls whether a file handle can be inherited by child processes. Returns ## `true` on success. This requires the OS file handle, which can be ## retrieved via `getOsFileHandle <#getOsFileHandle,File>`_. ## ## This procedure is not guaranteed to be available for all platforms. Test for - ## availability with `declared() <system.html#declared,untyped>`. + ## availability with `declared() <system.html#declared,untyped>`_. when SupportIoctlInheritCtl: result = c_ioctl(f, if inheritable: FIONCLEX else: FIOCLEX) != -1 elif defined(freertos) or defined(zephyr): From fede75723824e06f59f23b38a9016d3f8cdf71db Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 17 Aug 2023 22:48:28 +0800 Subject: [PATCH 452/489] bump checksums (#22497) --- koch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koch.nim b/koch.nim index 8e94b51507..571242a363 100644 --- a/koch.nim +++ b/koch.nim @@ -13,7 +13,7 @@ const # examples of possible values for repos: Head, ea82b54 NimbleStableCommit = "168416290e49023894fc26106799d6f1fc964a2d" # master AtlasStableCommit = "7b780811a168f3f32bff4822369dda46a7f87f9a" - ChecksumsStableCommit = "b4c73320253f78e3a265aec6d9e8feb83f97c77b" + ChecksumsStableCommit = "025bcca3915a1b9f19878cea12ad68f9884648fc" # examples of possible values for fusion: #head, #ea82b54, 1.2.3 FusionStableHash = "#372ee4313827ef9f2ea388840f7d6b46c2b1b014" From 98c39e8e571b95e7d9351c7115f897ce9af1a218 Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Thu, 17 Aug 2023 19:52:28 +0300 Subject: [PATCH 453/489] cascade tyFromExpr in type conversions in generic bodies (#22499) fixes #22490, fixes #22491, adapts #22029 to type conversions --- compiler/semexprs.nim | 12 +++++++----- tests/statictypes/tgenericcomputedrange.nim | 8 ++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index df65b33712..52d1f0628e 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -311,7 +311,7 @@ proc isOwnedSym(c: PContext; n: PNode): bool = let s = qualifiedLookUp(c, n, {}) result = s != nil and sfSystemModule in s.owner.flags and s.name.s == "owned" -proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode = +proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType = nil): PNode = if n.len != 2: localError(c.config, n.info, "a type conversion takes exactly one argument") return n @@ -358,7 +358,7 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode = if n[1].kind == nkExprEqExpr and targetType.skipTypes(abstractPtrs).kind == tyObject: localError(c.config, n.info, "object construction uses ':', not '='") - var op = semExprWithType(c, n[1]) + var op = semExprWithType(c, n[1], flags * {efDetermineType}) if op.kind == nkClosedSymChoice and op.len > 0 and op[0].sym.kind == skEnumField: # resolves overloadedable enums op = ambiguousSymChoice(c, n, op) @@ -373,7 +373,9 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode = # here or needs to be overwritten too then. result.add op - if targetType.kind == tyGenericParam: + if targetType.kind == tyGenericParam or + (op.typ != nil and op.typ.kind == tyFromExpr and c.inGenericContext > 0): + # expression is compiled early in a generic body result.typ = makeTypeFromExpr(c, copyTree(result)) return result @@ -1075,7 +1077,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType t = skipTypes(n[0].typ, abstractInst+{tyOwned}-{tyTypeDesc, tyDistinct}) if t != nil and t.kind == tyTypeDesc: if n.len == 1: return semObjConstr(c, n, flags, expectedType) - return semConv(c, n) + return semConv(c, n, flags) let nOrig = n.copyTree semOpAux(c, n) @@ -3123,7 +3125,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType # XXX think about this more (``set`` procs) let ambig = c.isAmbiguous if not (n[0].kind in {nkClosedSymChoice, nkOpenSymChoice, nkIdent} and ambig) and n.len == 2: - result = semConv(c, n, expectedType) + result = semConv(c, n, flags, expectedType) elif ambig and n.len == 1: errorUseQualifier(c, n.info, s) elif n.len == 1: diff --git a/tests/statictypes/tgenericcomputedrange.nim b/tests/statictypes/tgenericcomputedrange.nim index 82abe26770..9e3a49ae08 100644 --- a/tests/statictypes/tgenericcomputedrange.nim +++ b/tests/statictypes/tgenericcomputedrange.nim @@ -115,3 +115,11 @@ block: # issue #22187 k: array[p(m(T, s)), int64] var x: F[int, 3] doAssert x.k is array[3, int64] + +block: # issue #22490 + proc log2trunc(x: uint64): int = + if x == 0: int(0) else: int(0) + template maxChunkIdx(T: typedesc): int64 = 0'i64 + template layer(vIdx: int64): int = log2trunc(0'u64) + type HashList[T] = object + indices: array[int(layer(maxChunkIdx(T))), int] From 7fababd583ee5e3c113c0d83a04c07f2ee0ef06d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 18 Aug 2023 00:52:38 +0800 Subject: [PATCH 454/489] make float32 literals stringifying behave in JS the same as in C (#22500) --- compiler/jsgen.nim | 9 +++++++-- tests/float/tfloats.nim | 5 ++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index c566a718a8..1720de17f8 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -32,7 +32,7 @@ import ast, trees, magicsys, options, nversion, msgs, idents, types, ropes, ccgutils, wordrecg, renderer, - cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils, + cgmeth, lowerings, sighashes, modulegraphs, lineinfos, transf, injectdestructors, sourcemap, astmsgs, backendpragmas import pipelineutils @@ -43,6 +43,7 @@ import strutils except addf when defined(nimPreviewSlimSystem): import std/[assertions, syncio] +import std/formatfloat type TJSGen = object of PPassContext @@ -2900,7 +2901,11 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = r.res = rope"Infinity" of fcNegInf: r.res = rope"-Infinity" - else: r.res = rope(f.toStrMaxPrecision) + else: + if n.typ.skipTypes(abstractVarRange).kind == tyFloat32: + r.res.addFloatRoundtrip(f.float32) + else: + r.res.addFloatRoundtrip(f) r.kind = resExpr of nkCallKinds: if isEmptyType(n.typ): diff --git a/tests/float/tfloats.nim b/tests/float/tfloats.nim index 967605c53d..aaed2d615b 100644 --- a/tests/float/tfloats.nim +++ b/tests/float/tfloats.nim @@ -156,9 +156,8 @@ template main = when nimvm: discard # xxx, refs #12884 else: - when not defined(js): - doAssert x == 1.2345679'f32 - doAssert $x == "1.2345679" + doAssert x == 1.2345679'f32 + doAssert $x == "1.2345679" static: main() main() From eb83d20d0d1ab1d0cbd9574a3dc1bcdae949e865 Mon Sep 17 00:00:00 2001 From: Tomohiro <gpuppur@gmail.com> Date: Fri, 18 Aug 2023 23:47:47 +0900 Subject: [PATCH 455/489] Add staticFileExists and staticDirExists (#22278) --- compiler/vmops.nim | 4 ++++ lib/std/staticos.nim | 13 +++++++++++++ tests/stdlib/tstaticos.nim | 8 ++++++++ tests/vm/tvmmisc.nim | 2 ++ 4 files changed, 27 insertions(+) create mode 100644 lib/std/staticos.nim create mode 100644 tests/stdlib/tstaticos.nim diff --git a/compiler/vmops.nim b/compiler/vmops.nim index e81822ba64..23b41fd2ee 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -264,6 +264,10 @@ proc registerAdditionalOps*(c: PCtx) = systemop getCurrentException registerCallback c, "stdlib.osdirs.staticWalkDir", proc (a: VmArgs) {.nimcall.} = setResult(a, staticWalkDirImpl(getString(a, 0), getBool(a, 1))) + registerCallback c, "stdlib.staticos.staticDirExists", proc (a: VmArgs) {.nimcall.} = + setResult(a, dirExists(getString(a, 0))) + registerCallback c, "stdlib.staticos.staticFileExists", proc (a: VmArgs) {.nimcall.} = + setResult(a, fileExists(getString(a, 0))) registerCallback c, "stdlib.compilesettings.querySetting", proc (a: VmArgs) = setResult(a, querySettingImpl(c.config, getInt(a, 0))) registerCallback c, "stdlib.compilesettings.querySettingSeq", proc (a: VmArgs) = diff --git a/lib/std/staticos.nim b/lib/std/staticos.nim new file mode 100644 index 0000000000..2617c69138 --- /dev/null +++ b/lib/std/staticos.nim @@ -0,0 +1,13 @@ +## This module implements path handling like os module but works at only compile-time. +## This module works even when cross compiling to OS that is not supported by os module. + +proc staticFileExists*(filename: string): bool {.compileTime.} = + ## Returns true if `filename` exists and is a regular file or symlink. + ## + ## Directories, device files, named pipes and sockets return false. + discard + +proc staticDirExists*(dir: string): bool {.compileTime.} = + ## Returns true if the directory `dir` exists. If `dir` is a file, false + ## is returned. Follows symlinks. + discard diff --git a/tests/stdlib/tstaticos.nim b/tests/stdlib/tstaticos.nim new file mode 100644 index 0000000000..41ab995dd7 --- /dev/null +++ b/tests/stdlib/tstaticos.nim @@ -0,0 +1,8 @@ +import std/[assertions, staticos, os] + +block: + static: + doAssert staticDirExists("MISSINGFILE") == false + doAssert staticFileExists("MISSINGDIR") == false + doAssert staticDirExists(currentSourcePath().parentDir) + doAssert staticFileExists(currentSourcePath()) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index 1a8f68ee8f..da8208f73e 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -82,6 +82,8 @@ block: doAssert fileExists("MISSINGFILE") == false doAssert dirExists("MISSINGDIR") == false + doAssert fileExists(currentSourcePath()) + doAssert dirExists(currentSourcePath().parentDir) # bug #7210 block: From 20cbdc2741e9e34a99288ded9664378afc80acb6 Mon Sep 17 00:00:00 2001 From: Alberto Torres <kungfoobar@gmail.com> Date: Fri, 18 Aug 2023 21:13:27 +0200 Subject: [PATCH 456/489] Fix #22366 by making nimlf_/nimln_ part of the same line (#22503) Fix #22366 by making nimlf_/nimln_ part of the same line so the debugger doesn't advance to the next line before executing it --- compiler/cgen.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 811f899834..6d301dc475 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -312,10 +312,10 @@ proc genLineDir(p: BProc, t: PNode) = (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx: if freshLine: if lastFileIndex == t.info.fileIndex: - linefmt(p, cpsStmts, "nimln_($1);\n", + linefmt(p, cpsStmts, "nimln_($1);", [line]) else: - linefmt(p, cpsStmts, "nimlf_($1, $2);\n", + linefmt(p, cpsStmts, "nimlf_($1, $2);", [line, quotedFilename(p.config, t.info)]) proc accessThreadLocalVar(p: BProc, s: PSym) From c44c8ddb44b1379720f1f2c42bfa2dafe7fbc11c Mon Sep 17 00:00:00 2001 From: Juan Carlos <juancarlospaco@gmail.com> Date: Sat, 19 Aug 2023 02:05:06 -0300 Subject: [PATCH 457/489] Remove Deprecated Babel (#22507) --- compiler/commands.nim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 749be80f0d..6d162fab26 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -622,8 +622,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; for path in nimbleSubs(conf, arg): addPath(conf, if pass == passPP: processCfgPath(conf, path, info) else: processPath(conf, path, info), info) - of "nimblepath", "babelpath": - if switch.normalize == "babelpath": deprecatedAlias(switch, "nimblepath") + of "nimblepath": if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions: expectArg(conf, switch, arg, pass, info) var path = processPath(conf, arg, info, notRelativeToProj=true) @@ -633,8 +632,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; nimblePath(conf, path, info) path = nimbleDir / RelativeDir"pkgs" nimblePath(conf, path, info) - of "nonimblepath", "nobabelpath": - if switch.normalize == "nobabelpath": deprecatedAlias(switch, "nonimblepath") + of "nonimblepath": expectNoArg(conf, switch, arg, pass, info) disableNimblePath(conf) of "clearnimblepath": From 6eb722c47d7010e83ab953a7f3a9ef5d1e624c56 Mon Sep 17 00:00:00 2001 From: Nan Xiao <nan@chinadtrace.org> Date: Sat, 19 Aug 2023 21:05:17 +0800 Subject: [PATCH 458/489] replace getOpt with getopt (#22515) --- tests/manyloc/keineschweine/dependencies/nake/nake.nim | 2 +- tests/manyloc/keineschweine/enet_server/enet_server.nim | 2 +- tests/manyloc/keineschweine/keineschweine.nim | 2 +- tests/manyloc/keineschweine/server/old_dirserver.nim | 2 +- tests/manyloc/keineschweine/server/old_sg_server.nim | 2 +- tests/manyloc/nake/nake.nim | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/manyloc/keineschweine/dependencies/nake/nake.nim b/tests/manyloc/keineschweine/dependencies/nake/nake.nim index e466ee5e1f..36538097e1 100644 --- a/tests/manyloc/keineschweine/dependencies/nake/nake.nim +++ b/tests/manyloc/keineschweine/dependencies/nake/nake.nim @@ -69,7 +69,7 @@ else: var task: string printTaskList: bool - for kind, key, val in getOpt(): + for kind, key, val in getopt(): case kind of cmdLongOption, cmdShortOption: case key.tolower diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim index 794e1c8439..86d0ab360b 100644 --- a/tests/manyloc/keineschweine/enet_server/enet_server.nim +++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim @@ -113,7 +113,7 @@ when true: block: var zoneCfgFile = "./server_settings.json" - for kind, key, val in getOpt(): + for kind, key, val in getopt(): case kind of cmdShortOption, cmdLongOption: case key diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim index cde31bd181..123a4aebbb 100644 --- a/tests/manyloc/keineschweine/keineschweine.nim +++ b/tests/manyloc/keineschweine/keineschweine.nim @@ -691,7 +691,7 @@ when true: block: var bPlayOffline = false - for kind, key, val in getOpt(): + for kind, key, val in getopt(): case kind of cmdArgument: if key == "offline": bPlayOffline = true diff --git a/tests/manyloc/keineschweine/server/old_dirserver.nim b/tests/manyloc/keineschweine/server/old_dirserver.nim index 70ae05b0bb..a638296913 100644 --- a/tests/manyloc/keineschweine/server/old_dirserver.nim +++ b/tests/manyloc/keineschweine/server/old_dirserver.nim @@ -159,7 +159,7 @@ proc poll*(timeout: int = 250) = when true: import parseopt, strutils var cfgFile = "dirserver_settings.json" - for kind, key, val in getOpt(): + for kind, key, val in getopt(): case kind of cmdShortOption, cmdLongOption: case key diff --git a/tests/manyloc/keineschweine/server/old_sg_server.nim b/tests/manyloc/keineschweine/server/old_sg_server.nim index 8bd44017ed..d6fbbe99ec 100644 --- a/tests/manyloc/keineschweine/server/old_sg_server.nim +++ b/tests/manyloc/keineschweine/server/old_sg_server.nim @@ -144,7 +144,7 @@ proc poll*(timeout: int = 250) = when true: import parseopt, strutils var zoneCfgFile = "./server_settings.json" - for kind, key, val in getOpt(): + for kind, key, val in getopt(): case kind of cmdShortOption, cmdLongOption: case key diff --git a/tests/manyloc/nake/nake.nim b/tests/manyloc/nake/nake.nim index ce7faab5cc..5d3173a200 100644 --- a/tests/manyloc/nake/nake.nim +++ b/tests/manyloc/nake/nake.nim @@ -65,7 +65,7 @@ else: var task: string printTaskList: bool - for kind, key, val in getOpt(): + for kind, key, val in getopt(): case kind of cmdLongOption, cmdShortOption: case key.tolowerAscii From d77ada5bdfe1a0778e37604078a38178fe6045f4 Mon Sep 17 00:00:00 2001 From: Amjad Ben Hedhili <amjadhedhili@outlook.com> Date: Sat, 19 Aug 2023 14:14:56 +0100 Subject: [PATCH 459/489] Markdown code blocks migration part 9 (#22506) * Markdown code blocks migration part 9 * fix [skip ci] --- compiler/astalgo.nim | 2 +- compiler/sigmatch.nim | 2 +- lib/core/macros.nim | 28 ++++----- lib/system.nim | 124 ++++++++++++++++++------------------- lib/system/compilation.nim | 14 ++--- lib/system/indices.nim | 12 ++-- 6 files changed, 91 insertions(+), 91 deletions(-) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 621bd23808..1873d231fe 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -227,7 +227,7 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym = ## Named parameters are special because a named parameter can be ## gensym'ed and then they have '\`<number>' suffix that we need to ## ignore, see compiler / evaltempl.nim, snippet: - ## ``` + ## ```nim ## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id), ## if c.instLines: actual.info else: templ.info) ## ``` diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 048b74547f..7780e53f53 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -576,7 +576,7 @@ proc inconsistentVarTypes(f, a: PType): bool {.inline.} = proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = ## For example we have: - ## ``` + ## ```nim ## proc myMap[T,S](sIn: seq[T], f: proc(x: T): S): seq[S] = ... ## proc innerProc[Q,W](q: Q): W = ... ## ``` diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 3286d7861f..01a654b6c6 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -208,7 +208,7 @@ template `or`*(x, y: NimNode): NimNode = ## Evaluate `x` and when it is not an empty node, return ## it. Otherwise evaluate to `y`. Can be used to chain several ## expressions to get the first expression that is not empty. - ## ``` + ## ```nim ## let node = mightBeEmpty() or mightAlsoBeEmpty() or fallbackNode ## ``` @@ -590,7 +590,7 @@ proc getAst*(macroOrTemplate: untyped): NimNode {.magic: "ExpandToAst", noSideEf ## Obtains the AST nodes returned from a macro or template invocation. ## See also `genasts.genAst`. ## Example: - ## ``` + ## ```nim ## macro FooMacro() = ## var ast = getAst(BarTemplate()) ## ``` @@ -1049,7 +1049,7 @@ macro dumpTree*(s: untyped): untyped = echo s.treeRepr ## a certain expression/statement. ## ## For example: - ## ``` + ## ```nim ## dumpTree: ## echo "Hello, World!" ## ``` @@ -1073,7 +1073,7 @@ macro dumpLisp*(s: untyped): untyped = echo s.lispRepr(indented = true) ## a certain expression/statement. ## ## For example: - ## ``` + ## ```nim ## dumpLisp: ## echo "Hello, World!" ## ``` @@ -1096,7 +1096,7 @@ macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr ## outputs and then copying the snippets into the macro for modification. ## ## For example: - ## ``` + ## ```nim ## dumpAstGen: ## echo "Hello, World!" ## ``` @@ -1179,7 +1179,7 @@ proc newIdentDefs*(name, kind: NimNode; ## `let` or `var` blocks may have an empty `kind` node if the ## identifier is being assigned a value. Example: ## - ## ``` + ## ```nim ## var varSection = newNimNode(nnkVarSection).add( ## newIdentDefs(ident("a"), ident("string")), ## newIdentDefs(ident("b"), newEmptyNode(), newLit(3))) @@ -1190,7 +1190,7 @@ proc newIdentDefs*(name, kind: NimNode; ## ## If you need to create multiple identifiers you need to use the lower level ## `newNimNode`: - ## ``` + ## ```nim ## result = newNimNode(nnkIdentDefs).add( ## ident("a"), ident("b"), ident("c"), ident("string"), ## newStrLitNode("Hello")) @@ -1241,7 +1241,7 @@ proc newProc*(name = newEmptyNode(); proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]): NimNode = ## Constructor for `if` statements. - ## ``` + ## ```nim ## newIfStmt( ## (Ident, StmtList), ## ... @@ -1258,7 +1258,7 @@ proc newEnum*(name: NimNode, fields: openArray[NimNode], ## Creates a new enum. `name` must be an ident. Fields are allowed to be ## either idents or EnumFieldDef: - ## ``` + ## ```nim ## newEnum( ## name = ident("Colors"), ## fields = [ident("Blue"), ident("Red")], @@ -1429,7 +1429,7 @@ iterator children*(n: NimNode): NimNode {.inline.} = template findChild*(n: NimNode; cond: untyped): NimNode {.dirty.} = ## Find the first child node matching condition (or nil). - ## ``` + ## ```nim ## var res = findChild(n, it.kind == nnkPostfix and ## it.basename.ident == ident"foo") ## ``` @@ -1536,7 +1536,7 @@ macro expandMacros*(body: typed): untyped = ## ## For instance, ## - ## ``` + ## ```nim ## import std/[sugar, macros] ## ## let @@ -1652,7 +1652,7 @@ macro hasCustomPragma*(n: typed, cp: typed{nkSym}): untyped = ## ## See also `getCustomPragmaVal`_. ## - ## ``` + ## ```nim ## template myAttr() {.pragma.} ## type ## MyObj = object @@ -1677,7 +1677,7 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped = ## ## See also `hasCustomPragma`_. ## - ## ``` + ## ```nim ## template serializationKey(key: string) {.pragma.} ## type ## MyObj {.serializationKey: "mo".} = object @@ -1773,7 +1773,7 @@ proc extractDocCommentsAndRunnables*(n: NimNode): NimNode = ## runnableExamples in `a`, stopping at the first child that is neither. ## Example: ## - ## ``` + ## ```nim ## import std/macros ## macro transf(a): untyped = ## result = quote do: diff --git a/lib/system.nim b/lib/system.nim index 7b27f226a6..4163534cf6 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -108,7 +108,7 @@ proc `addr`*[T](x: T): ptr T {.magic: "Addr", noSideEffect.} = ## ## Cannot be overloaded. ## - ## ``` + ## ```nim ## var ## buf: seq[char] = @['a','b','c'] ## p = buf[1].addr @@ -194,7 +194,7 @@ proc high*[T: Ordinal|enum|range](x: T): T {.magic: "High", noSideEffect, ## **This proc is deprecated**, use this one instead: ## * `high(typedesc) <#high,typedesc[T]>`_ ## - ## ``` + ## ```nim ## high(2) # => 9223372036854775807 ## ``` @@ -202,7 +202,7 @@ proc high*[T: Ordinal|enum|range](x: typedesc[T]): T {.magic: "High", noSideEffe ## Returns the highest possible value of an ordinal or enum type. ## ## `high(int)` is Nim's way of writing `INT_MAX`:idx: or `MAX_INT`:idx:. - ## ``` + ## ```nim ## high(int) # => 9223372036854775807 ## ``` ## @@ -211,7 +211,7 @@ proc high*[T: Ordinal|enum|range](x: typedesc[T]): T {.magic: "High", noSideEffe proc high*[T](x: openArray[T]): int {.magic: "High", noSideEffect.} ## Returns the highest possible index of a sequence `x`. - ## ``` + ## ```nim ## var s = @[1, 2, 3, 4, 5, 6, 7] ## high(s) # => 6 ## for i in low(s)..high(s): @@ -225,7 +225,7 @@ proc high*[I, T](x: array[I, T]): I {.magic: "High", noSideEffect.} ## Returns the highest possible index of an array `x`. ## ## For empty arrays, the return type is `int`. - ## ``` + ## ```nim ## var arr = [1, 2, 3, 4, 5, 6, 7] ## high(arr) # => 6 ## for i in low(arr)..high(arr): @@ -239,7 +239,7 @@ proc high*[I, T](x: typedesc[array[I, T]]): I {.magic: "High", noSideEffect.} ## Returns the highest possible index of an array type. ## ## For empty arrays, the return type is `int`. - ## ``` + ## ```nim ## high(array[7, int]) # => 6 ## ``` ## @@ -255,7 +255,7 @@ proc high*(x: cstring): int {.magic: "High", noSideEffect.} proc high*(x: string): int {.magic: "High", noSideEffect.} ## Returns the highest possible index of a string `x`. - ## ``` + ## ```nim ## var str = "Hello world!" ## high(str) # => 11 ## ``` @@ -271,7 +271,7 @@ proc low*[T: Ordinal|enum|range](x: T): T {.magic: "Low", noSideEffect, ## **This proc is deprecated**, use this one instead: ## * `low(typedesc) <#low,typedesc[T]>`_ ## - ## ``` + ## ```nim ## low(2) # => -9223372036854775808 ## ``` @@ -279,7 +279,7 @@ proc low*[T: Ordinal|enum|range](x: typedesc[T]): T {.magic: "Low", noSideEffect ## Returns the lowest possible value of an ordinal or enum type. ## ## `low(int)` is Nim's way of writing `INT_MIN`:idx: or `MIN_INT`:idx:. - ## ``` + ## ```nim ## low(int) # => -9223372036854775808 ## ``` ## @@ -288,7 +288,7 @@ proc low*[T: Ordinal|enum|range](x: typedesc[T]): T {.magic: "Low", noSideEffect proc low*[T](x: openArray[T]): int {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of a sequence `x`. - ## ``` + ## ```nim ## var s = @[1, 2, 3, 4, 5, 6, 7] ## low(s) # => 0 ## for i in low(s)..high(s): @@ -302,7 +302,7 @@ proc low*[I, T](x: array[I, T]): I {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of an array `x`. ## ## For empty arrays, the return type is `int`. - ## ``` + ## ```nim ## var arr = [1, 2, 3, 4, 5, 6, 7] ## low(arr) # => 0 ## for i in low(arr)..high(arr): @@ -316,7 +316,7 @@ proc low*[I, T](x: typedesc[array[I, T]]): I {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of an array type. ## ## For empty arrays, the return type is `int`. - ## ``` + ## ```nim ## low(array[7, int]) # => 0 ## ``` ## @@ -331,7 +331,7 @@ proc low*(x: cstring): int {.magic: "Low", noSideEffect.} proc low*(x: string): int {.magic: "Low", noSideEffect.} ## Returns the lowest possible index of a string `x`. - ## ``` + ## ```nim ## var str = "Hello world!" ## low(str) # => 0 ## ``` @@ -409,7 +409,7 @@ proc `..`*[T, U](a: sink T, b: sink U): HSlice[T, U] {.noSideEffect, inline, mag ## ## Slices can also be used in the set constructor and in ordinal case ## statements, but then they are special-cased by the compiler. - ## ``` + ## ```nim ## let a = [10, 20, 30, 40, 50] ## echo a[2 .. 3] # @[30, 40] ## ``` @@ -418,7 +418,7 @@ proc `..`*[T, U](a: sink T, b: sink U): HSlice[T, U] {.noSideEffect, inline, mag proc `..`*[T](b: sink T): HSlice[int, T] {.noSideEffect, inline, magic: "DotDot", deprecated: "replace `..b` with `0..b`".} = ## Unary `slice`:idx: operator that constructs an interval `[default(int), b]`. - ## ``` + ## ```nim ## let a = [10, 20, 30, 40, 50] ## echo a[.. 2] # @[10, 20, 30] ## ``` @@ -573,7 +573,7 @@ proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.} ## sizeof should fallback to the `sizeof` in the C compiler. The ## result isn't available for the Nim compiler and therefore can't ## be used inside of macros. - ## ``` + ## ```nim ## sizeof('A') # => 1 ## sizeof(2) # => 8 ## ``` @@ -604,7 +604,7 @@ proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.} ## Note that the sequence will be filled with zeroed entries. ## After the creation of the sequence you should assign entries to ## the sequence instead of adding them. Example: - ## ``` + ## ```nim ## var inputStrings: seq[string] ## newSeq(inputStrings, 3) ## assert len(inputStrings) == 3 @@ -620,7 +620,7 @@ proc newSeq*[T](len = 0.Natural): seq[T] = ## Note that the sequence will be filled with zeroed entries. ## After the creation of the sequence you should assign entries to ## the sequence instead of adding them. - ## ``` + ## ```nim ## var inputStrings = newSeq[string](3) ## assert len(inputStrings) == 3 ## inputStrings[0] = "The fourth" @@ -638,7 +638,7 @@ proc newSeqOfCap*[T](cap: Natural): seq[T] {. magic: "NewSeqOfCap", noSideEffect.} = ## Creates a new sequence of type `seq[T]` with length zero and capacity ## `cap`. Example: - ## ``` + ## ```nim ## var x = newSeqOfCap[int](5) ## assert len(x) == 0 ## x.add(10) @@ -654,7 +654,7 @@ when not defined(js): ## uninitialized. After the creation of the sequence you should assign ## entries to the sequence instead of adding them. ## Example: - ## ``` + ## ```nim ## var x = newSeqUninitialized[int](3) ## assert len(x) == 3 ## x[0] = 10 @@ -748,7 +748,7 @@ include "system/setops" proc contains*[U, V, W](s: HSlice[U, V], value: W): bool {.noSideEffect, inline.} = ## Checks if `value` is within the range of `s`; returns true if ## `value >= s.a and value <= s.b`. - ## ``` + ## ```nim ## assert((1..3).contains(1) == true) ## assert((1..3).contains(2) == true) ## assert((1..3).contains(4) == false) @@ -760,13 +760,13 @@ when not defined(nimHasCallsitePragma): template `in`*(x, y: untyped): untyped {.dirty, callsite.} = contains(y, x) ## Sugar for `contains`. - ## ``` + ## ```nim ## assert(1 in (1..3) == true) ## assert(5 in (1..3) == false) ## ``` template `notin`*(x, y: untyped): untyped {.dirty, callsite.} = not contains(y, x) ## Sugar for `not contains`. - ## ``` + ## ```nim ## assert(1 notin (1..3) == false) ## assert(5 notin (1..3) == true) ## ``` @@ -776,7 +776,7 @@ proc `is`*[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.} ## ## For a negated version, use `isnot <#isnot.t,untyped,untyped>`_. ## - ## ``` + ## ```nim ## assert 42 is int ## assert @[1, 2] is seq ## @@ -791,7 +791,7 @@ proc `is`*[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.} ## ``` template `isnot`*(x, y: untyped): untyped {.callsite.} = not (x is y) ## Negated version of `is <#is,T,S>`_. Equivalent to `not(x is y)`. - ## ``` + ## ```nim ## assert 42 isnot float ## assert @[1, 2] isnot enum ## ``` @@ -887,7 +887,7 @@ proc cmp*[T](x, y: T): int = ## ## This is useful for writing generic algorithms without performance loss. ## This generic implementation uses the `==` and `<` operators. - ## ``` + ## ```nim ## import std/algorithm ## echo sorted(@[4, 2, 6, 5, 8, 7], cmp[int]) ## ``` @@ -908,7 +908,7 @@ proc `@`* [IDX, T](a: sink array[IDX, T]): seq[T] {.magic: "ArrToSeq", noSideEff ## sequences with the array constructor: `@[1, 2, 3]` has the type ## `seq[int]`, while `[1, 2, 3]` has the type `array[0..2, int]`. ## - ## ``` + ## ```nim ## let ## a = [1, 3, 5] ## b = "foo" @@ -950,7 +950,7 @@ proc setLen*[T](s: var seq[T], newlen: Natural) {. ## ## If the current length is greater than the new length, ## `s` will be truncated. - ## ``` + ## ```nim ## var x = @[10, 20] ## x.setLen(5) ## x[4] = 50 @@ -965,7 +965,7 @@ proc setLen*(s: var string, newlen: Natural) {. ## ## If the current length is greater than the new length, ## `s` will be truncated. - ## ``` + ## ```nim ## var myS = "Nim is great!!" ## myS.setLen(3) # myS <- "Nim" ## echo myS, " is fantastic!!" @@ -990,25 +990,25 @@ proc newStringOfCap*(cap: Natural): string {. proc `&`*(x: string, y: char): string {. magic: "ConStrStr", noSideEffect.} ## Concatenates `x` with `y`. - ## ``` + ## ```nim ## assert("ab" & 'c' == "abc") ## ``` proc `&`*(x, y: char): string {. magic: "ConStrStr", noSideEffect.} ## Concatenates characters `x` and `y` into a string. - ## ``` + ## ```nim ## assert('a' & 'b' == "ab") ## ``` proc `&`*(x, y: string): string {. magic: "ConStrStr", noSideEffect.} ## Concatenates strings `x` and `y`. - ## ``` + ## ```nim ## assert("ab" & "cd" == "abcd") ## ``` proc `&`*(x: char, y: string): string {. magic: "ConStrStr", noSideEffect.} ## Concatenates `x` with `y`. - ## ``` + ## ```nim ## assert('a' & "bc" == "abc") ## ``` @@ -1017,7 +1017,7 @@ proc `&`*(x: char, y: string): string {. proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.} ## Appends `y` to `x` in place. - ## ``` + ## ```nim ## var tmp = "" ## tmp.add('a') ## tmp.add('b') @@ -1150,7 +1150,7 @@ when defined(nimscript) or not defined(nimSeqsV2): ## containers should also call their adding proc `add` for consistency. ## Generic code becomes much easier to write if the Nim naming scheme is ## respected. - ## ``` + ## ```nim ## var s: seq[string] = @["test2","test2"] ## s.add("test") ## assert s == @["test2", "test2", "test"] @@ -1164,7 +1164,7 @@ when false: # defined(gcDestructors): ## containers should also call their adding proc `add` for consistency. ## Generic code becomes much easier to write if the Nim naming scheme is ## respected. - ## ``` + ## ```nim ## var s: seq[string] = @["test2","test2"] ## s.add("test") # s <- @[test2, test2, test] ## ``` @@ -1230,7 +1230,7 @@ proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} = proc insert*[T](x: var seq[T], item: sink T, i = 0.Natural) {.noSideEffect.} = ## Inserts `item` into `x` at position `i`. - ## ``` + ## ```nim ## var i = @[1, 3, 5] ## i.insert(99, 0) # i <- @[99, 1, 3, 5] ## ``` @@ -1261,7 +1261,7 @@ when not defined(nimV2): ## ## It works even for complex data graphs with cycles. This is a great ## debugging tool. - ## ``` + ## ```nim ## var s: seq[string] = @["test2", "test2"] ## var i = @[1, 2, 3, 4, 5] ## echo repr(s) # => 0x1055eb050[0x1055ec050"test2", 0x1055ec078"test2"] @@ -1294,7 +1294,7 @@ proc toFloat*(i: int): float {.noSideEffect, inline.} = ## If the conversion fails, `ValueError` is raised. ## However, on most platforms the conversion cannot fail. ## - ## ``` + ## ```nim ## let ## a = 2 ## b = 3.7 @@ -1317,7 +1317,7 @@ proc toInt*(f: float): int {.noSideEffect.} = ## ## Note that some floating point numbers (e.g. infinity or even 1e19) ## cannot be accurately converted. - ## ``` + ## ```nim ## doAssert toInt(0.49) == 0 ## doAssert toInt(0.5) == 1 ## doAssert toInt(-0.5) == -1 # rounding is symmetrical @@ -1330,7 +1330,7 @@ proc toBiggestInt*(f: BiggestFloat): BiggestInt {.noSideEffect.} = proc `/`*(x, y: int): float {.inline, noSideEffect.} = ## Division of integers that results in a float. - ## ``` + ## ```nim ## echo 7 / 5 # => 1.4 ## ``` ## @@ -1397,7 +1397,7 @@ proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.} ## This is often more efficient than `tmp = a; a = b; b = tmp`. ## Particularly useful for sorting algorithms. ## - ## ``` + ## ```nim ## var ## a = 5 ## b = 9 @@ -1436,7 +1436,7 @@ include "system/iterators_1" proc len*[U: Ordinal; V: Ordinal](x: HSlice[U, V]): int {.noSideEffect, inline.} = ## Length of ordinal slice. When x.b < x.a returns zero length. - ## ``` + ## ```nim ## assert((0..5).len == 6) ## assert((5..2).len == 0) ## ``` @@ -1477,7 +1477,7 @@ when defined(nimSeqsV2): ## Concatenates two sequences. ## ## Requires copying of the sequences. - ## ``` + ## ```nim ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) ## ``` ## @@ -1493,7 +1493,7 @@ when defined(nimSeqsV2): ## Appends element y to the end of the sequence. ## ## Requires copying of the sequence. - ## ``` + ## ```nim ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) ## ``` ## @@ -1508,7 +1508,7 @@ when defined(nimSeqsV2): ## Prepends the element x to the beginning of the sequence. ## ## Requires copying of the sequence. - ## ``` + ## ```nim ## assert(1 & @[2, 3, 4] == @[1, 2, 3, 4]) ## ``` newSeq(result, y.len + 1) @@ -1522,7 +1522,7 @@ else: ## Concatenates two sequences. ## ## Requires copying of the sequences. - ## ``` + ## ```nim ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) ## ``` ## @@ -1538,7 +1538,7 @@ else: ## Appends element y to the end of the sequence. ## ## Requires copying of the sequence. - ## ``` + ## ```nim ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) ## ``` ## @@ -1553,7 +1553,7 @@ else: ## Prepends the element x to the beginning of the sequence. ## ## Requires copying of the sequence. - ## ``` + ## ```nim ## assert(1 & @[2, 3, 4] == @[1, 2, 3, 4]) ## ``` newSeq(result, y.len + 1) @@ -1574,7 +1574,7 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[ ## to retrieve information about the current filename and line number. ## Example: ## - ## ``` + ## ```nim ## import std/strutils ## ## template testException(exception, code: untyped): typed = @@ -1674,7 +1674,7 @@ proc contains*[T](a: openArray[T], item: T): bool {.inline.}= ## ## This allows the `in` operator: `a.contains(item)` is the same as ## `item in a`. - ## ``` + ## ```nim ## var a = @[1, 3, 5] ## assert a.contains(5) ## assert 3 in a @@ -1768,7 +1768,7 @@ when notJSnotNims: ## ## `outOfMemHook` can be used to raise an exception in case of OOM like so: ## - ## ``` + ## ```nim ## var gOutOfMem: ref EOutOfMemory ## new(gOutOfMem) # need to be allocated *before* OOM really happened! ## gOutOfMem.msg = "out of memory" @@ -1882,7 +1882,7 @@ template likely*(val: bool): bool = ## You can use this template to decorate a branch condition. On certain ## platforms this can help the processor predict better which branch is ## going to be run. Example: - ## ``` + ## ```nim ## for value in inputValues: ## if likely(value <= 100): ## process(value) @@ -1906,7 +1906,7 @@ template unlikely*(val: bool): bool = ## You can use this proc to decorate a branch condition. On certain ## platforms this can help the processor predict better which branch is ## going to be run. Example: - ## ``` + ## ```nim ## for value in inputValues: ## if unlikely(value > 100): ## echo "Value too big!" @@ -2102,7 +2102,7 @@ when notJSnotNims: ## is pressed. Only one such hook is supported. ## Example: ## - ## ``` + ## ```nim ## proc ctrlc() {.noconv.} = ## echo "Ctrl+C fired!" ## # do clean up stuff @@ -2339,7 +2339,7 @@ include "system/indices" proc `&=`*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} ## Appends in place to a string. - ## ``` + ## ```nim ## var a = "abc" ## a &= "de" # a <- "abcde" ## ``` @@ -2418,7 +2418,7 @@ proc repr*[T, U](x: HSlice[T, U]): string = when hasAlloc or defined(nimscript): proc insert*(x: var string, item: string, i = 0.Natural) {.noSideEffect.} = ## Inserts `item` into `x` at position `i`. - ## ``` + ## ```nim ## var a = "abc" ## a.insert("zz", 0) # a <- "zzabc" ## ``` @@ -2497,7 +2497,7 @@ proc addQuoted*[T](s: var string, x: T) = ## Users may overload `addQuoted` for custom (string-like) types if ## they want to implement a customized element representation. ## - ## ``` + ## ```nim ## var tmp = "" ## tmp.addQuoted(1) ## tmp.add(", ") @@ -2539,7 +2539,7 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} = ## the official signature says, the return type is *not* `RootObj` but a ## tuple of a structure that depends on the current scope. Example: ## - ## ``` + ## ```nim ## proc testLocals() = ## var ## a = "something" @@ -2578,7 +2578,7 @@ when hasAlloc and notJSnotNims: proc procCall*(x: untyped) {.magic: "ProcCall", compileTime.} = ## Special magic to prohibit dynamic binding for `method`:idx: calls. ## This is similar to `super`:idx: in ordinary OO languages. - ## ``` + ## ```nim ## # 'someMethod' will be resolved fully statically: ## procCall someMethod(a, b) ## ``` @@ -2603,7 +2603,7 @@ template closureScope*(body: untyped): untyped = ## ## Example: ## - ## ``` + ## ```nim ## var myClosure : proc() ## # without closureScope: ## for i in 0 .. 5: @@ -2623,7 +2623,7 @@ template closureScope*(body: untyped): untyped = template once*(body: untyped): untyped = ## Executes a block of code only once (the first time the block is reached). - ## ``` + ## ```nim ## proc draw(t: Triangle) = ## once: ## graphicsInit() diff --git a/lib/system/compilation.nim b/lib/system/compilation.nim index c36bd98319..7cf80eb170 100644 --- a/lib/system/compilation.nim +++ b/lib/system/compilation.nim @@ -1,7 +1,7 @@ const NimMajor* {.intdefine.}: int = 2 ## is the major number of Nim's version. Example: - ## ``` + ## ```nim ## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard ## ``` # see also std/private/since @@ -40,7 +40,7 @@ proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.} ## `x` is an external symbol introduced through the compiler's ## `-d:x switch <nimc.html#compiler-usage-compileminustime-symbols>`_ to enable ## build time conditionals: - ## ``` + ## ```nim ## when not defined(release): ## # Do here programmer friendly expensive sanity checks. ## # Put here the normal code @@ -57,7 +57,7 @@ proc declared*(x: untyped): bool {.magic: "Declared", noSideEffect, compileTime. ## ## This can be used to check whether a library provides a certain ## feature or not: - ## ``` + ## ```nim ## when not declared(strutils.toUpper): ## # provide our own toUpper proc here, because strutils is ## # missing it. @@ -74,7 +74,7 @@ proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime. ## Special compile-time procedure that checks whether `x` can be compiled ## without any semantic error. ## This can be used to check whether a type supports some operation: - ## ``` + ## ```nim ## when compiles(3 + 4): ## echo "'+' for integers is available" ## ``` @@ -164,7 +164,7 @@ proc staticRead*(filename: string): string {.magic: "Slurp".} ## ## The maximum file size limit that `staticRead` and `slurp` can read is ## near or equal to the *free* memory of the device you are using to compile. - ## ``` + ## ```nim ## const myResource = staticRead"mydatafile.bin" ## ``` ## @@ -181,7 +181,7 @@ proc staticExec*(command: string, input = "", cache = ""): string {. ## ## If `input` is not an empty string, it will be passed as a standard input ## to the executed program. - ## ``` + ## ```nim ## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") & ## "\nCompiled on " & staticExec("uname -v") ## ``` @@ -197,7 +197,7 @@ proc staticExec*(command: string, input = "", cache = ""): string {. ## behaviour then. `command & input & cache` (the concatenated string) is ## used to determine whether the entry in the cache is still valid. You can ## use versioning information for `cache`: - ## ``` + ## ```nim ## const stateMachine = staticExec("dfaoptimizer", "input", "0.8.0") ## ``` diff --git a/lib/system/indices.nim b/lib/system/indices.nim index fd6770e232..f4a1403464 100644 --- a/lib/system/indices.nim +++ b/lib/system/indices.nim @@ -10,7 +10,7 @@ template `^`*(x: int): BackwardsIndex = BackwardsIndex(x) ## Builtin `roof`:idx: operator that can be used for convenient array access. ## `a[^x]` is a shortcut for `a[a.len-x]`. ## - ## ``` + ## ```nim ## let ## a = [1, 3, 5, 7, 9] ## b = "abcdefgh" @@ -46,7 +46,7 @@ template `..^`*(a, b: untyped): untyped = template `..<`*(a, b: untyped): untyped = ## A shortcut for `a .. pred(b)`. - ## ``` + ## ```nim ## for i in 5 ..< 9: ## echo i # => 5; 6; 7; 8 ## ``` @@ -76,7 +76,7 @@ template spliceImpl(s, a, L, b: typed): untyped = proc `[]`*[T, U: Ordinal](s: string, x: HSlice[T, U]): string {.inline, systemRaisesDefect.} = ## Slice operation for strings. ## Returns the inclusive range `[s[x.a], s[x.b]]`: - ## ``` + ## ```nim ## var s = "abcdef" ## assert s[1..3] == "bcd" ## ``` @@ -106,7 +106,7 @@ proc `[]=`*[T, U: Ordinal](s: var string, x: HSlice[T, U], b: string) {.systemRa proc `[]`*[Idx, T; U, V: Ordinal](a: array[Idx, T], x: HSlice[U, V]): seq[T] {.systemRaisesDefect.} = ## Slice operation for arrays. ## Returns the inclusive range `[a[x.a], a[x.b]]`: - ## ``` + ## ```nim ## var a = [1, 2, 3, 4] ## assert a[0..2] == @[1, 2, 3] ## ``` @@ -117,7 +117,7 @@ proc `[]`*[Idx, T; U, V: Ordinal](a: array[Idx, T], x: HSlice[U, V]): seq[T] {.s proc `[]=`*[Idx, T; U, V: Ordinal](a: var array[Idx, T], x: HSlice[U, V], b: openArray[T]) {.systemRaisesDefect.} = ## Slice assignment for arrays. - ## ``` + ## ```nim ## var a = [10, 20, 30, 40, 50] ## a[1..2] = @[99, 88] ## assert a == [10, 99, 88, 40, 50] @@ -132,7 +132,7 @@ proc `[]=`*[Idx, T; U, V: Ordinal](a: var array[Idx, T], x: HSlice[U, V], b: ope proc `[]`*[T; U, V: Ordinal](s: openArray[T], x: HSlice[U, V]): seq[T] {.systemRaisesDefect.} = ## Slice operation for sequences. ## Returns the inclusive range `[s[x.a], s[x.b]]`: - ## ``` + ## ```nim ## var s = @[1, 2, 3, 4] ## assert s[0..2] == @[1, 2, 3] ## ``` From 93407096db4192a77002fad9d974d46878c2186b Mon Sep 17 00:00:00 2001 From: PhilippMDoerner <philippmdoerner@web.de> Date: Sat, 19 Aug 2023 17:25:38 +0200 Subject: [PATCH 460/489] #22514 expand testament option docs (#22516) * #22514 Expand docs on testament spec options The file, line and column options of testament are not in the docs, but can be very important to know. They allow you to specify where a compile-time error originated from. Particularly given that testament assumes the origin to always be the test-file, this is important to know. * #22514 Specify nimout relevance a bit more * #22514 Fix slightly erroneous doc-link * #22514 Add example * #22514 Add some docs on ccodecheck --- doc/testament.md | 61 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/doc/testament.md b/doc/testament.md index 08c3cd8353..0ff3591ac9 100644 --- a/doc/testament.md +++ b/doc/testament.md @@ -112,8 +112,21 @@ Example "template" **to edit** and write a Testament unittest: # "run": expect successful compilation and execution # "reject": expect failed compilation. The "reject" action can catch # {.error.} pragmas but not {.fatal.} pragmas because + # {.error.} calls are expected to originate from the test-file, + # and can explicitly be specified using the "file", "line" and + # "column" options. # {.fatal.} pragmas guarantee that compilation will be aborted. action: "run" + + # For testing failed compilations you can specify the expected origin of the + # compilation error. + # With the "file", "line" and "column" options you can define the file, + # line and column that a compilation-error should have originated from. + # Use only with action: "reject" as it expects a failed compilation. + # Requires errormsg or msg to be defined. + # file: "" + # line: "" + # column: "" # The exit code that the test is expected to return. Typically, the default # value of 0 is fine. Note that if the test will be run by valgrind, then @@ -127,13 +140,14 @@ Example "template" **to edit** and write a Testament unittest: output: "" outputsub: "" - # Whether to sort the output lines before comparing them to the desired - # output. + # Whether to sort the compiler output lines before comparing them to the + # expected output. sortoutput: true - # Each line in the string given here appears in the same order in the - # compiler output, but there may be more lines that appear before, after, or - # in between them. + # Provide a `nimout` string to assert that the compiler during compilation + # prints the defined lines to the standard out. + # The lines must match in order, but there may be more lines that appear + # before, after, or in between them. nimout: ''' a very long, multi-line @@ -160,6 +174,9 @@ Example "template" **to edit** and write a Testament unittest: # "leaks": run the test with Valgrind, but do not check for memory leaks valgrind: false # Can use Valgrind to check for memory leaks, or not (Linux 64Bit only). + # Checks that the specified piece of C-code is within the generated C-code. + ccodecheck: "'Assert error message'" + # Command the test should use to run. If left out or an empty string is # provided, the command is taken to be: # "nim $target --hints:on -d:testing --nimblePath:build/deps/pkgs $options $file" @@ -196,7 +213,7 @@ Example "template" **to edit** and write a Testament unittest: * As you can see the "Spec" is just a `discard """ """`. * Spec has sane defaults, so you don't need to provide them all, any simple assert will work just fine. * This is not the full spec of Testament, check [the Testament Spec on GitHub, - see parseSpec()](https://github.com/nim-lang/Nim/blob/devel/testament/specs.nim#L315). + see parseSpec()](https://github.com/nim-lang/Nim/blob/devel/testament/specs.nim#L317). * Nim itself uses Testament, so [there are plenty of test examples]( https://github.com/nim-lang/Nim/tree/devel/tests). * Has some built-in CI compatibility, like Azure Pipelines, etc. @@ -283,6 +300,38 @@ Expected to fail: assert not_defined == "not_defined", "not_defined is not defined" ``` +Expected to fail with error thrown from another file: +```nim +# test.nim +discard """ + action: "reject" + errorMsg: "I break" + file: "breakPragma.nim" +""" +import ./breakPragma + +proc x() {.justDo.} = discard + +# breakPragma.nim +import std/macros + +macro justDo*(procDef: typed): untyped = + error("I break") + return procDef +``` + +Expecting generated C to contain a given piece of code: + + ```nim + discard """ + # Checks that the string "Assert error message" is in the generated + # C code. + ccodecheck: "'Assert error message'" + """ + assert 42 == 42, "Assert error message" + ``` + + Non-Zero exit code: ```nim From c0ecdb01a967b1b903a756abf7202bfbd95ec7b1 Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Sat, 19 Aug 2023 21:04:25 +0200 Subject: [PATCH 461/489] Fix #21722 (#22512) * Keep return in mind for sink * Keep track of return using bool instead of mode * Update compiler/injectdestructors.nim * Add back IsReturn --------- Co-authored-by: SirOlaf <> Co-authored-by: Andreas Rumpf <rumpf_a@web.de> --- compiler/injectdestructors.nim | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 829076d493..a5ec6c21a6 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -79,11 +79,11 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode = proc nestedScope(parent: var Scope; body: PNode): Scope = Scope(vars: @[], locals: @[], wasMoved: @[], final: @[], body: body, needsTry: false, parent: addr(parent)) -proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode +proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode type MoveOrCopyFlag = enum - IsDecl, IsExplicitSink + IsDecl, IsExplicitSink, IsReturn proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; flags: set[MoveOrCopyFlag] = {}): PNode @@ -272,7 +272,7 @@ proc deepAliases(dest, ri: PNode): bool = proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode = if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or IsDecl in flags or (isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)))) or - isNoInit(dest): + isNoInit(dest) or IsReturn in flags: # optimize sink call into a bitwise memcopy result = newTree(nkFastAsgn, dest, ri) else: @@ -765,7 +765,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode = result.add copyNode(n[0]) s.needsTry = true -proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode = +proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode = if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt, nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}: template process(child, s): untyped = p(child, c, s, mode) @@ -949,7 +949,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}: cycleCheck(n, c) assert n[1].kind notin {nkAsgn, nkFastAsgn, nkSinkAsgn} - let flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {} + var flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {} + if inReturn: + flags.incl(IsReturn) result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s, flags) elif isDiscriminantField(n[0]): result = c.genDiscriminantAsgn(s, n) @@ -1033,7 +1035,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing of nkReturnStmt: result = shallowCopy(n) for i in 0..<n.len: - result[i] = p(n[i], c, s, mode) + result[i] = p(n[i], c, s, mode, inReturn=true) s.needsTry = true of nkCast: result = shallowCopy(n) From a4781dc4bcdf6e76076af80d0b21cb09865b3d44 Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Sun, 20 Aug 2023 07:30:36 +0300 Subject: [PATCH 462/489] use old typeinfo generation for hot code reloading (#22518) * use old typeinfo generation for hot code reloading * at least test hello world compilation on orc --- compiler/ccgtypes.nim | 2 +- testament/categories.nim | 7 +++++-- tests/dll/nimhcr_basic.nim | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index eb5e906e42..b7363f67fe 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1772,7 +1772,7 @@ proc genTypeInfoV2(m: BModule; t: PType; info: TLineInfo): Rope = return prefixTI.rope & result & ")".rope m.g.typeInfoMarkerV2[sig] = (str: result, owner: owner) - if m.compileToCpp: + if m.compileToCpp or m.hcrOn: genTypeInfoV2OldImpl(m, t, origType, result, info) else: genTypeInfoV2Impl(m, t, origType, result, info) diff --git a/testament/categories.nim b/testament/categories.nim index c449cf3e04..843bef3f9a 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -81,10 +81,13 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string, isOrc = testSpec r, makeTest("tests/dll/nimhcr_unit.nim", options & " --threads:off" & rpath, cat) testSpec r, makeTest("tests/dll/visibility.nim", options & " --threads:off" & rpath, cat) - if "boehm" notin options and not isOrc: + if "boehm" notin options: # hcr tests - testSpec r, makeTest("tests/dll/nimhcr_basic.nim", options & " --threads:off --forceBuild --hotCodeReloading:on " & rpath, cat) + var basicHcrTest = makeTest("tests/dll/nimhcr_basic.nim", options & " --threads:off --forceBuild --hotCodeReloading:on " & rpath, cat) + # test segfaults for now but compiles: + if isOrc: basicHcrTest.spec.action = actionCompile + testSpec r, basicHcrTest # force build required - see the comments in the .nim file for more details var hcri = makeTest("tests/dll/nimhcr_integration.nim", diff --git a/tests/dll/nimhcr_basic.nim b/tests/dll/nimhcr_basic.nim index 340c3fc4e9..2e1f39ae06 100644 --- a/tests/dll/nimhcr_basic.nim +++ b/tests/dll/nimhcr_basic.nim @@ -3,5 +3,6 @@ discard """ Hello world ''' """ +# for now orc only tests successful compilation echo "Hello world" From 942f846f04b4fa3c3154f7277ab1a8f6762d2714 Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Mon, 21 Aug 2023 21:08:00 +0300 Subject: [PATCH 463/489] fix getNullValue for cstring in VM, make other VM code aware of nil cstring (#22527) * fix getNullValue for cstring in VM fixes #22524 * very ugly fixes, but fix #15730 * nil cstring len works, more test lines * fix high --- compiler/vm.nim | 19 +++++++++++++++++-- compiler/vmdef.nim | 2 +- compiler/vmgen.nim | 7 ++++--- tests/vm/tvmmisc.nim | 31 +++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 1f4e4333d0..79832dbcb5 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1017,7 +1017,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcLenCstring: decodeBImm(rkInt) assert regs[rb].kind == rkNode - regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm + if regs[rb].node.kind == nkNilLit: + regs[ra].intVal = -imm + else: + regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm of opcIncl: decodeB(rkNode) let b = regs[rb].regToNode @@ -1215,6 +1218,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcEqStr: decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].node.strVal == regs[rc].node.strVal) + of opcEqCString: + decodeBC(rkInt) + let bNil = regs[rb].node.kind == nkNilLit + let cNil = regs[rc].node.kind == nkNilLit + regs[ra].intVal = ord((bNil and cNil) or + (not bNil and not cNil and regs[rb].node.strVal == regs[rc].node.strVal)) of opcLeStr: decodeBC(rkInt) regs[ra].intVal = ord(regs[rb].node.strVal <= regs[rc].node.strVal) @@ -1498,7 +1507,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = regs[ra].node c.currentExceptionA = raised # Set the `name` field of the exception - c.currentExceptionA[2].skipColon.strVal = c.currentExceptionA.typ.sym.name.s + var exceptionNameNode = newStrNode(nkStrLit, c.currentExceptionA.typ.sym.name.s) + if c.currentExceptionA[2].kind == nkExprColonExpr: + exceptionNameNode.typ = c.currentExceptionA[2][1].typ + c.currentExceptionA[2][1] = exceptionNameNode + else: + exceptionNameNode.typ = c.currentExceptionA[2].typ + c.currentExceptionA[2] = exceptionNameNode c.exceptionInstr = pc var frame = tos diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index f369908ba4..bdb0aeed15 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -99,7 +99,7 @@ type opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcEqNimNode, opcSameNodeType, opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt, - opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet, + opcEqStr, opcEqCString, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet, opcMulSet, opcPlusSet, opcMinusSet, opcConcatStr, opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq, opcIsNil, opcOf, opcIs, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 8aaac6272c..e58ddbeb91 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1159,7 +1159,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = c.gABC(n, opcNarrowU, dest, TRegister(size*8)) of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr: genConv(c, n, n[1], dest) - of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr) + of mEqStr: genBinaryABC(c, n, dest, opcEqStr) + of mEqCString: genBinaryABC(c, n, dest, opcEqCString) of mLeStr: genBinaryABC(c, n, dest, opcLeStr) of mLtStr: genBinaryABC(c, n, dest, opcLtStr) of mEqSet: genBinarySet(c, n, dest, opcEqSet) @@ -1877,10 +1878,10 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode = result = newNodeIT(nkUIntLit, info, t) of tyFloat..tyFloat128: result = newNodeIT(nkFloatLit, info, t) - of tyCstring, tyString: + of tyString: result = newNodeIT(nkStrLit, info, t) result.strVal = "" - of tyVar, tyLent, tyPointer, tyPtr, tyUntyped, + of tyCstring, tyVar, tyLent, tyPointer, tyPtr, tyUntyped, tyTyped, tyTypeDesc, tyRef, tyNil: result = newNodeIT(nkNilLit, info, t) of tyProc: diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index da8208f73e..5760422a1b 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -735,3 +735,34 @@ block: # bug #22190 tab = mkOpTable(Berlin) doAssert not tab + +block: # issue #22524 + const cnst = cstring(nil) + doAssert cnst.isNil + doAssert cnst == nil + let b = cnst + doAssert b.isNil + doAssert b == nil + + let a = static: cstring(nil) + doAssert a.isNil + + static: + var x: cstring + doAssert x.isNil + doAssert x == nil + doAssert x != "" + +block: # issue #15730 + const s: cstring = "" + doAssert s != nil + + static: + let s: cstring = "" + doAssert not s.isNil + doAssert s != nil + doAssert s == "" + +static: # more nil cstring issues + let x = cstring(nil) + doAssert x.len == 0 From 602f537eb2445b442b6cddecf9f55bf476068ea9 Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Mon, 21 Aug 2023 21:08:57 +0300 Subject: [PATCH 464/489] allow non-pragma special words as user pragmas (#22526) allow non-pragma special words as macro pragmas fixes #22525 --- compiler/trees.nim | 8 +++++--- compiler/wordrecg.nim | 27 +++++++++++++++++++-------- tests/pragmas/tpragmas_misc.nim | 5 +++++ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/compiler/trees.nim b/compiler/trees.nim index c4ddc8cf7c..cc2b0eafdd 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -144,10 +144,12 @@ proc whichPragma*(n: PNode): TSpecialWord = case key.kind of nkIdent: result = whichKeyword(key.ident) of nkSym: result = whichKeyword(key.sym.name) - of nkCast: result = wCast + of nkCast: return wCast of nkClosedSymChoice, nkOpenSymChoice: - result = whichPragma(key[0]) - else: result = wInvalid + return whichPragma(key[0]) + else: return wInvalid + if result in nonPragmaWordsLow..nonPragmaWordsHigh: + result = wInvalid proc isNoSideEffectPragma*(n: PNode): bool = var k = whichPragma(n) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index b2b0c8ae23..1724b18f6a 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -91,28 +91,36 @@ type wRedefine = "redefine", wCallsite = "callsite", wQuirky = "quirky", + # codegen keywords, but first the ones that are also pragmas: + wExtern = "extern", wGoto = "goto", wRegister = "register", + wUnion = "union", wPacked = "packed", wVirtual = "virtual", + wVolatile = "volatile", wMember = "member", + wByCopy = "bycopy", wByRef = "byref", + + # codegen keywords but not pragmas: wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char", wClass = "class", wCompl = "compl", wConstCast = "const_cast", wDefault = "default", wDelete = "delete", wDouble = "double", wDynamicCast = "dynamic_cast", - wExplicit = "explicit", wExtern = "extern", wFalse = "false", wFloat = "float", - wFriend = "friend", wGoto = "goto", wInt = "int", wLong = "long", wMutable = "mutable", + wExplicit = "explicit", wFalse = "false", wFloat = "float", + wFriend = "friend", wInt = "int", wLong = "long", wMutable = "mutable", wNamespace = "namespace", wNew = "new", wOperator = "operator", wPrivate = "private", - wProtected = "protected", wPublic = "public", wRegister = "register", + wProtected = "protected", wPublic = "public", wReinterpretCast = "reinterpret_cast", wRestrict = "restrict", wShort = "short", wSigned = "signed", wSizeof = "sizeof", wStaticCast = "static_cast", wStruct = "struct", wSwitch = "switch", wThis = "this", wThrow = "throw", wTrue = "true", wTypedef = "typedef", wTypeid = "typeid", wTypeof = "typeof", wTypename = "typename", - wUnion = "union", wPacked = "packed", wUnsigned = "unsigned", wVirtual = "virtual", - wVoid = "void", wVolatile = "volatile", wWchar = "wchar_t", wMember = "member", + wUnsigned = "unsigned", wVoid = "void", wAlignas = "alignas", wAlignof = "alignof", wConstexpr = "constexpr", wDecltype = "decltype", wNullptr = "nullptr", wNoexcept = "noexcept", wThreadLocal = "thread_local", wStaticAssert = "static_assert", - wChar16 = "char16_t", wChar32 = "char32_t", + wChar16 = "char16_t", wChar32 = "char32_t", wWchar = "wchar_t", wStdIn = "stdin", wStdOut = "stdout", wStdErr = "stderr", - wInOut = "inout", wByCopy = "bycopy", wByRef = "byref", wOneWay = "oneway", + wInOut = "inout", wOneWay = "oneway", + # end of codegen keywords + wBitsize = "bitsize", wImportHidden = "all", wSendable = "sendable" @@ -125,12 +133,15 @@ const nimKeywordsLow* = ord(wAsm) nimKeywordsHigh* = ord(wYield) - ccgKeywordsLow* = ord(wAuto) + ccgKeywordsLow* = ord(wExtern) ccgKeywordsHigh* = ord(wOneWay) cppNimSharedKeywords* = { wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport, wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing} + + nonPragmaWordsLow* = wAuto + nonPragmaWordsHigh* = wOneWay from std/enumutils import genEnumCaseStmt diff --git a/tests/pragmas/tpragmas_misc.nim b/tests/pragmas/tpragmas_misc.nim index 6dc2e6b802..adb7e73c34 100644 --- a/tests/pragmas/tpragmas_misc.nim +++ b/tests/pragmas/tpragmas_misc.nim @@ -68,3 +68,8 @@ block: # issue #10994 proc a {.bar.} = discard # works proc b {.bar, foo.} = discard # doesn't + +block: # issue #22525 + macro catch(x: typed) = x + proc thing {.catch.} = discard + thing() From a26ccb34768fdaceff2cf4d27aee4c830fd47303 Mon Sep 17 00:00:00 2001 From: Hamid Bluri <hr.bolouri@gmail.com> Date: Tue, 22 Aug 2023 20:01:21 +0330 Subject: [PATCH 465/489] fix #22492 (#22511) * fix #22492 * Update nimdoc.css remove scroll-y * Update nimdoc.out.css * Update nimdoc.css * make it sticky again * Update nimdoc.out.css * danm sticky, use fixed * Update nimdoc.out.css * fix margin * Update nimdoc.out.css * make search input react to any change (not just keyboard events) according to https://github.com/nim-lang/Nim/pull/22511#issuecomment-1685218787 --- config/nimdoc.cfg | 4 ++-- doc/nimdoc.css | 11 ++++++----- nimdoc/extlinks/project/expected/_._/util.html | 2 +- nimdoc/extlinks/project/expected/main.html | 2 +- nimdoc/extlinks/project/expected/sub/submodule.html | 2 +- nimdoc/rst2html/expected/rst_examples.html | 2 +- nimdoc/test_doctype/expected/test_doctype.html | 2 +- nimdoc/test_out_index_dot_html/expected/index.html | 2 +- nimdoc/testproject/expected/nimdoc.out.css | 11 ++++++----- .../testproject/expected/subdir/subdir_b/utils.html | 2 +- nimdoc/testproject/expected/testproject.html | 2 +- 11 files changed, 22 insertions(+), 20 deletions(-) diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 9f36e7d1c2..9535aa384f 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -155,7 +155,7 @@ doc.body_toc_group = """ </div> <div id="searchInputDiv"> Search: <input type="search" id="searchInput" - onkeyup="search()" /> + oninput="search()" /> </div> $body_toc_groupsection $tableofcontents @@ -189,7 +189,7 @@ doc.body_toc_group = """ </ul> </div> <div id="searchInputDiv"> - Search: <input type="search" id="searchInput" onkeyup="search()"/> + Search: <input type="search" id="searchInput" oninput="search()"/> </div> <div> Group by: diff --git a/doc/nimdoc.css b/doc/nimdoc.css index 3fb5497ff6..a9e4ac9c6a 100644 --- a/doc/nimdoc.css +++ b/doc/nimdoc.css @@ -767,15 +767,16 @@ div.topic { div.search_results { background-color: var(--third-background); - margin: 3em; + margin: 3vh 5vw; padding: 1em; border: 1px solid #4d4d4d; - position: sticky; - top: 0; + position: fixed; + top: 10px; isolation: isolate; + max-width: calc(100vw - 6em); z-index: 1; - max-height: 100vh; - overflow-y: scroll; } + max-height: calc(100vh - 6em); + overflow-y: scroll;} div#global-links ul { margin-left: 0; diff --git a/nimdoc/extlinks/project/expected/_._/util.html b/nimdoc/extlinks/project/expected/_._/util.html index 9b9b29a4f9..35f3332112 100644 --- a/nimdoc/extlinks/project/expected/_._/util.html +++ b/nimdoc/extlinks/project/expected/_._/util.html @@ -37,7 +37,7 @@ </ul> </div> <div id="searchInputDiv"> - Search: <input type="search" id="searchInput" onkeyup="search()"/> + Search: <input type="search" id="searchInput" oninput="search()"/> </div> <div> Group by: diff --git a/nimdoc/extlinks/project/expected/main.html b/nimdoc/extlinks/project/expected/main.html index cf7982fde1..1a58ea2ac7 100644 --- a/nimdoc/extlinks/project/expected/main.html +++ b/nimdoc/extlinks/project/expected/main.html @@ -37,7 +37,7 @@ </ul> </div> <div id="searchInputDiv"> - Search: <input type="search" id="searchInput" onkeyup="search()"/> + Search: <input type="search" id="searchInput" oninput="search()"/> </div> <div> Group by: diff --git a/nimdoc/extlinks/project/expected/sub/submodule.html b/nimdoc/extlinks/project/expected/sub/submodule.html index 913138d6ec..60887ae37a 100644 --- a/nimdoc/extlinks/project/expected/sub/submodule.html +++ b/nimdoc/extlinks/project/expected/sub/submodule.html @@ -37,7 +37,7 @@ </ul> </div> <div id="searchInputDiv"> - Search: <input type="search" id="searchInput" onkeyup="search()"/> + Search: <input type="search" id="searchInput" oninput="search()"/> </div> <div> Group by: diff --git a/nimdoc/rst2html/expected/rst_examples.html b/nimdoc/rst2html/expected/rst_examples.html index 72f6453f25..af46771f37 100644 --- a/nimdoc/rst2html/expected/rst_examples.html +++ b/nimdoc/rst2html/expected/rst_examples.html @@ -37,7 +37,7 @@ </ul> </div> <div id="searchInputDiv"> - Search: <input type="search" id="searchInput" onkeyup="search()"/> + Search: <input type="search" id="searchInput" oninput="search()"/> </div> <div> Group by: diff --git a/nimdoc/test_doctype/expected/test_doctype.html b/nimdoc/test_doctype/expected/test_doctype.html index 01ad6e5a09..694ed9b00e 100644 --- a/nimdoc/test_doctype/expected/test_doctype.html +++ b/nimdoc/test_doctype/expected/test_doctype.html @@ -37,7 +37,7 @@ </ul> </div> <div id="searchInputDiv"> - Search: <input type="search" id="searchInput" onkeyup="search()"/> + Search: <input type="search" id="searchInput" oninput="search()"/> </div> <div> Group by: diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html index 22d5daa358..40df1943a8 100644 --- a/nimdoc/test_out_index_dot_html/expected/index.html +++ b/nimdoc/test_out_index_dot_html/expected/index.html @@ -37,7 +37,7 @@ </ul> </div> <div id="searchInputDiv"> - Search: <input type="search" id="searchInput" onkeyup="search()"/> + Search: <input type="search" id="searchInput" oninput="search()"/> </div> <div> Group by: diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css index 3fb5497ff6..a9e4ac9c6a 100644 --- a/nimdoc/testproject/expected/nimdoc.out.css +++ b/nimdoc/testproject/expected/nimdoc.out.css @@ -767,15 +767,16 @@ div.topic { div.search_results { background-color: var(--third-background); - margin: 3em; + margin: 3vh 5vw; padding: 1em; border: 1px solid #4d4d4d; - position: sticky; - top: 0; + position: fixed; + top: 10px; isolation: isolate; + max-width: calc(100vw - 6em); z-index: 1; - max-height: 100vh; - overflow-y: scroll; } + max-height: calc(100vh - 6em); + overflow-y: scroll;} div#global-links ul { margin-left: 0; diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index cfdac53107..ba9512d5a9 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -37,7 +37,7 @@ </ul> </div> <div id="searchInputDiv"> - Search: <input type="search" id="searchInput" onkeyup="search()"/> + Search: <input type="search" id="searchInput" oninput="search()"/> </div> <div> Group by: diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 78a730e598..db49102f85 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -37,7 +37,7 @@ </ul> </div> <div id="searchInputDiv"> - Search: <input type="search" id="searchInput" onkeyup="search()"/> + Search: <input type="search" id="searchInput" oninput="search()"/> </div> <div> Group by: From 6b04d0395ab1d6d8efa7d287c73da2c7230800c9 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf <rumpf_a@web.de> Date: Tue, 22 Aug 2023 21:01:08 +0200 Subject: [PATCH 466/489] allow tuples and procs in 'toTask' + minor things (#22530) --- lib/pure/strscans.nim | 4 ++-- lib/std/tasks.nim | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 775c4244ac..0b23abc28b 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -172,7 +172,7 @@ The parsing is performed with the help of 3 helper templates that that can be implemented for a custom type. These templates need to be named ``atom`` and ``nxt``. ``atom`` should be -overloaded to handle both single characters and sets of character. +overloaded to handle both `char` and `set[char]`. ```nim import std/streams @@ -472,7 +472,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b macro scanTuple*(input: untyped; pattern: static[string]; matcherTypes: varargs[untyped]): untyped {.since: (1, 5).}= ## Works identically as scanf, but instead of predeclaring variables it returns a tuple. - ## Tuple is started with a bool which indicates if the scan was successful + ## Tuple is started with a bool which indicates if the scan was successful ## followed by the requested data. ## If using a user defined matcher, provide the types in order they appear after pattern: ## `line.scanTuple("${yourMatcher()}", int)` diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim index 6a4b2bb6d8..9eb7c97c4e 100644 --- a/lib/std/tasks.nim +++ b/lib/std/tasks.nim @@ -173,7 +173,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC # passing by static parameters # so we pass them directly instead of passing by scratchObj callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i]) - of nnkSym, nnkPtrTy: + of nnkSym, nnkPtrTy, nnkProcTy, nnkTupleConstr: addAllNode(param, e[i]) of nnkCharLit..nnkNilLit: callNode.add nnkExprEqExpr.newTree(formalParams[i][0], e[i]) From 3de75ffc02ea85b95702ec0dc0976748954d3e2c Mon Sep 17 00:00:00 2001 From: SirOlaf <34164198+SirOlaf@users.noreply.github.com> Date: Wed, 23 Aug 2023 06:18:35 +0200 Subject: [PATCH 467/489] Fix #21532: Check if template return is untyped (#22517) * Don't ignore return in semTemplateDef * Add test --------- Co-authored-by: SirOlaf <> --- compiler/semtempl.nim | 3 +++ tests/template/t21532.nim | 8 ++++++++ 2 files changed, 11 insertions(+) create mode 100644 tests/template/t21532.nim diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index a72143bdd7..85411f7c46 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -674,6 +674,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = # a template's parameters are not gensym'ed even if that was originally the # case as we determine whether it's a template parameter in the template # body by the absence of the sfGenSym flag: + let retType = s.typ[0] + if retType != nil and retType.kind != tyUntyped: + allUntyped = false for i in 1..<s.typ.n.len: let param = s.typ.n[i].sym if param.name.id != ord(wUnderscore): diff --git a/tests/template/t21532.nim b/tests/template/t21532.nim new file mode 100644 index 0000000000..3193b0dc35 --- /dev/null +++ b/tests/template/t21532.nim @@ -0,0 +1,8 @@ + +template elementType(a: untyped): typedesc = + typeof(block: (for ai in a: ai)) + +func fn[T](a: T) = + doAssert elementType(a) is int + +@[1,2,3].fn \ No newline at end of file From 4f891aa50c298bcb81fc8859e2118b3118188720 Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Wed, 23 Aug 2023 14:43:02 +0300 Subject: [PATCH 468/489] don't render underscore identifiers with id (#22538) --- compiler/renderer.nim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index e39be78fe9..c73fa99451 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -14,7 +14,7 @@ {.used.} import - lexer, options, idents, strutils, ast, msgs, lineinfos + lexer, options, idents, strutils, ast, msgs, lineinfos, wordrecg when defined(nimPreviewSlimSystem): import std/[syncio, assertions, formatfloat] @@ -838,7 +838,7 @@ proc gcase(g: var TSrcGen, n: PNode) = gsub(g, n[^1], c) proc genSymSuffix(result: var string, s: PSym) {.inline.} = - if sfGenSym in s.flags: + if sfGenSym in s.flags and s.name.id != ord(wUnderscore): result.add '_' result.addInt s.id @@ -958,7 +958,9 @@ proc gident(g: var TSrcGen, n: PNode) = s.addInt localId if sfCursor in n.sym.flags: s.add "_cursor" - elif n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp): + elif n.kind == nkSym and (renderIds in g.flags or + (sfGenSym in n.sym.flags and n.sym.name.id != ord(wUnderscore)) or + n.sym.kind == skTemp): s.add '_' s.addInt n.sym.id when defined(debugMagics): From 03f267c8013eca2830eb3deadda73ed08096ec12 Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Wed, 23 Aug 2023 20:25:26 +0300 Subject: [PATCH 469/489] make jsffi properly gensym (#22539) fixes #21208 --- lib/js/jsffi.nim | 51 ++++++++++++++++++++++++++------------------- tests/js/tjsffi.nim | 6 ++++++ 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim index db40e75150..08b1c6db9e 100644 --- a/lib/js/jsffi.nim +++ b/lib/js/jsffi.nim @@ -227,36 +227,40 @@ macro `.`*(obj: JsObject, field: untyped): JsObject = assert obj.a.to(int) == 20 if validJsName($field): let importString = "#." & $field + let helperName = genSym(nskProc, "helper") result = quote do: - proc helper(o: JsObject): JsObject - {.importjs: `importString`, gensym.} - helper(`obj`) + proc `helperName`(o: JsObject): JsObject + {.importjs: `importString`.} + `helperName`(`obj`) else: if not mangledNames.hasKey($field): mangledNames[$field] = mangleJsName($field) let importString = "#." & mangledNames[$field] + let helperName = genSym(nskProc, "helper") result = quote do: - proc helper(o: JsObject): JsObject - {.importjs: `importString`, gensym.} - helper(`obj`) + proc `helperName`(o: JsObject): JsObject + {.importjs: `importString`.} + `helperName`(`obj`) macro `.=`*(obj: JsObject, field, value: untyped): untyped = ## Experimental dot accessor (set) for type JsObject. ## Sets the value of a property of name `field` in a JsObject `x` to `value`. if validJsName($field): let importString = "#." & $field & " = #" + let helperName = genSym(nskProc, "helper") result = quote do: - proc helper(o: JsObject, v: auto) - {.importjs: `importString`, gensym.} - helper(`obj`, `value`) + proc `helperName`(o: JsObject, v: auto) + {.importjs: `importString`.} + `helperName`(`obj`, `value`) else: if not mangledNames.hasKey($field): mangledNames[$field] = mangleJsName($field) let importString = "#." & mangledNames[$field] & " = #" + let helperName = genSym(nskProc, "helper") result = quote do: - proc helper(o: JsObject, v: auto) - {.importjs: `importString`, gensym.} - helper(`obj`, `value`) + proc `helperName`(o: JsObject, v: auto) + {.importjs: `importString`.} + `helperName`(`obj`, `value`) macro `.()`*(obj: JsObject, field: untyped, @@ -283,10 +287,11 @@ macro `.()`*(obj: JsObject, if not mangledNames.hasKey($field): mangledNames[$field] = mangleJsName($field) importString = "#." & mangledNames[$field] & "(@)" - result = quote: - proc helper(o: JsObject): JsObject - {.importjs: `importString`, gensym, discardable.} - helper(`obj`) + let helperName = genSym(nskProc, "helper") + result = quote do: + proc `helperName`(o: JsObject): JsObject + {.importjs: `importString`, discardable.} + `helperName`(`obj`) for idx in 0 ..< args.len: let paramName = newIdentNode("param" & $idx) result[0][3].add newIdentDefs(paramName, newIdentNode("JsObject")) @@ -303,10 +308,11 @@ macro `.`*[K: cstring, V](obj: JsAssoc[K, V], if not mangledNames.hasKey($field): mangledNames[$field] = mangleJsName($field) importString = "#." & mangledNames[$field] + let helperName = genSym(nskProc, "helper") result = quote do: - proc helper(o: type(`obj`)): `obj`.V - {.importjs: `importString`, gensym.} - helper(`obj`) + proc `helperName`(o: type(`obj`)): `obj`.V + {.importjs: `importString`.} + `helperName`(`obj`) macro `.=`*[K: cstring, V](obj: JsAssoc[K, V], field: untyped, @@ -320,10 +326,11 @@ macro `.=`*[K: cstring, V](obj: JsAssoc[K, V], if not mangledNames.hasKey($field): mangledNames[$field] = mangleJsName($field) importString = "#." & mangledNames[$field] & " = #" + let helperName = genSym(nskProc, "helper") result = quote do: - proc helper(o: type(`obj`), v: `obj`.V) - {.importjs: `importString`, gensym.} - helper(`obj`, `value`) + proc `helperName`(o: type(`obj`), v: `obj`.V) + {.importjs: `importString`.} + `helperName`(`obj`, `value`) macro `.()`*[K: cstring, V: proc](obj: JsAssoc[K, V], field: untyped, diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim index 2e57f70c1e..b54d13e43e 100644 --- a/tests/js/tjsffi.nim +++ b/tests/js/tjsffi.nim @@ -265,3 +265,9 @@ block: # test ** doAssert to(`**`(a + a, b), int) == 2 doAssert to(`**`(toJs(1) + toJs(1), toJs(2)), int) == 4 + +block: # issue #21208 + type MyEnum = enum baz + var obj: JsObject + {.emit: "`obj` = {bar: {baz: 123}}".} + discard obj.bar.baz From 53d43e96716539d96e6a1e5f3926a3fe3a11e2dd Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Thu, 24 Aug 2023 07:11:48 +0300 Subject: [PATCH 470/489] round out tuple unpacking assignment, support underscores (#22537) * round out tuple unpacking assignment, support underscores fixes #18710 * fix test messages * use discard instead of continue Co-authored-by: Andreas Rumpf <rumpf_a@web.de> --------- Co-authored-by: Andreas Rumpf <rumpf_a@web.de> --- compiler/lowerings.nim | 19 ------------------ compiler/semexprs.nim | 33 ++++++++++++++++++++++++++++++- compiler/semstmts.nim | 17 +++++++++------- tests/arc/topt_no_cursor.nim | 8 ++++---- tests/errmsgs/tassignunpack.nim | 2 +- tests/tuples/ttuples_various.nim | 12 +++++++++++ tests/types/tassignemptytuple.nim | 2 +- 7 files changed, 60 insertions(+), 33 deletions(-) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index a083b91953..42d0f1790c 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -122,25 +122,6 @@ proc newTupleAccessRaw*(tup: PNode, i: int): PNode = proc newTryFinally*(body, final: PNode): PNode = result = newTree(nkHiddenTryStmt, body, newTree(nkFinally, final)) -proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode = - let value = n.lastSon - result = newNodeI(nkStmtList, n.info) - - var temp = newSym(skTemp, getIdent(g.cache, "_"), idgen, owner, value.info, owner.options) - var v = newNodeI(nkLetSection, value.info) - let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info) - - var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3) - vpart[0] = tempAsNode - vpart[1] = newNodeI(nkTupleClassTy, value.info) - vpart[2] = value - v.add vpart - result.add(v) - - let lhs = n[0] - for i in 0..<lhs.len: - result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempAsNode, i)) - proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode = result = newNodeI(nkStmtList, n.info) # note: cannot use 'skTemp' here cause we really need the copy for the VM :-( diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 52d1f0628e..cb27ca0ff4 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1828,6 +1828,37 @@ proc goodLineInfo(arg: PNode): TLineInfo = else: arg.info +proc makeTupleAssignments(c: PContext; n: PNode): PNode = + ## expand tuple unpacking assignment into series of assignments + ## + ## mirrored with semstmts.makeVarTupleSection + let lhs = n[0] + let value = semExprWithType(c, n[1], {efTypeAllowed}) + if value.typ.kind != tyTuple: + localError(c.config, n[1].info, errXExpected, "tuple") + elif lhs.len != value.typ.len: + localError(c.config, n.info, errWrongNumberOfVariables) + result = newNodeI(nkStmtList, n.info) + + let temp = newSym(skTemp, getIdent(c.cache, "tmpTupleAsgn"), c.idgen, getCurrOwner(c), n.info) + temp.typ = value.typ + temp.flags.incl(sfGenSym) + var v = newNodeI(nkLetSection, value.info) + let tempNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info) + var vpart = newNodeI(nkIdentDefs, v.info, 3) + vpart[0] = tempNode + vpart[1] = c.graph.emptyNode + vpart[2] = value + v.add vpart + result.add(v) + + for i in 0..<lhs.len: + if lhs[i].kind == nkIdent and lhs[i].ident.id == ord(wUnderscore): + # skip _ assignments if we are using a temp as they are already evaluated + discard + else: + result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempNode, i)) + proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = checkSonsLen(n, 2, c.config) var a = n[0] @@ -1870,7 +1901,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = # unfortunately we need to rewrite ``(x, y) = foo()`` already here so # that overloading of the assignment operator still works. Usually we # prefer to do these rewritings in transf.nim: - return semStmt(c, lowerTupleUnpackingForAsgn(c.graph, n, c.idgen, c.p.owner), {}) + return semStmt(c, makeTupleAssignments(c, n), {}) else: a = semExprWithType(c, a, {efLValue}) else: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 39c37f4fb2..bb9c474a8f 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -599,12 +599,14 @@ proc globalVarInitCheck(c: PContext, n: PNode) = proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSymKind, origResult: var PNode): PNode = ## expand tuple unpacking assignments into new var/let/const section + ## + ## mirrored with semexprs.makeTupleAssignments if typ.kind != tyTuple: localError(c.config, a.info, errXExpected, "tuple") elif a.len-2 != typ.len: localError(c.config, a.info, errWrongNumberOfVariables) var - tmpTuple: PSym = nil + tempNode: PNode = nil lastDef: PNode let defkind = if symkind == skConst: nkConstDef else: nkIdentDefs # temporary not needed if not const and RHS is tuple literal @@ -612,17 +614,18 @@ proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSy let useTemp = def.kind notin {nkPar, nkTupleConstr} or symkind == skConst if useTemp: # use same symkind for compatibility with original section - tmpTuple = newSym(symkind, getIdent(c.cache, "tmpTuple"), c.idgen, getCurrOwner(c), n.info) - tmpTuple.typ = typ - tmpTuple.flags.incl(sfGenSym) + let temp = newSym(symkind, getIdent(c.cache, "tmpTuple"), c.idgen, getCurrOwner(c), n.info) + temp.typ = typ + temp.flags.incl(sfGenSym) lastDef = newNodeI(defkind, a.info) newSons(lastDef, 3) - lastDef[0] = newSymNode(tmpTuple) + lastDef[0] = newSymNode(temp) # NOTE: at the moment this is always ast.emptyNode, see parser.nim lastDef[1] = a[^2] lastDef[2] = def - tmpTuple.ast = lastDef + temp.ast = lastDef addToVarSection(c, origResult, n, lastDef) + tempNode = newSymNode(temp) result = newNodeI(n.kind, a.info) for j in 0..<a.len-2: let name = a[j] @@ -641,7 +644,7 @@ proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSy lastDef[0] = name lastDef[^2] = c.graph.emptyNode if useTemp: - lastDef[^1] = newTreeIT(nkBracketExpr, name.info, typ[j], newSymNode(tmpTuple), newIntNode(nkIntLit, j)) + lastDef[^1] = newTupleAccessRaw(tempNode, j) else: var val = def[j] if val.kind == nkExprColonExpr: val = val[1] diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim index 7cfb0a0d50..dfb0f0a386 100644 --- a/tests/arc/topt_no_cursor.nim +++ b/tests/arc/topt_no_cursor.nim @@ -39,13 +39,13 @@ var lresult lvalue lnext - _ + tmpTupleAsgn lresult = @[123] -_ = ( +tmpTupleAsgn = ( let blitTmp = lresult blitTmp, ";") -lvalue = _[0] -lnext = _[1] +lvalue = tmpTupleAsgn[0] +lnext = tmpTupleAsgn[1] `=sink`(result.value, move lvalue) `=destroy`(lnext) `=destroy_1`(lvalue) diff --git a/tests/errmsgs/tassignunpack.nim b/tests/errmsgs/tassignunpack.nim index 27413a42b6..d74e16dd5e 100644 --- a/tests/errmsgs/tassignunpack.nim +++ b/tests/errmsgs/tassignunpack.nim @@ -1,3 +1,3 @@ var a, b = 0 (a, b) = 1 #[tt.Error - ^ type mismatch: got <int literal(1)> but expected 'tuple']# + ^ 'tuple' expected]# diff --git a/tests/tuples/ttuples_various.nim b/tests/tuples/ttuples_various.nim index 97bc70bd28..e392731d2f 100644 --- a/tests/tuples/ttuples_various.nim +++ b/tests/tuples/ttuples_various.nim @@ -197,3 +197,15 @@ block: # bug #22054 var v = A(field: (a: 1314)) doAssert get(v)[0] == 1314 + +block: # tuple unpacking assignment with underscore + var + a = 1 + b = 2 + doAssert (a, b) == (1, 2) + (a, _) = (3, 4) + doAssert (a, b) == (3, 2) + (_, a) = (5, 6) + doAssert (a, b) == (6, 2) + (b, _) = (7, 8) + doAssert (a, b) == (6, 7) diff --git a/tests/types/tassignemptytuple.nim b/tests/types/tassignemptytuple.nim index f3320dec7a..9d5a311baa 100644 --- a/tests/types/tassignemptytuple.nim +++ b/tests/types/tassignemptytuple.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "invalid type: 'empty' in this context: '(seq[empty], (seq[empty], set[empty]))' for let" + errormsg: "cannot infer the type of the tuple" file: "tassignemptytuple.nim" line: 11 """ From c56a712e7d54485b97df3b110ef148f5c12f2ab3 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 24 Aug 2023 18:59:45 +0800 Subject: [PATCH 471/489] fixes #22541; peg matchLen can raise an unlisted exception: Exception (#22545) The `mopProc` is a recursive function. --- lib/pure/pegs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index 7f0f532fe5..18e26027f5 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -562,7 +562,7 @@ template matchOrParse(mopProc: untyped) = # procs. For the former, *enter* and *leave* event handler code generators # are provided which just return *discard*. - proc mopProc(s: string, p: Peg, start: int, c: var Captures): int {.gcsafe.} = + proc mopProc(s: string, p: Peg, start: int, c: var Captures): int {.gcsafe, raises: [].} = proc matchBackRef(s: string, p: Peg, start: int, c: var Captures): int = # Parse handler code must run in an *of* clause of its own for each # *PegKind*, so we encapsulate the identical clause body for From bc9785c08d53c2f94f62738e541508592c9b3b24 Mon Sep 17 00:00:00 2001 From: Jacek Sieka <arnetheduck@gmail.com> Date: Thu, 24 Aug 2023 15:41:29 +0200 Subject: [PATCH 472/489] Fix `getAppFilename` exception handling (#22544) * Fix `getAppFilename` exception handling avoid platform-dependendent error handling strategies * more fixes * space --- lib/pure/os.nim | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 77dc3ca8f8..13b103b925 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -8,7 +8,7 @@ # ## This module contains basic operating system facilities like -## retrieving environment variables, working with directories, +## retrieving environment variables, working with directories, ## running shell commands, etc. ## .. importdoc:: symlinks.nim, appdirs.nim, dirs.nim, ospaths2.nim @@ -624,10 +624,12 @@ when defined(haiku): else: result = "" -proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noWeirdTarget.} = +proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noWeirdTarget, raises: [].} = ## Returns the filename of the application's executable. ## This proc will resolve symlinks. ## + ## Returns empty string when name is unavailable + ## ## See also: ## * `getAppDir proc`_ ## * `getCurrentCompilerExe proc`_ @@ -657,14 +659,17 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW if getExecPath2(result.cstring, size): result = "" # error! if result.len > 0: - result = result.expandFilename + try: + result = result.expandFilename + except OSError: + result = "" else: when defined(linux) or defined(aix): result = getApplAux("/proc/self/exe") elif defined(solaris): result = getApplAux("/proc/" & $getpid() & "/path/a.out") elif defined(genode): - raiseOSError(OSErrorCode(-1), "POSIX command line not supported") + result = "" # Not supported elif defined(freebsd) or defined(dragonfly) or defined(netbsd): result = getApplFreebsd() elif defined(haiku): @@ -676,7 +681,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW # little heuristic that may work on other POSIX-like systems: if result.len == 0: - result = getApplHeuristic() + result = try: getApplHeuristic() except OSError: "" proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noWeirdTarget.} = ## Returns the directory of the application's executable. From 101337885459decedc9dc3301b1ff04cf8c54c32 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 25 Aug 2023 02:56:58 +0800 Subject: [PATCH 473/489] fixes a strictdef ten years long vintage bug, which counts the same thing twice (#22549) fixes a strictdef ten years long vintage bug --- compiler/ccgcalls.nim | 1 + compiler/semexprs.nim | 1 + compiler/sempass2.nim | 31 +++++++++++++++++++++---------- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 80b534cee6..494f3c8c69 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -24,6 +24,7 @@ proc canRaiseDisp(p: BProc; n: PNode): bool = proc preventNrvo(p: BProc; dest, le, ri: PNode): bool = proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool = + result = false var n = le while true: # do NOT follow nkHiddenDeref here! diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index cb27ca0ff4..cb4bddb5d1 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2150,6 +2150,7 @@ proc expectString(c: PContext, n: PNode): string = if n.kind in nkStrKinds: return n.strVal else: + result = "" localError(c.config, n.info, errStringLiteralExpected) proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym = diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 854247095e..30050f25d2 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -356,12 +356,15 @@ proc useVar(a: PEffects, n: PNode) = type TIntersection = seq[tuple[id, count: int]] # a simple count table -proc addToIntersection(inter: var TIntersection, s: int) = +proc addToIntersection(inter: var TIntersection, s: int, zeroInit: bool) = for j in 0..<inter.len: if s == inter[j].id: inc inter[j].count return - inter.add((id: s, count: 1)) + if zeroInit: + inter.add((id: s, count: 0)) + else: + inter.add((id: s, count: 1)) proc throws(tracked, n, orig: PNode) = if n.typ == nil or n.typ.kind != tyError: @@ -465,7 +468,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) = track(tracked, n[0]) dec tracked.inTryStmt for i in oldState..<tracked.init.len: - addToIntersection(inter, tracked.init[i]) + addToIntersection(inter, tracked.init[i], false) var branches = 1 var hasFinally = false @@ -500,7 +503,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) = tracked.init.add b[j][2].sym.id track(tracked, b[^1]) for i in oldState..<tracked.init.len: - addToIntersection(inter, tracked.init[i]) + addToIntersection(inter, tracked.init[i], false) else: setLen(tracked.init, oldState) track(tracked, b[^1]) @@ -698,9 +701,11 @@ proc trackCase(tracked: PEffects, n: PNode) = addCaseBranchFacts(tracked.guards, n, i) for i in 0..<branch.len: track(tracked, branch[i]) - if not breaksBlock(branch.lastSon): inc toCover + let hasBreaksBlock = breaksBlock(branch.lastSon) + if not hasBreaksBlock: + inc toCover for i in oldState..<tracked.init.len: - addToIntersection(inter, tracked.init[i]) + addToIntersection(inter, tracked.init[i], hasBreaksBlock) setLen(tracked.init, oldState) if not stringCase or lastSon(n).kind == nkElse: @@ -720,9 +725,11 @@ proc trackIf(tracked: PEffects, n: PNode) = var inter: TIntersection = @[] var toCover = 0 track(tracked, n[0][1]) - if not breaksBlock(n[0][1]): inc toCover + let hasBreaksBlock = breaksBlock(n[0][1]) + if not hasBreaksBlock: + inc toCover for i in oldState..<tracked.init.len: - addToIntersection(inter, tracked.init[i]) + addToIntersection(inter, tracked.init[i], hasBreaksBlock) for i in 1..<n.len: let branch = n[i] @@ -734,9 +741,12 @@ proc trackIf(tracked: PEffects, n: PNode) = setLen(tracked.init, oldState) for i in 0..<branch.len: track(tracked, branch[i]) - if not breaksBlock(branch.lastSon): inc toCover + let hasBreaksBlock = breaksBlock(branch.lastSon) + if not hasBreaksBlock: + inc toCover for i in oldState..<tracked.init.len: - addToIntersection(inter, tracked.init[i]) + addToIntersection(inter, tracked.init[i], hasBreaksBlock) + setLen(tracked.init, oldState) if lastSon(n).len == 1: for id, count in items(inter): @@ -1327,6 +1337,7 @@ proc track(tracked: PEffects, n: PNode) = proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool = if spec.typ.kind == tyOr: + result = false for t in spec.typ: if safeInheritanceDiff(g.excType(real), t) <= 0: return true From fc6a388780c9a0e2eb6c5eff4e291e7bcfcd5f7a Mon Sep 17 00:00:00 2001 From: Amjad Ben Hedhili <amjadhedhili@outlook.com> Date: Thu, 24 Aug 2023 19:57:49 +0100 Subject: [PATCH 474/489] Add `cursor` to lists iterator variables (#22531) * followup #21507 --- lib/pure/collections/lists.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index 6e3ddf3975..e1d32e7372 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -286,7 +286,7 @@ iterator nodes*[T](L: SomeLinkedList[T]): SomeLinkedNode[T] = x.value = 5 * x.value - 1 assert $a == "[49, 99, 199, 249]" - var it = L.head + var it {.cursor.} = L.head while it != nil: let nxt = it.next yield it @@ -311,7 +311,7 @@ iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] = x.value = 5 * x.value - 1 assert $a == "[49, 99, 199, 249]" - var it = L.head + var it {.cursor.} = L.head if it != nil: while true: let nxt = it.next @@ -733,7 +733,7 @@ proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.disc if L.tail.next == n: L.tail.next = L.head # restore cycle else: - var prev = L.head + var prev {.cursor.} = L.head while prev.next != n and prev.next != nil: prev = prev.next if prev.next == nil: From d677ed31e50a322851b476f20fd1719eb17cd426 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 25 Aug 2023 12:48:08 +0800 Subject: [PATCH 475/489] follow up #22549 (#22551) --- compiler/int128.nim | 2 +- compiler/reorder.nim | 1 + compiler/sempass2.nim | 7 ++++--- compiler/types.nim | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/int128.nim b/compiler/int128.nim index 6968b1f892..18e751f989 100644 --- a/compiler/int128.nim +++ b/compiler/int128.nim @@ -573,4 +573,4 @@ proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} = of 8: return maskUInt64(arg) else: - assert(false, "masking only implemented for 1, 2, 4 and 8 bytes") + raiseAssert "masking only implemented for 1, 2, 4 and 8 bytes" diff --git a/compiler/reorder.nim b/compiler/reorder.nim index a96841bcad..aedebc7d42 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -252,6 +252,7 @@ proc hasCommand(n: PNode): bool = of nkStmtList, nkStmtListExpr, nkWhenStmt, nkElifBranch, nkElse, nkStaticStmt, nkLetSection, nkConstSection, nkVarSection, nkIdentDefs: + result = false for a in n: if a.hasCommand: return true diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 30050f25d2..0954f42fd0 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -356,12 +356,13 @@ proc useVar(a: PEffects, n: PNode) = type TIntersection = seq[tuple[id, count: int]] # a simple count table -proc addToIntersection(inter: var TIntersection, s: int, zeroInit: bool) = +proc addToIntersection(inter: var TIntersection, s: int, initOnly: bool) = for j in 0..<inter.len: if s == inter[j].id: - inc inter[j].count + if not initOnly: + inc inter[j].count return - if zeroInit: + if initOnly: inter.add((id: s, count: 0)) else: inter.add((id: s, count: 1)) diff --git a/compiler/types.nim b/compiler/types.nim index 3160583787..4dc9d36f5f 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1753,6 +1753,7 @@ proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = return true case t.kind of tyTuple: + result = false var cycleDetectorCopy: IntSet for i in 0..<t.len: cycleDetectorCopy = cycleDetector From 1cc4d3f6220c5609e38258bd2c5a348e83106be4 Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Fri, 25 Aug 2023 22:08:47 +0300 Subject: [PATCH 476/489] fix generic param substitution in templates (#22535) * fix generic param substitution in templates fixes #13527, fixes #17240, fixes #6340, fixes #20033, fixes #19576, fixes #19076 * fix bare except in test, test updated packages in CI --- compiler/sem.nim | 8 +++- compiler/semcall.nim | 7 ++- tests/template/tgenericparam.nim | 80 ++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 tests/template/tgenericparam.nim diff --git a/compiler/sem.nim b/compiler/sem.nim index f69e7a69d0..653d83aaa6 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -473,7 +473,13 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, # we now know the supplied arguments var paramTypes = initIdTable() for param, value in genericParamsInMacroCall(s, call): - idTablePut(paramTypes, param.typ, value.typ) + var givenType = value.typ + # the sym nodes used for the supplied generic arguments for + # templates and macros leave type nil so regular sem can handle it + # in this case, get the type directly from the sym + if givenType == nil and value.kind == nkSym and value.sym.typ != nil: + givenType = value.sym.typ + idTablePut(paramTypes, param.typ, givenType) retType = generateTypeInstance(c, paramTypes, macroResult.info, retType) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index e7c9226dd2..adb87b5b4c 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -655,7 +655,12 @@ proc semResolvedCall(c: PContext, x: var TCandidate, else: x.call.add c.graph.emptyNode of skType: - x.call.add newSymNode(s, n.info) + var tn = newSymNode(s, n.info) + # this node will be used in template substitution, + # pretend this is an untyped node and let regular sem handle the type + # to prevent problems where a generic parameter is treated as a value + tn.typ = nil + x.call.add tn else: internalAssert c.config, false diff --git a/tests/template/tgenericparam.nim b/tests/template/tgenericparam.nim new file mode 100644 index 0000000000..d33f55cf70 --- /dev/null +++ b/tests/template/tgenericparam.nim @@ -0,0 +1,80 @@ +block: # basic template generic parameter substitution + block: # issue #13527 + template typeNameTempl[T](a: T): string = $T + proc typeNameProc[T](a: T): string = $T + doAssert typeNameTempl(1) == typeNameProc(1) + doAssert typeNameTempl(true) == typeNameProc(true) + doAssert typeNameTempl(1.0) == typeNameProc(1.0) + doAssert typeNameTempl(1u8) == typeNameProc(1u8) + + template isDefault[T](a: T): bool = a == default(T) + doAssert isDefault(0.0) + + block: # issue #17240 + func to(c: int, t: typedesc[float]): t = discard + template converted[I, T](i: seq[I], t: typedesc[T]): seq[T] = + var result = newSeq[T](2) + result[0] = i[0].to(T) + result + doAssert newSeq[int](3).converted(float) == @[0.0, 0.0] + + block: # issue #6340 + type A[T] = object + v: T + proc foo(x: int): string = "int" + proc foo(x: typedesc[int]): string = "typedesc[int]" + template fooT(x: int): string = "int" + template fooT(x: typedesc[int]): string = "typedesc[int]" + proc foo[T](x: A[T]): (string, string) = + (foo(T), fooT(T)) + template fooT[T](x: A[T]): (string, string) = + (foo(T), fooT(T)) + var x: A[int] + doAssert foo(x) == fooT(x) + + block: # issue #20033 + template run[T](): T = default(T) + doAssert run[int]() == 0 + +import options, tables + +block: # complex cases of above with imports + block: # issue #19576, complex case + type RegistryKey = object + key, val: string + var regKey = @[RegistryKey(key: "abc", val: "def")] + template findFirst[T](s: seq[T], pred: proc(x: T): bool): Option[T] = + var res = none(T) # important line + for x in s: + if pred(x): + res = some(x) + break + res + proc getval(searchKey: string): Option[string] = + let found = regKey.findFirst(proc (rk: RegistryKey): bool = rk.key == searchKey) + if found.isNone: none(string) + else: some(found.get().val) + doAssert getval("strange") == none(string) + doAssert getval("abc") == some("def") + block: # issue #19076 + block: # case 1 + var tested: Table[string,int] + template `[]`[V](t:Table[string,V],key:string):untyped = + $V + doAssert tested["abc"] == "int" + template `{}`[V](t:Table[string,V],key:string):untyped = + ($V, tables.`[]`(t, key)) + doAssert (try: tested{"abc"} except KeyError: ("not there", 123)) == ("not there", 123) + tables.`[]=`(tested, "abc", 456) + doAssert tested["abc"] == "int" + doAssert tested{"abc"} == ("int", 456) + block: # case 2 + type Foo[A,T] = object + t:T + proc init[A,T](f:type Foo,a:typedesc[A],t:T):Foo[A,T] = Foo[A,T](t:t) + template fromOption[A](o:Option[A]):auto = + when o.isSome: + Foo.init(A,35) + else: + Foo.init(A,"hi") + let op = fromOption(some(5)) From a108a451c5c4be7158283c08a89691d9684dc578 Mon Sep 17 00:00:00 2001 From: Juan Carlos <juancarlospaco@gmail.com> Date: Fri, 25 Aug 2023 17:55:17 -0300 Subject: [PATCH 477/489] Improve compiler cli args (#22509) * . * Fix cli args out of range with descriptive error instead of crash * https://github.com/nim-lang/Nim/pull/22509#issuecomment-1692259451 --- compiler/commands.nim | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index 6d162fab26..ba996f77ed 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -891,15 +891,19 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; defineSymbol(conf.symbols, "nodejs") of "maxloopiterationsvm": expectArg(conf, switch, arg, pass, info) - conf.maxLoopIterationsVM = parseInt(arg) + var value: int = 10_000_000 + discard parseSaturatedNatural(arg, value) + if not value > 0: localError(conf, info, "maxLoopIterationsVM must be a positive integer greater than zero") + conf.maxLoopIterationsVM = value of "errormax": expectArg(conf, switch, arg, pass, info) # Note: `nim check` (etc) can overwrite this. # `0` is meaningless, give it a useful meaning as in clang's -ferror-limit # If user doesn't set this flag and the code doesn't either, it'd # have the same effect as errorMax = 1 - let ret = parseInt(arg) - conf.errorMax = if ret == 0: high(int) else: ret + var value: int = 0 + discard parseSaturatedNatural(arg, value) + conf.errorMax = if value == 0: high(int) else: value of "verbosity": expectArg(conf, switch, arg, pass, info) let verbosity = parseInt(arg) @@ -913,7 +917,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf.mainPackageNotes = conf.notes of "parallelbuild": expectArg(conf, switch, arg, pass, info) - conf.numberOfProcessors = parseInt(arg) + var value: int = 0 + discard parseSaturatedNatural(arg, value) + conf.numberOfProcessors = value of "version", "v": expectNoArg(conf, switch, arg, pass, info) writeVersionInfo(conf, pass) From c19fd69b693e0e71d8d03812a42c4b8e50c51a3e Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Sun, 27 Aug 2023 12:27:47 +0300 Subject: [PATCH 478/489] test case haul for old generic/template/macro issues (#22564) * test case haul for old generic/template/macro issues closes #12582, closes #19552, closes #2465, closes #4596, closes #15246, closes #12683, closes #7889, closes #4547, closes #12415, closes #2002, closes #1771, closes #5121 The test for #5648 is also moved into its own test from `types/tissues_types` due to not being joinable. * fix template gensym test --- tests/generics/treentranttypes.nim | 11 ++++ .../generics/tuninstantiatedgenericcalls.nim | 62 +++++++++++++++++++ tests/macros/tmacros_various.nim | 31 ++++++++++ tests/template/mdotcall.nim | 32 ++++++++++ tests/template/tdotcall.nim | 12 ++++ tests/template/template_various.nim | 36 +++++++++++ tests/template/tobjectdeclfield.nim | 25 +++++--- tests/types/t5648.nim | 32 ++++++++++ tests/types/tissues_types.nim | 41 +++++------- 9 files changed, 248 insertions(+), 34 deletions(-) create mode 100644 tests/types/t5648.nim diff --git a/tests/generics/treentranttypes.nim b/tests/generics/treentranttypes.nim index 40ff1647b9..801f0e444f 100644 --- a/tests/generics/treentranttypes.nim +++ b/tests/generics/treentranttypes.nim @@ -101,3 +101,14 @@ echo @(b.arr[0].arr), @(b.arr[1].arr) let y = b echo @(y.arr[0].arr), @(y.arr[1].arr) +import macros + +block: # issue #5121 + type + A = object + AConst[X] = A + + macro dumpType(t: typedesc): untyped = + result = newTree(nnkTupleConstr, newLit $t.getType[1].typeKind, newLit t.getType[1].treeRepr) + + doAssert dumpType(A) == ("ntyObject", "Sym \"A\"") diff --git a/tests/generics/tuninstantiatedgenericcalls.nim b/tests/generics/tuninstantiatedgenericcalls.nim index b12a33fe79..bac334e955 100644 --- a/tests/generics/tuninstantiatedgenericcalls.nim +++ b/tests/generics/tuninstantiatedgenericcalls.nim @@ -78,3 +78,65 @@ block: doAssert x.data.len == 5 var y: Leb128Buf[uint16] doAssert y.data.len == 3 + +import macros + +block: # issue #12415 + macro isSomePointerImpl(t: typedesc): bool = + var impl = t.getTypeInst[1].getTypeImpl + if impl.kind == nnkDistinctTy: + impl = impl[0].getTypeImpl + if impl.kind in {nnkPtrTy,nnkRefTy}: + result = newLit(true) + elif impl.kind == nnkSym and impl.eqIdent("pointer"): + result = newLit(true) + else: + result = newLit(false) + + proc isSomePointer[T](t: typedesc[T]): bool {.compileTime.} = + isSomePointerImpl(t) + + type + Option[T] = object + ## An optional type that stores its value and state separately in a boolean. + when isSomePointer(typedesc(T)): + val: T + else: + val: T + has: bool + var x: Option[ref int] + doAssert not compiles(x.has) + var y: Option[int] + doAssert compiles(y.has) + +block: # issue #2002 + proc isNillable(T: typedesc): bool = + when compiles((let v: T = nil)): + return true + else: + return false + + type + Foo[T] = object + when isNillable(T): + nillable: float + else: + notnillable: int + + var val1: Foo[ref int] + doAssert compiles(val1.nillable) + doAssert not compiles(val1.notnillable) + var val2: Foo[int] + doAssert not compiles(val2.nillable) + doAssert compiles(val2.notnillable) + +block: # issue #1771 + type + Foo[X, T] = object + bar: array[X.low..X.high, T] + + proc test[X, T](f: Foo[X, T]): T = + f.bar[X.low] + + var a: Foo[range[0..2], float] + doAssert test(a) == 0.0 diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim index 2446912ea3..e351b45271 100644 --- a/tests/macros/tmacros_various.nim +++ b/tests/macros/tmacros_various.nim @@ -268,6 +268,37 @@ xbenchmark: discard inputtest fastSHA("hey") +block: # issue #4547 + macro lazy(stmtList : typed) : untyped = + let decl = stmtList[0] + decl.expectKind nnkLetSection + let name = decl[0][0].strVal + let call = decl[0][2].copy + call.expectKind nnkCall + let ident = newIdentNode("get" & name) + result = quote do: + var value : type(`call`) + proc `ident`() : type(`call`) = + if value.isNil: + value = `call` + value + type MyObject = object + a,b: int + # this part, the macro call and it's result (written in the comment below) is important + lazy: + let y = new(MyObject) + #[ + var value: type(new(MyObject)) + proc gety(): type(new(MyObject)) = + if value.isNil: + value = new(MyObject) + value + ]# + doAssert gety().a == 0 # works and should work + doAssert gety().b == 0 # works and should work + doAssert not declared(y) + doAssert not compiles(y.a) # identifier y should not exist anymore + doAssert not compiles(y.b) # identifier y should not exist anymore block: # bug #13511 type diff --git a/tests/template/mdotcall.nim b/tests/template/mdotcall.nim index 13dcbd8248..fecd8ee266 100644 --- a/tests/template/mdotcall.nim +++ b/tests/template/mdotcall.nim @@ -48,3 +48,35 @@ template publicTemplateObjSyntax*(o: var ObjA, arg: Natural, doStuff: untyped) = o.foo2() doStuff o.bar2(arg) + +# issue #15246 +import os + +template sourceBaseName*(): string = + bind splitFile + instantiationInfo().filename.splitFile().name + +# issue #12683 + +import unicode +template toRune(s: string): Rune = s.runeAt(0) +proc heh*[T](x: Slice[T], chars: string) = discard chars.toRune + +# issue #7889 + +from streams import newStringStream, readData, writeData + +template bindmeTemplate*(): untyped = + var tst = "sometext" + var ss = newStringStream("anothertext") + ss.writeData(tst[0].addr, 2) + discard ss.readData(tst[0].addr, 2) # <= comment this out to make compilation successful + +from macros import quote, newIdentNode + +macro bindmeQuote*(): untyped = + quote do: + var tst = "sometext" + var ss = newStringStream("anothertext") + ss.writeData(tst[0].addr, 2) + discard ss.readData(tst[0].addr, 2) # <= comment this out to make compilation successful diff --git a/tests/template/tdotcall.nim b/tests/template/tdotcall.nim index 5fc991dd2d..dc97fd52e6 100644 --- a/tests/template/tdotcall.nim +++ b/tests/template/tdotcall.nim @@ -18,3 +18,15 @@ block: # issue #11733 var evaluated = false a.publicTemplateObjSyntax(42): evaluated = true doAssert evaluated + +block: # issue #15246 + doAssert sourceBaseName() == "tdotcall" + +block: # issue #12683 + heh(0..40, "|") + +block: # issue #7889 + if false: + bindmeQuote() + if false: + bindmeTemplate() diff --git a/tests/template/template_various.nim b/tests/template/template_various.nim index a3b549e181..2088b1739f 100644 --- a/tests/template/template_various.nim +++ b/tests/template/template_various.nim @@ -354,6 +354,23 @@ block gensym3: echo a ! b ! c ! d ! e echo x,y,z +block: # issue #2465 + template t() = + template declX(str: string) {.gensym.} = + var x {.inject.} : string = str + + t() + doAssert not declared(declX) + doAssert not compiles(declX("a string")) + + template t2() = + template fooGensym() {.gensym.} = + echo 42 + + t2() + doAssert not declared(fooGensym) + doAssert not compiles(fooGensym()) + block identifier_construction_with_overridden_symbol: # could use add, but wanna make sure it's an override no matter what @@ -368,3 +385,22 @@ block identifier_construction_with_overridden_symbol: `examplefn n`() exampletempl(1) + +import typetraits + +block: # issue #4596 + type + T0 = object + T1 = object + + template printFuncsT() = + proc getV[A](a: typedesc[A]): string = + var s {. global .} = name(A) + return s + + printFuncsT() + + doAssert getV(T1) == "T1" + doAssert getV(T0) == "T0" + doAssert getV(T0) == "T0" + doAssert getV(T1) == "T1" diff --git a/tests/template/tobjectdeclfield.nim b/tests/template/tobjectdeclfield.nim index 201f076ca3..afce2cae81 100644 --- a/tests/template/tobjectdeclfield.nim +++ b/tests/template/tobjectdeclfield.nim @@ -1,12 +1,21 @@ -var x = 0 +block: # issue #16005 + var x = 0 -block: - type Foo = object - x: float # ok - -template main() = block: type Foo = object - x: float # Error: cannot use symbol of kind 'var' as a 'field' + x: float # ok -main() + template main() = + block: + type Foo = object + x: float # Error: cannot use symbol of kind 'var' as a 'field' + + main() + +block: # issue #19552 + template test = + type + test2 = ref object + reset: int + + test() diff --git a/tests/types/t5648.nim b/tests/types/t5648.nim new file mode 100644 index 0000000000..b3bd406b3f --- /dev/null +++ b/tests/types/t5648.nim @@ -0,0 +1,32 @@ +discard """ + output: ''' +ptr Foo +''' +joinable: false +""" +# not joinable because it causes out of memory with --gc:boehm + +# issue #5648 + +import typetraits + +type Foo = object + bar: int + +proc main() = + var f = create(Foo) + f.bar = 3 + echo f.type.name + + discard realloc(f, 0) + + var g = Foo() + g.bar = 3 + +var + mainPtr = cast[pointer](main) + mainFromPtr = cast[typeof(main)](mainPtr) + +doAssert main == mainFromPtr + +main() diff --git a/tests/types/tissues_types.nim b/tests/types/tissues_types.nim index 275941caec..eab4e8e9be 100644 --- a/tests/types/tissues_types.nim +++ b/tests/types/tissues_types.nim @@ -3,7 +3,6 @@ discard """ true true true -ptr Foo (member: "hello world") (member: 123.456) (member: "hello world", x: ...) @@ -11,10 +10,7 @@ ptr Foo 0 false ''' -joinable: false """ -# not joinable because it causes out of memory with --gc:boehm -import typetraits block t1252: echo float32 isnot float64 @@ -29,28 +25,6 @@ block t5640: var v = vec2([0.0'f32, 0.0'f32]) -block t5648: - type Foo = object - bar: int - - proc main() = - var f = create(Foo) - f.bar = 3 - echo f.type.name - - discard realloc(f, 0) - - var g = Foo() - g.bar = 3 - - var - mainPtr = cast[pointer](main) - mainFromPtr = cast[typeof(main)](mainPtr) - - doAssert main == mainFromPtr - - main() - block t7581: discard int -1 @@ -107,3 +81,18 @@ block: var f1: Foo echo f1.bar + +import macros + +block: # issue #12582 + macro foo(T: type): type = + nnkBracketExpr.newTree(bindSym "array", newLit 1, T) + var + _: foo(int) # fine + type + Foo = object + x: foo(int) # fine + Bar = ref object + x: foo(int) # error + let b = Bar() + let b2 = Bar(x: [123]) From 0b78b7f595ef96a9769e0d59167239c611b9857a Mon Sep 17 00:00:00 2001 From: Bung <crc32@qq.com> Date: Sun, 27 Aug 2023 20:29:24 +0800 Subject: [PATCH 479/489] =?UTF-8?q?fix=20#22548;environment=20misses=20for?= =?UTF-8?q?=20type=20reference=20in=20iterator=20access=20n=E2=80=A6=20(#2?= =?UTF-8?q?2559)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix #22548;environment misses for type reference in iterator access nested in closure * fix #21737 * Update lambdalifting.nim * remove containsCallKinds * simplify --- compiler/lambdalifting.nim | 24 +++++++++++++++++++----- tests/iter/t21737.nim | 22 ++++++++++++++++++++++ tests/iter/t22548.nim | 21 +++++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 tests/iter/t21737.nim create mode 100644 tests/iter/t22548.nim diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index ee1e5b7976..ee19eec081 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -316,6 +316,7 @@ type processed, capturedVars: IntSet ownerToType: Table[int, PType] somethingToDo: bool + inTypeOf: bool graph: ModuleGraph idgen: IdGenerator @@ -417,6 +418,9 @@ Consider: """ +proc isTypeOf(n: PNode): bool = + n.kind == nkSym and n.sym.magic in {mTypeOf, mType} + proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) = var cp = getEnvParam(fn) let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner @@ -455,7 +459,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = c.somethingToDo = true addClosureParam(c, owner, n.info) if interestingIterVar(s): - if not c.capturedVars.containsOrIncl(s.id): + if not c.capturedVars.contains(s.id): + if not c.inTypeOf: c.capturedVars.incl(s.id) let obj = getHiddenParam(c.graph, owner).typ.skipTypes({tyOwned, tyRef, tyPtr}) #let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr}) @@ -481,10 +486,12 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = addClosureParam(c, owner, n.info) #echo "capturing ", n.info # variable 's' is actually captured: - if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id): - let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr}) - #getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr}) - discard addField(obj, s, c.graph.cache, c.idgen) + if interestingVar(s): + if not c.capturedVars.contains(s.id): + if not c.inTypeOf: c.capturedVars.incl(s.id) + let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr}) + #getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr}) + discard addField(obj, s, c.graph.cache, c.idgen) # create required upFields: var w = owner.skipGenericOwner if isInnerProc(w) or owner.isIterator: @@ -516,9 +523,14 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) = detectCapturedVars(n[namePos], owner, c) of nkReturnStmt: detectCapturedVars(n[0], owner, c) + of nkIdentDefs: + detectCapturedVars(n[^1], owner, c) else: + if n.isCallExpr and n[0].isTypeOf: + c.inTypeOf = true for i in 0..<n.len: detectCapturedVars(n[i], owner, c) + c.inTypeOf = false type LiftingPass = object @@ -798,6 +810,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass; of nkTypeOfExpr: result = n else: + if n.isCallExpr and n[0].isTypeOf: + return if owner.isIterator: if nfLL in n.flags: # special case 'when nimVm' due to bug #3636: diff --git a/tests/iter/t21737.nim b/tests/iter/t21737.nim new file mode 100644 index 0000000000..da06faea71 --- /dev/null +++ b/tests/iter/t21737.nim @@ -0,0 +1,22 @@ +discard """ + action: compile +""" + +template mytoSeq*(iter: untyped): untyped = + var result: seq[typeof(iter)]# = @[] + for x in iter: + result.add(x) + result + +iterator test(dir:int): int = + yield 1234 + +iterator walkGlobKinds (): int = + let dir2 = 123 + let it = mytoSeq(test(dir2)) + +proc main()= + let it = iterator(): int= + for path in walkGlobKinds(): + yield path +main() diff --git a/tests/iter/t22548.nim b/tests/iter/t22548.nim new file mode 100644 index 0000000000..b9abb75d03 --- /dev/null +++ b/tests/iter/t22548.nim @@ -0,0 +1,21 @@ +discard """ + action: compile +""" + +type Xxx[T] = object + +iterator x(v: string): char = + var v2: Xxx[int] + + var y: v2.T + + echo y + +proc bbb(vv: string): proc () = + proc xxx() = + for c in x(vv): + echo c + + return xxx + +bbb("test")() From 100eb6820c271bbd1c02a8e6a9001fc5a08a2637 Mon Sep 17 00:00:00 2001 From: Bung <crc32@qq.com> Date: Sun, 27 Aug 2023 22:56:50 +0800 Subject: [PATCH 480/489] close #9334 (#22565) --- tests/closure/t9334.nim | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/closure/t9334.nim diff --git a/tests/closure/t9334.nim b/tests/closure/t9334.nim new file mode 100644 index 0000000000..36a9a7d77c --- /dev/null +++ b/tests/closure/t9334.nim @@ -0,0 +1,19 @@ +discard """ + cmd: "nim $target --hints:off $options -r $file" + nimout: '''@[1] +@[1, 1] +''' + nimoutFull: true +""" +proc p(s: var seq[int]): auto = + let sptr = addr s + return proc() = sptr[].add 1 + +proc f = + var data = @[1] + p(data)() + echo repr data + +static: + f() # prints [1] +f() # prints [1, 1] From 094a29eb315b571924bb3b381eb25df8fb9c193c Mon Sep 17 00:00:00 2001 From: Bung <crc32@qq.com> Date: Mon, 28 Aug 2023 12:31:16 +0800 Subject: [PATCH 481/489] add test case for #19095 (#22566) --- tests/closure/t19095.nim | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/closure/t19095.nim diff --git a/tests/closure/t19095.nim b/tests/closure/t19095.nim new file mode 100644 index 0000000000..880456e029 --- /dev/null +++ b/tests/closure/t19095.nim @@ -0,0 +1,35 @@ +discard """ + action: compile +""" + +block: + func inCheck() = + discard + + iterator iter(): int = + yield 0 + yield 0 + + func search() = + let inCheck = 0 + + for i in iter(): + + proc hello() = + inCheck() + + search() +block: + iterator iter(): int = + yield 0 + yield 0 + + func search() = + let lmrMoveCounter = 0 + + for i in iter(): + + proc hello() = + discard lmrMoveCounter + + search() From 306b9aca485bfc90931218c4f050863bcbe6e6c0 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 28 Aug 2023 15:57:24 +0800 Subject: [PATCH 482/489] `initCandidate` and friends now return values (#22570) * `initCandidate` and friends now return values * fixes semexprs.nim * fixes semcall.nim * Update compiler/semcall.nim --- compiler/semcall.nim | 8 +++--- compiler/semexprs.nim | 3 +-- compiler/sigmatch.nim | 61 ++++++++++++++++++------------------------- 3 files changed, 31 insertions(+), 41 deletions(-) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index adb87b5b4c..adfc98e197 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -51,9 +51,9 @@ proc initCandidateSymbols(c: PContext, headSymbol: PNode, result.add((symx, o.lastOverloadScope)) symx = nextOverloadIter(o, c, headSymbol) if result.len > 0: - initCandidate(c, best, result[0].s, initialBinding, + best = initCandidate(c, result[0].s, initialBinding, result[0].scope, diagnostics) - initCandidate(c, alt, result[0].s, initialBinding, + alt = initCandidate(c, result[0].s, initialBinding, result[0].scope, diagnostics) best.state = csNoMatch @@ -82,10 +82,10 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, # starts at 1 because 0 is already done with setup, only needs checking var nextSymIndex = 1 - var z: TCandidate = default(TCandidate) # current candidate + var z: TCandidate # current candidate while true: determineType(c, sym) - initCandidate(c, z, sym, initialBinding, scope, diagnosticsFlag) + z = initCandidate(c, sym, initialBinding, scope, diagnosticsFlag) # this is kinda backwards as without a check here the described # problems in recalc would not happen, but instead it 100% diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index cb4bddb5d1..ff9727967f 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -992,8 +992,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, proc resolveIndirectCall(c: PContext; n, nOrig: PNode; t: PType): TCandidate = - result = default(TCandidate) - initCandidate(c, result, t) + result = initCandidate(c, t) matches(c, n, nOrig, result) proc bracketedMacro(n: PNode): PSym = diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 7780e53f53..bb99463b64 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -100,25 +100,18 @@ proc markOwnerModuleAsUsed*(c: PContext; s: PSym) template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone proc initCandidateAux(ctx: PContext, - c: var TCandidate, callee: PType) {.inline.} = - c.c = ctx - c.exactMatches = 0 - c.subtypeMatches = 0 - c.convMatches = 0 - c.intConvMatches = 0 - c.genericMatches = 0 - c.state = csEmpty - c.firstMismatch = MismatchInfo() - c.callee = callee - c.call = nil - c.baseTypeMatch = false - c.genericConverter = false - c.inheritancePenalty = 0 + callee: PType): TCandidate {.inline.} = + result = TCandidate(c: ctx, exactMatches: 0, subtypeMatches: 0, + convMatches: 0, intConvMatches: 0, genericMatches: 0, + state: csEmpty, firstMismatch: MismatchInfo(), + callee: callee, call: nil, baseTypeMatch: false, + genericConverter: false, inheritancePenalty: 0 + ) -proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) = - initCandidateAux(ctx, c, callee) - c.calleeSym = nil - c.bindings = initIdTable() +proc initCandidate*(ctx: PContext, callee: PType): TCandidate = + result = initCandidateAux(ctx, callee) + result.calleeSym = nil + result.bindings = initIdTable() proc put(c: var TCandidate, key, val: PType) {.inline.} = ## Given: proc foo[T](x: T); foo(4) @@ -134,27 +127,27 @@ proc put(c: var TCandidate, key, val: PType) {.inline.} = echo "binding ", key, " -> ", val idTablePut(c.bindings, key, val.skipIntLit(c.c.idgen)) -proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, +proc initCandidate*(ctx: PContext, callee: PSym, binding: PNode, calleeScope = -1, - diagnosticsEnabled = false) = - initCandidateAux(ctx, c, callee.typ) - c.calleeSym = callee + diagnosticsEnabled = false): TCandidate = + result = initCandidateAux(ctx, callee.typ) + result.calleeSym = callee if callee.kind in skProcKinds and calleeScope == -1: if callee.originatingModule == ctx.module: - c.calleeScope = 2 + result.calleeScope = 2 var owner = callee while true: owner = owner.skipGenericOwner if owner.kind == skModule: break - inc c.calleeScope + inc result.calleeScope else: - c.calleeScope = 1 + result.calleeScope = 1 else: - c.calleeScope = calleeScope - c.diagnostics = @[] # if diagnosticsEnabled: @[] else: nil - c.diagnosticsEnabled = diagnosticsEnabled - c.magic = c.calleeSym.magic - c.bindings = initIdTable() + result.calleeScope = calleeScope + result.diagnostics = @[] # if diagnosticsEnabled: @[] else: nil + result.diagnosticsEnabled = diagnosticsEnabled + result.magic = result.calleeSym.magic + result.bindings = initIdTable() if binding != nil and callee.kind in routineKinds: var typeParams = callee.ast[genericParamsPos] for i in 1..min(typeParams.len, binding.len-1): @@ -166,16 +159,14 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, bound = makeTypeDesc(ctx, bound) else: bound = bound.skipTypes({tyTypeDesc}) - put(c, formalTypeParam, bound) + put(result, formalTypeParam, bound) proc newCandidate*(ctx: PContext, callee: PSym, binding: PNode, calleeScope = -1): TCandidate = - result = default(TCandidate) - initCandidate(ctx, result, callee, binding, calleeScope) + result = initCandidate(ctx, callee, binding, calleeScope) proc newCandidate*(ctx: PContext, callee: PType): TCandidate = - result = default(TCandidate) - initCandidate(ctx, result, callee) + result = initCandidate(ctx, callee) proc copyCandidate(a: var TCandidate, b: TCandidate) = a.c = b.c From 2e7c8a339f654ebd6fe178f4c81aa89c14851f22 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 28 Aug 2023 16:43:58 +0800 Subject: [PATCH 483/489] newStringOfCap now won't initialize all elements anymore (#22568) newStringOfCap nows won't initialize all elements anymore --- lib/system/strs_v2.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index 296aae045f..1c15d14711 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -108,10 +108,11 @@ proc rawNewString(space: int): NimStringV2 {.compilerproc.} = result = NimStringV2(len: 0, p: nil) else: when compileOption("threads"): - var p = cast[ptr NimStrPayload](allocShared0(contentSize(space))) + var p = cast[ptr NimStrPayload](allocShared(contentSize(space))) else: - var p = cast[ptr NimStrPayload](alloc0(contentSize(space))) + var p = cast[ptr NimStrPayload](alloc(contentSize(space))) p.cap = space + p.data[0] = '\0' result = NimStringV2(len: 0, p: p) proc mnewString(len: int): NimStringV2 {.compilerproc.} = From 94454addb2a045731f2b4f44d697a319e3a20071 Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Mon, 28 Aug 2023 16:09:43 +0300 Subject: [PATCH 484/489] define toList procs after add for lists [backport] (#22573) fixes #22543 --- lib/pure/collections/lists.nim | 44 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index e1d32e7372..b9d5c48eb5 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -165,28 +165,6 @@ proc newSinglyLinkedNode*[T](value: T): SinglyLinkedNode[T] = new(result) result.value = value -func toSinglyLinkedList*[T](elems: openArray[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} = - ## Creates a new `SinglyLinkedList` from the members of `elems`. - runnableExamples: - from std/sequtils import toSeq - let a = [1, 2, 3, 4, 5].toSinglyLinkedList - assert a.toSeq == [1, 2, 3, 4, 5] - - result = initSinglyLinkedList[T]() - for elem in elems.items: - result.add(elem) - -func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} = - ## Creates a new `DoublyLinkedList` from the members of `elems`. - runnableExamples: - from std/sequtils import toSeq - let a = [1, 2, 3, 4, 5].toDoublyLinkedList - assert a.toSeq == [1, 2, 3, 4, 5] - - result = initDoublyLinkedList[T]() - for elem in elems.items: - result.add(elem) - template itemsListImpl() {.dirty.} = var it {.cursor.} = L.head while it != nil: @@ -993,3 +971,25 @@ proc appendMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} = ## * `addMoved proc <#addMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_ ## * `addMoved proc <#addMoved,DoublyLinkedList[T],DoublyLinkedList[T]>`_ a.addMoved(b) + +func toSinglyLinkedList*[T](elems: openArray[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} = + ## Creates a new `SinglyLinkedList` from the members of `elems`. + runnableExamples: + from std/sequtils import toSeq + let a = [1, 2, 3, 4, 5].toSinglyLinkedList + assert a.toSeq == [1, 2, 3, 4, 5] + + result = initSinglyLinkedList[T]() + for elem in elems.items: + result.add(elem) + +func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} = + ## Creates a new `DoublyLinkedList` from the members of `elems`. + runnableExamples: + from std/sequtils import toSeq + let a = [1, 2, 3, 4, 5].toDoublyLinkedList + assert a.toSeq == [1, 2, 3, 4, 5] + + result = initDoublyLinkedList[T]() + for elem in elems.items: + result.add(elem) From 3de8d755135d94983ca087f448ad76832c341eaa Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Mon, 28 Aug 2023 22:40:46 +0300 Subject: [PATCH 485/489] correct logic for qualified symbol in templates (#22577) * correct logic for qualified symbol in templates fixes #19865 * add test --- compiler/semtempl.nim | 5 ++++- tests/template/template_issues.nim | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 85411f7c46..eec0281222 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -567,6 +567,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = # so we use the generic code for nkDotExpr too let s = qualifiedLookUp(c.c, n, {}) if s != nil: + # mirror the nkIdent case # do not symchoice a quoted template parameter (bug #2390): if s.owner == c.owner and s.kind == skParam and n.kind == nkAccQuoted and n.len == 1: @@ -578,7 +579,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = elif contains(c.toMixin, s.name.id): return symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0) else: - return symChoice(c.c, n, s, scOpen, c.noGenSym > 0) + if s.kind in {skType, skVar, skLet, skConst}: + discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule}) + return semTemplSymbol(c.c, n, s, c.noGenSym > 0) if n.kind == nkDotExpr: result = n result[0] = semTemplBody(c, n[0]) diff --git a/tests/template/template_issues.nim b/tests/template/template_issues.nim index 58c40941db..5b7c54ed64 100644 --- a/tests/template/template_issues.nim +++ b/tests/template/template_issues.nim @@ -302,3 +302,7 @@ block: # bug #21920 discard t[void]() # Error: expression has no type: discard + +block: # issue #19865 + template f() = discard default(system.int) + f() From 6b955ac4af834fb9765b5b2a2588a5feb1de31f0 Mon Sep 17 00:00:00 2001 From: metagn <metagngn@gmail.com> Date: Mon, 28 Aug 2023 22:41:18 +0300 Subject: [PATCH 486/489] properly fold constants for dynlib pragma (#22575) fixes #12929 --- compiler/pragmas.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 6a371ba067..49b3b819e4 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -333,7 +333,7 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode = # {.dynlib: myGetProcAddr(...).} result = c.semExpr(c, n[1]) if result.kind == nkSym and result.sym.kind == skConst: - result = result.sym.astdef # look it up + result = c.semConstExpr(c, result) # fold const if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}: localError(c.config, n.info, errStringLiteralExpected) result = newEmptyStrNode(c, n) From d8ffc6a75edbed49e24f9ed5c9eff892eefc3ee7 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 29 Aug 2023 13:59:51 +0800 Subject: [PATCH 487/489] minor style changes in the compiler (#22584) * minor style changes in the compiler * use raiseAssert --- compiler/vm.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/vm.nim b/compiler/vm.nim index 79832dbcb5..18b2648658 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1392,8 +1392,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let prcValue = c.globals[prc.position-1] if prcValue.kind == nkEmpty: globalError(c.config, c.debug[pc], "cannot run " & prc.name.s) - var slots2: TNodeSeq = default(TNodeSeq) - slots2.setLen(tos.slots.len) + var slots2: TNodeSeq = newSeq[PNode](tos.slots.len) for i in 0..<tos.slots.len: slots2[i] = regToNode(tos.slots[i]) let newValue = callForeignFunction(c.config, prcValue, prc.typ, slots2, @@ -1482,7 +1481,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcExcept: # This opcode is never executed, it only holds information for the # exception handling routines. - doAssert(false) + raiseAssert "unreachable" of opcFinally: # Pop the last safepoint introduced by a opcTry. This opcode is only # executed _iff_ no exception was raised in the body of the `try` From 1fcb53cded47a9671671170f0df42f6efbde5be4 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:40:19 +0800 Subject: [PATCH 488/489] fixes broken nightlies; follow up #22544 (#22585) ref https://github.com/nim-lang/nightlies/actions/runs/5970369118/job/16197865657 > /home/runner/work/nightlies/nightlies/nim/lib/pure/os.nim(678, 30) Error: getApplOpenBsd() can raise an unlisted exception: ref OSError --- lib/pure/os.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 13b103b925..7ba156c89f 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -675,7 +675,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW elif defined(haiku): result = getApplHaiku() elif defined(openbsd): - result = getApplOpenBsd() + result = try: getApplOpenBsd() except OSError: "" elif defined(nintendoswitch): result = "" From e53c66ef39e9f6b521835399677430c2c980ee64 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 29 Aug 2023 19:29:42 +0800 Subject: [PATCH 489/489] fixes #22555; implements `newStringUninit` (#22572) * fixes newStringUninitialized; implement `newStringUninitialized` * add a simple test case * adds a changelog * Update lib/system.nim * Apply suggestions from code review rename to newStringUninit --- changelog.md | 2 + lib/system.nim | 58 ++++++++++++++--------- tests/system/tnewstring_uninitialized.nim | 11 +++++ 3 files changed, 49 insertions(+), 22 deletions(-) create mode 100644 tests/system/tnewstring_uninitialized.nim diff --git a/changelog.md b/changelog.md index b4b8ca532d..fb0102cd3a 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,8 @@ [//]: # "Additions:" +- Adds `newStringUninit` to system, which creates a new string of length `len` like `newString` but with uninitialized content. + [//]: # "Deprecations:" diff --git a/lib/system.nim b/lib/system.nim index 4163534cf6..c3cad4f711 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -646,26 +646,6 @@ proc newSeqOfCap*[T](cap: Natural): seq[T] {. ## ``` discard -when not defined(js): - proc newSeqUninitialized*[T: SomeNumber](len: Natural): seq[T] = - ## Creates a new sequence of type `seq[T]` with length `len`. - ## - ## Only available for numbers types. Note that the sequence will be - ## uninitialized. After the creation of the sequence you should assign - ## entries to the sequence instead of adding them. - ## Example: - ## ```nim - ## var x = newSeqUninitialized[int](3) - ## assert len(x) == 3 - ## x[0] = 10 - ## ``` - result = newSeqOfCap[T](len) - when defined(nimSeqsV2): - cast[ptr int](addr result)[] = len - else: - var s = cast[PGenericSeq](result) - s.len = len - func len*[TOpenArray: openArray|varargs](x: TOpenArray): int {.magic: "LengthOpenArray".} = ## Returns the length of an openArray. runnableExamples: @@ -973,8 +953,8 @@ proc setLen*(s: var string, newlen: Natural) {. proc newString*(len: Natural): string {. magic: "NewString", importc: "mnewString", noSideEffect.} - ## Returns a new string of length `len` but with uninitialized - ## content. One needs to fill the string character after character + ## Returns a new string of length `len`. + ## One needs to fill the string character after character ## with the index operator `s[i]`. ## ## This procedure exists only for optimization purposes; @@ -1630,6 +1610,40 @@ when notJSnotNims and defined(nimSeqsV2): include "system/strs_v2" include "system/seqs_v2" +when not defined(js): + proc newSeqUninitialized*[T: SomeNumber](len: Natural): seq[T] = + ## Creates a new sequence of type `seq[T]` with length `len`. + ## + ## Only available for numbers types. Note that the sequence will be + ## uninitialized. After the creation of the sequence you should assign + ## entries to the sequence instead of adding them. + ## Example: + ## ```nim + ## var x = newSeqUninitialized[int](3) + ## assert len(x) == 3 + ## x[0] = 10 + ## ``` + result = newSeqOfCap[T](len) + when defined(nimSeqsV2): + cast[ptr int](addr result)[] = len + else: + var s = cast[PGenericSeq](result) + s.len = len + + proc newStringUninit*(len: Natural): string = + ## Returns a new string of length `len` but with uninitialized + ## content. One needs to fill the string character after character + ## with the index operator `s[i]`. + ## + ## This procedure exists only for optimization purposes; + ## the same effect can be achieved with the `&` operator or with `add`. + result = newStringOfCap(len) + when defined(nimSeqsV2): + cast[ptr int](addr result)[] = len + else: + var s = cast[PGenericSeq](result) + s.len = len + {.pop.} when not defined(nimscript): diff --git a/tests/system/tnewstring_uninitialized.nim b/tests/system/tnewstring_uninitialized.nim new file mode 100644 index 0000000000..9bc0e16229 --- /dev/null +++ b/tests/system/tnewstring_uninitialized.nim @@ -0,0 +1,11 @@ +discard """ + matrix: "--mm:refc;" +""" + +# bug #22555 +var x = newStringUninit(10) +doAssert x.len == 10 +for i in 0..<x.len: + x[i] = chr(ord('a') + i) + +doAssert x == "abcdefghij"