From 02e3487c9c95b5faa186292a7ea682671f06c035 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 7 Aug 2025 23:45:00 +0800 Subject: [PATCH 01/21] `std/locks` use header files instead of dlls on windows (#25090) ref https://github.com/nim-lang/nimony/pull/1370 --- lib/std/private/syslocks.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/std/private/syslocks.nim b/lib/std/private/syslocks.nim index e19ec2c04d..70f61d60bb 100644 --- a/lib/std/private/syslocks.nim +++ b/lib/std/private/syslocks.nim @@ -51,20 +51,20 @@ when defined(windows): proc initializeConditionVariable( conditionVariable: var SysCond - ) {.stdcall, noSideEffect, dynlib: "kernel32", importc: "InitializeConditionVariable".} + ) {.stdcall, noSideEffect, header: "", importc: "InitializeConditionVariable".} proc sleepConditionVariableCS( conditionVariable: var SysCond, PCRITICAL_SECTION: var SysLock, dwMilliseconds: int - ): int32 {.stdcall, noSideEffect, dynlib: "kernel32", importc: "SleepConditionVariableCS".} + ): int32 {.stdcall, noSideEffect, header: "", importc: "SleepConditionVariableCS".} proc signalSysCond*(hEvent: var SysCond) {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "WakeConditionVariable".} + header: "", importc: "WakeConditionVariable".} proc broadcastSysCond*(hEvent: var SysCond) {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "WakeAllConditionVariable".} + header: "", importc: "WakeAllConditionVariable".} proc initSysCond*(cond: var SysCond) {.inline.} = initializeConditionVariable(cond) From a0b3048f3f5215c3c12d3714df905ecda1757892 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 8 Aug 2025 22:22:23 +0800 Subject: [PATCH 02/21] Revert "`std/locks` use header files instead of dlls on windows" (#25091) Reverts nim-lang/Nim#25090 It seems to cause problems for C++ and i686 ``` 2025-08-08T02:37:55.5976232Z c:/a/nightlies/nightlies/external/mingw32/bin/../lib/gcc/i686-w64-mingw32/11.1.0/../../../../i686-w64-mingw32/bin/ld.exe: C:\Users\runneradmin\nimcache\manual_experimental_snippet_106_d\@pstd@sprivate@ssyslocks.nim.c.o:@pstd@sprivate@ssyslocks.nim.c:(.text+0x29): undefined reference to `SleepConditionVariableCS' 2025-08-08T02:37:55.5978066Z c:/a/nightlies/nightlies/external/mingw32/bin/../lib/gcc/i686-w64-mingw32/11.1.0/../../../../i686-w64-mingw32/bin/ld.exe: C:\Users\runneradmin\nimcache\manual_experimental_snippet_106_d\@pthreadpool.nim.c.o:@pthreadpool.nim.c:(.text+0x26): undefined reference to `InitializeConditionVariable' 2025-08-08T02:37:55.5980101Z c:/a/nightlies/nightlies/external/mingw32/bin/../lib/gcc/i686-w64-mingw32/11.1.0/../../../../i686-w64-mingw32/bin/ld.exe: C:\Users\runneradmin\nimcache\manual_experimental_snippet_106_d\@pthreadpool.nim.c.o:@pthreadpool.nim.c:(.text+0x116): undefined reference to `WakeConditionVariable' 2025-08-08T02:37:55.5981093Z collect2.exe: error: ld returned 1 exit status 2025-08-08T02:37:55.5988564Z Error: execution of an external program failed: 'gcc.exe -o ``` --- lib/std/private/syslocks.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/std/private/syslocks.nim b/lib/std/private/syslocks.nim index 70f61d60bb..e19ec2c04d 100644 --- a/lib/std/private/syslocks.nim +++ b/lib/std/private/syslocks.nim @@ -51,20 +51,20 @@ when defined(windows): proc initializeConditionVariable( conditionVariable: var SysCond - ) {.stdcall, noSideEffect, header: "", importc: "InitializeConditionVariable".} + ) {.stdcall, noSideEffect, dynlib: "kernel32", importc: "InitializeConditionVariable".} proc sleepConditionVariableCS( conditionVariable: var SysCond, PCRITICAL_SECTION: var SysLock, dwMilliseconds: int - ): int32 {.stdcall, noSideEffect, header: "", importc: "SleepConditionVariableCS".} + ): int32 {.stdcall, noSideEffect, dynlib: "kernel32", importc: "SleepConditionVariableCS".} proc signalSysCond*(hEvent: var SysCond) {.stdcall, noSideEffect, - header: "", importc: "WakeConditionVariable".} + dynlib: "kernel32", importc: "WakeConditionVariable".} proc broadcastSysCond*(hEvent: var SysCond) {.stdcall, noSideEffect, - header: "", importc: "WakeAllConditionVariable".} + dynlib: "kernel32", importc: "WakeAllConditionVariable".} proc initSysCond*(cond: var SysCond) {.inline.} = initializeConditionVariable(cond) From 53bb0b591acac94fc336796bb7a536f10ef43c73 Mon Sep 17 00:00:00 2001 From: Laylie <202595611+laylie527@users.noreply.github.com> Date: Sun, 10 Aug 2025 17:38:39 +0800 Subject: [PATCH 03/21] Link to nims docs from nimc docs (#25095) --- doc/nimc.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/nimc.md b/doc/nimc.md index 1bc3edc4cf..24a2b3afe1 100644 --- a/doc/nimc.md +++ b/doc/nimc.md @@ -224,6 +224,8 @@ directories (in this order; later files overwrite previous settings): command-line option. +[NimScript files](nims.html) can also be used for configuration. + Command-line settings have priority over configuration file settings. The default build of a project is a `debug build`:idx:. To compile a From c6352ce0ab5fef061b43c8ca960ff7728541b30b Mon Sep 17 00:00:00 2001 From: RAMLAH MUNIR Date: Thu, 14 Aug 2025 19:33:52 +0500 Subject: [PATCH 04/21] closes #25084 : docs: fix example for *+ operator (#25102) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Fixed an inconsistency in the Nim manual's example for the `*+` operator. Previously, the example on line 4065 of `doc/manual.md` used variables `a`, `b`, and `c`: ```nim assert `*+`(3, 4, 6) == `+`(`*`(a, b), c) ``` This did not match the preceding call which directly used literals `3`, `4`, `6`. Updated the example to: ```nim assert `*+`(3, 4, 6) == `+`(`*`(3, 4), 6) ``` This change makes the example consistent with the function call and immediately understandable to readers without requiring prior variable definitions. ## Rationale * Improves clarity by avoiding undefined variables in a code snippet. * Matches the example usage in the preceding line. * Helps beginners understand the operator's behavior without additional context. ## Changes * **Edited**: `doc/manual.md` line 4065 — replaced variables `a`, `b`, `c` with literals `3`, `4`, `6`. ## Issue Closes #25084 --- doc/manual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.md b/doc/manual.md index 9abd0e762c..29006a7536 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -4062,7 +4062,7 @@ notation. (Thus an operator can have more than two parameters): # Multiply and add result = a * b + c - assert `*+`(3, 4, 6) == `+`(`*`(a, b), c) + assert `*+`(3, 4, 6) == `+`(`*`(3, 4), 6) ``` From b527db9ddd33fd16a8afd8467344fec81a54c84d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 21 Aug 2025 19:31:55 +0800 Subject: [PATCH 05/21] fixes #25109; fixes #25111 transform `addr(conv(x))` -> `conv(addr(x))` (#25112) follows up https://github.com/nim-lang/Nim/pull/24818 relates to https://github.com/nim-lang/Nim/issues/23923 fixes #25109 fixes #25111 transform `addr ( conv ( x ) )` -> `conv ( addr ( x ) )` so that it is the original value that is being modified ```c T1_ = ((unsigned long long*) ((&a_1))); r(T1_); ``` --- compiler/ccgexprs.nim | 6 +++++- tests/ccgbugs/taddrconvs.nim | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 4ca34b9d74..d3e215ea56 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -981,7 +981,11 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) = var a: TLoc = initLocExpr(p, e[0]) if e[0].kind in {nkHiddenStdConv, nkHiddenSubConv, nkConv} and not ignoreConv(e[0]): # addr (conv x) introduces a temp because `conv x` is not a rvalue - putIntoDest(p, d, e, addrLoc(p.config, expressionsNeedsTmp(p, a)), a.storage) + # transform addr ( conv ( x ) ) -> conv ( addr ( x ) ) + var exprLoc: TLoc = initLocExpr(p, e[0][1]) + var tmp = getTemp(p, e.typ, needsInit=false) + putIntoDest(p, tmp, e, cCast(getTypeDesc(p.module, e.typ), addrLoc(p.config, exprLoc))) + putIntoDest(p, d, e, rdLoc(tmp)) else: putIntoDest(p, d, e, addrLoc(p.config, a), a.storage) diff --git a/tests/ccgbugs/taddrconvs.nim b/tests/ccgbugs/taddrconvs.nim index 6990648c4a..759b1c1e0f 100644 --- a/tests/ccgbugs/taddrconvs.nim +++ b/tests/ccgbugs/taddrconvs.nim @@ -25,3 +25,23 @@ block: var m = uint64(12) foo(culonglong(m)) main() + +block: # bug #25109 + type T = culonglong + proc r(c: var T) = c = 1 + proc h(a: var culonglong) = r(T(a)) + var a: culonglong + h(a) + doAssert a == 1 + +block: # bug #25111 + type T = culonglong + proc r(c: var T) = c = 1 + + proc foo = + var a: uint64 + r(T(a)) + doAssert a == 1 + + foo() + From e2a294504e39c50483caf4552803f113dd5da23d Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:14:46 +0800 Subject: [PATCH 06/21] fixes #25066; forbids comparing pointers at compile time (#25103) fixes #25066 Probably it is not worth implementing comparing pointers at compile time. For a starter, we can improve the error message instead of letting it crash --- compiler/vmgen.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index e365d3f236..ae60851c5f 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1182,8 +1182,10 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMag of mEqF64: genBinaryABC(c, n, dest, opcEqFloat) of mLeF64: genBinaryABC(c, n, dest, opcLeFloat) of mLtF64: genBinaryABC(c, n, dest, opcLtFloat) - of mLePtr, mLeU: genBinaryABC(c, n, dest, opcLeu) - of mLtPtr, mLtU: genBinaryABC(c, n, dest, opcLtu) + of mLeU: genBinaryABC(c, n, dest, opcLeu) + of mLtU: genBinaryABC(c, n, dest, opcLtu) + of mLePtr, mLtPtr: + globalError(c.config, n.info, "pointer comparisons are not available at compile-time") of mEqProc, mEqRef: genBinaryABC(c, n, dest, opcEqRef) of mXor: genBinaryABC(c, n, dest, opcXor) From d472022a7701d4c3c807980cf805606f2cb26277 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 27 Aug 2025 12:23:04 +0200 Subject: [PATCH 07/21] fixes #25114 (#25124) --- compiler/ast.nim | 5 +++-- compiler/treetab.nim | 17 +++++++++++------ compiler/vmdef.nim | 4 +++- compiler/vmgen.nim | 22 ++++++++++++++-------- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index d1d2d127a0..d80589c087 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -819,6 +819,7 @@ type # nodes are compared by structure! counter*: int data*: TNodePairSeq + ignoreTypes*: bool TObjectSeq* = seq[RootRef] TObjectSet* = object @@ -1641,8 +1642,8 @@ proc initObjectSet*(): TObjectSet = result = TObjectSet(counter: 0) newSeq(result.data, StartSize) -proc initNodeTable*(): TNodeTable = - result = TNodeTable(counter: 0) +proc initNodeTable*(ignoreTypes=false): TNodeTable = + result = TNodeTable(counter: 0, ignoreTypes: ignoreTypes) newSeq(result.data, StartSize) proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType = diff --git a/compiler/treetab.nim b/compiler/treetab.nim index 6685c4a899..1fd539f0f2 100644 --- a/compiler/treetab.nim +++ b/compiler/treetab.nim @@ -42,32 +42,37 @@ proc hashTree*(n: PNode): Hash = #echo "hashTree ", result #echo n -proc treesEquivalent(a, b: PNode): bool = +proc treesEquivalent(a, b: PNode; ignoreTypes: bool): bool = if a == b: result = true elif (a != nil) and (b != nil) and (a.kind == b.kind): case a.kind - of nkEmpty, nkNilLit, nkType: result = true + of nkEmpty: result = true of nkSym: result = a.sym.id == b.sym.id of nkIdent: result = a.ident.id == b.ident.id of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal - of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal + of nkFloatLit..nkFloat64Lit: + result = cast[uint64](a.floatVal) == cast[uint64](b.floatVal) + #result = a.floatVal == b.floatVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal + of nkType, nkNilLit: + result = a.typ == b.typ else: if a.len == b.len: for i in 0..= 0: @@ -1549,8 +1556,7 @@ template cannotEval(c: PCtx; n: PNode) = if c.config.cmd == cmdCheck and c.config.m.errorOutputs != {}: # nim check command with no error outputs doesn't need to cascade here, # includes `tryConstExpr` case which should not continue generating code - localError(c.config, n.info, "cannot evaluate at compile time: " & - n.renderTree) + localError(c.config, n.info, "cannot evaluate at compile time: " & n.renderTree) c.cannotEval = true return globalError(c.config, n.info, "cannot evaluate at compile time: " & @@ -1888,7 +1894,7 @@ proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = c.freeTemp(objR) proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) = - if n[0].typ == nil: + if n[0].typ == nil: globalError(c.config, n.info, "cannot access array with nil type") return From 0a8f618e2b4ee687a1dfeb08ed0e04bebe006eaf Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 29 Aug 2025 03:51:45 +0800 Subject: [PATCH 08/21] fixes #25121; [FieldDefect] with iterator-loop (#25130) fixes #25121 --- compiler/transf.nim | 3 ++- tests/iter/titer_issues.nim | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index 0ed2e10e82..c6f0dbb332 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -259,7 +259,8 @@ proc transformBlock(c: PTransf, n: PNode): PNode = var labl: PSym if c.inlining > 0: labl = newLabel(c, n[0]) - c.transCon.mapping[n[0].sym.itemId] = newSymNode(labl) + if n[0].kind != nkEmpty: + c.transCon.mapping[n[0].sym.itemId] = newSymNode(labl) else: labl = if n[0].kind != nkEmpty: diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim index 2452102bd3..efea76c02e 100644 --- a/tests/iter/titer_issues.nim +++ b/tests/iter/titer_issues.nim @@ -412,3 +412,15 @@ block: # bug #24033 collections.add (id, str, $num) doAssert collections[1] == (1, "foo", "3.14") + + +block: # bug #25121 + iterator k(): int = + when nimvm: + yield 0 + else: + yield 0 + + for _ in k(): + (proc() = (; let _ = block: 0))() + From 065c4b443bcbeee02c6c6bb18cb1cc651e3fcf2b Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Fri, 29 Aug 2025 04:56:46 +0900 Subject: [PATCH 09/21] fixes #25125 (#25126) `strutils.formatSize` returns correct strings from large values close to `int64.high`. Round down `bytes` when it is converted to float. --- lib/pure/strutils.nim | 43 +++++++++++++------------- tests/stdlib/tstrutils.nim | 63 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 24 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index c218ac1c53..1a5d4d5d6f 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -74,6 +74,7 @@ import std/parseutils from std/math import pow, floor, log10 from std/algorithm import fill, reverse import std/enumutils +from std/bitops import fastLog2 from std/unicode import toLower, toUpper export toLower, toUpper @@ -2639,37 +2640,35 @@ func formatSize*(bytes: int64, ## * `strformat module`_ for string interpolation and formatting runnableExamples: doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" - doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" + doAssert formatSize((2.234*1024*1024).int) == "2.233MiB" doAssert formatSize(4096, includeSpace = true) == "4 KiB" doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB" doAssert formatSize(4096) == "4KiB" - doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,13MB" + doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,129MB" - const iecPrefixes = ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"] - const collPrefixes = ["", "k", "M", "G", "T", "P", "E", "Z", "Y"] - var - xb: int64 = bytes - fbytes: float - lastXb: int64 = bytes - matchedIndex = 0 - prefixes: array[9, string] + # It doesn't needs Zi and larger units until we use int72 or larger ints. + const iecPrefixes = ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei"] + const collPrefixes = ["", "k", "M", "G", "T", "P", "E"] + + let lg2 = if bytes == 0: + 0 + else: + when hasWorkingInt64: + fastLog2(bytes) + else: + fastLog2(int32 bytes) + let matchedIndex = lg2 div 10 + # Lower bits that are smaller than 0.001 when `bytes` is converted to a real number and added prefix, are discard. + # Then it is converted to float with round down. + let discardBits = (lg2 div 10 - 1) * 10 + + var prefixes: array[7, string] if prefix == bpColloquial: prefixes = collPrefixes else: prefixes = iecPrefixes - # Iterate through prefixes seeing if value will be greater than - # 0 in each case - for index in 1.. Date: Tue, 2 Sep 2025 01:29:58 +0900 Subject: [PATCH 10/21] fixes overflow defect when compiled with js backend (#25132) Follow up to https://github.com/nim-lang/Nim/pull/25126. This fixes overflow defect when `tests/stdlib/tstrutils.nim` was compiled with js backend. --- tests/stdlib/tstrutils.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index a21a337bd5..dfa72faf22 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -789,8 +789,8 @@ bar block: # formatSize disableVm: when hasWorkingInt64: - doAssert formatSize(1024 * 1024 * 1024 * 2 - 1) == "1.999GiB" - doAssert formatSize(1024 * 1024 * 1024 * 2) == "2GiB" + doAssert formatSize(1024'i64 * 1024 * 1024 * 2 - 1) == "1.999GiB" + doAssert formatSize(1024'i64 * 1024 * 1024 * 2) == "2GiB" doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231 doAssert formatSize(int64.high) == "7.999EiB" doAssert formatSize(int64.high div 2 + 1) == "4EiB" From 8ea8755cc0252eb52a3f1d68d1c91f8f5f7d449f Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Thu, 4 Sep 2025 13:46:50 +0900 Subject: [PATCH 11/21] fixes tnewruntime_strutils.nim not to raise AssertionDefect (#25142) Follow up to https://github.com/nim-lang/Nim/pull/25126 It changed `formatSize` outputs from some inputs, so some of existing test code related to it need to be updated. Sorry, I didn't know `tests/destructor/tnewruntime_strutils.nim` has tests calls `formatSize`. --- tests/destructor/tnewruntime_strutils.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim index 7e4074218f..e73e9b2445 100644 --- a/tests/destructor/tnewruntime_strutils.nim +++ b/tests/destructor/tnewruntime_strutils.nim @@ -53,11 +53,11 @@ proc nonStaticTests = block: # formatSize tests when not defined(js): doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231 - doAssert formatSize((2.234*1024*1024).int) == "2.234MiB" + doAssert formatSize((2.234*1024*1024).int) == "2.233MiB" doAssert formatSize(4096) == "4KiB" doAssert formatSize(4096, prefix=bpColloquial, includeSpace=true) == "4 kB" doAssert formatSize(4096, includeSpace=true) == "4 KiB" - doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,13MB" + doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,129MB" block: # formatEng tests doAssert formatEng(0, 2, trim=false) == "0.00" From 08d74a1c272c25cbc7a0b5c2a9288a06cc23f619 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 9 Sep 2025 22:16:12 +0800 Subject: [PATCH 12/21] fixes #24093; Dereferencing result of cast in single expression triggers unnecessary copy (#25143) fixes #24093 transforms ```nim let a = new array[1000, byte] block: for _ in cast[typeof(a)](a)[]: discard ``` into ```nim let a = new array[1000, byte] block: let temp = cast[typeof(a)](a) for _ in temp[]: discard ``` So it keeps the same behavior with the manual version --- compiler/transf.nim | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index c6f0dbb332..197e073477 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -828,12 +828,20 @@ proc transformFor(c: PTransf, n: PNode): PNode = t = formal.ast.typ # better use the type that actually has a destructor. elif t.destructor == nil and arg.typ.destructor != nil: t = arg.typ - # generate a temporary and produce an assignment statement: - var temp = newTemp(c, t, formal.info) - #incl(temp.sym.flags, sfCursor) - addVar(v, temp) - stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg, true)) - newC.mapping[formal.itemId] = temp + + if arg.kind in {nkDerefExpr, nkHiddenDeref}: + # optimizes for `[]` # bug #24093 + var temp = newTemp(c, arg[0].typ, formal.info) + addVar(v, temp) + stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg[0], true)) + newC.mapping[formal.itemId] = newDeref(temp) + else: + # generate a temporary and produce an assignment statement: + var temp = newTemp(c, t, formal.info) + #incl(temp.sym.flags, sfCursor) + addVar(v, temp) + stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg, true)) + newC.mapping[formal.itemId] = temp of paVarAsgn: assert(skipTypes(formal.typ, abstractInst).kind in {tyVar, tyLent}) newC.mapping[formal.itemId] = arg From 34bb37ddda6d36cc243fe8a5354d3087a8309d4b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 9 Sep 2025 22:17:22 +0800 Subject: [PATCH 13/21] fixes #25120; don't generate hooks for `NimNode` (#25144) fixes #25120 --- compiler/semtypes.nim | 4 +++- tests/errmsgs/t25120.nim | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/errmsgs/t25120.nim diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 42efcd2399..9d660a3bec 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1147,7 +1147,9 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = let t = newTypeS(tySink, c, result) result = t else: discard - if result.kind == tyRef and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}: + if result.kind == tyRef and + c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and + tfTriggersCompileTime notin result.flags: result.flags.incl tfHasAsgn proc findEnforcedStaticType(t: PType): PType = diff --git a/tests/errmsgs/t25120.nim b/tests/errmsgs/t25120.nim new file mode 100644 index 0000000000..217bba1fa7 --- /dev/null +++ b/tests/errmsgs/t25120.nim @@ -0,0 +1,6 @@ +discard """ + errormsg: "request to generate code for .compileTime proc: riesig" +""" + +proc riesig(): NimNode = discard +discard riesig() From c8456eacd509b94e4ca4d5a32ca54179aa8a9d4b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Tue, 9 Sep 2025 22:22:05 +0800 Subject: [PATCH 14/21] fixes #25117; `requiresInit` not checked for result if it has been used (#25151) fixes #25117 errors on `requiresInit` of `result` if it is used before initialization. Otherwise ```nim # prevent superfluous warnings about the same variable: a.init.add s.id ``` It produces a warning, and this line prevents it from being recognized by the `requiresInit` check in `trackProc` --- compiler/sempass2.nim | 4 +++- koch.nim | 2 +- tests/errmsgs/t25117.nim | 13 +++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/errmsgs/t25117.nim diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 65d216b831..7707d1a248 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -379,7 +379,9 @@ proc useVar(a: PEffects, n: PNode) = # If the variable is explicitly marked as .noinit. do not emit any error a.init.add s.id elif s.id notin a.init: - if s.typ.requiresInit: + if s.kind == skResult and tfRequiresInit in s.typ.flags: + localError(a.config, n.info, "'result' requires explicit initialization") + elif s.typ.requiresInit: message(a.config, n.info, warnProveInit, s.name.s) elif a.leftPartOfAsgn <= 0: if strictDefs in a.c.features: diff --git a/koch.nim b/koch.nim index dbca93a0d4..48cd2cdcb2 100644 --- a/koch.nim +++ b/koch.nim @@ -13,7 +13,7 @@ const # examples of possible values for repos: Head, ea82b54 NimbleStableCommit = "9207e8b2bbdf66b5a4d1020214cff44d2d30df92" # 0.20.1 AtlasStableCommit = "26cecf4d0cc038d5422fc1aa737eec9c8803a82b" # 0.9 - ChecksumsStableCommit = "f8f6bd34bfa3fe12c64b919059ad856a96efcba0" # 2.0.1 + ChecksumsStableCommit = "0b8e46379c5bc1bf73d8b3011908389c60fb9b98" # 2.0.1 SatStableCommit = "faf1617f44d7632ee9601ebc13887644925dcc01" NimonyStableCommit = "1dbabac403ae32e185ee4c29f006d04e04b50c6d" # unversioned \ diff --git a/tests/errmsgs/t25117.nim b/tests/errmsgs/t25117.nim new file mode 100644 index 0000000000..1f63e65b49 --- /dev/null +++ b/tests/errmsgs/t25117.nim @@ -0,0 +1,13 @@ +discard """ + errormsg: "'result' requires explicit initialization" +""" + +type RI {.requiresInit.} = object + v: int + +proc xxx(v: var RI) = discard + +proc f(T: type): T = + xxx(result) # Should fail + +discard f(RI) \ No newline at end of file From 5ba279276ea98e59e36faa6cbf71c10e12b43124 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 9 Sep 2025 20:05:12 +0200 Subject: [PATCH 15/21] sequtils: `findIt` (#25134) Complements `anyIt`, `find`, etc, plugging an odd gap in the `xxxIt` family of functions --- lib/pure/collections/sequtils.nim | 62 ++++++++++++++++++++----------- tests/stdlib/tsequtils.nim | 11 ++++++ 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 42d54c8392..202f5a3b1c 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -116,6 +116,11 @@ macro evalOnceAs(expAlias, exp: untyped, newProc(name = genSym(nskTemplate, $expAlias), params = [getType(untyped)], body = val, procType = nnkTemplateDef)) +template unCheckedInc(x) = + {.push overflowChecks: off.} + inc(x) + {.pop.} + func concat*[T](seqs: varargs[seq[T]]): seq[T] = ## Takes several sequences' items and returns them inside a new sequence. ## All sequences must be of the same type. @@ -139,7 +144,7 @@ func concat*[T](seqs: varargs[seq[T]]): seq[T] = for s in items(seqs): for itm in items(s): result[i] = itm - inc(i) + unCheckedInc(i) func addUnique*[T](s: var seq[T], x: sink T) = ## Adds `x` to the container `s` if it is not already present. @@ -170,7 +175,7 @@ func count*[T](s: openArray[T], x: T): int = result = 0 for itm in items(s): if itm == x: - inc result + unCheckedInc result func cycle*[T](s: openArray[T], n: Natural): seq[T] = ## Returns a new sequence with the items of the container `s` repeated @@ -188,7 +193,7 @@ func cycle*[T](s: openArray[T], n: Natural): seq[T] = for x in 0 ..< n: for e in s: result[o] = e - inc o + unCheckedInc o proc repeat*[T](x: T, n: Natural): seq[T] = ## Returns a new sequence with the item `x` repeated `n` times. @@ -321,6 +326,26 @@ func minmax*[T](x: openArray[T], cmp: proc(a, b: T): int): (T, T) {.effectsOf: c elif cmp(result[1], x[i]) < 0: result[1] = x[i] +template findIt*(s, predicate: untyped): int = + ## Iterates through a container and returns the index of the first item that + ## fulfills the predicate, or -1 + ## + ## Unlike the `find`, the predicate needs to be an expression using + ## the `it` variable for testing, like: `findIt([3, 2, 1], it == 2)`. + var + res = -1 + i = 0 + + # We must use items here since both `find` and `anyIt` are defined in terms + # of `items` + # (and not `pairs`) + for it {.inject.} in items(s): + if predicate: + res = i + break + unCheckedInc(i) + res + template zipImpl(s1, s2, retType: untyped): untyped = proc zip*[S, T](s1: openArray[S], s2: openArray[T]): retType = ## Returns a new sequence with a combination of the two input containers. @@ -417,7 +442,7 @@ func distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = if extra == 0 or spread == false: # Use an algorithm which overcounts the stride and minimizes reading limits. - if extra > 0: inc(stride) + if extra > 0: unCheckedInc(stride) for i in 0 ..< num: result[i] = newSeq[T]() for g in first ..< min(s.len, first + stride): @@ -429,7 +454,7 @@ func distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = last = first + stride if extra > 0: extra -= 1 - inc(last) + unCheckedInc(last) result[i] = newSeq[T]() for g in first ..< last: result[i].add(s[g]) @@ -586,7 +611,7 @@ proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.}) s[pos] = move(s[i]) else: shallowCopy(s[pos], s[i]) - inc(pos) + unCheckedInc(pos) setLen(s, pos) func delete*[T](s: var seq[T]; slice: Slice[int]) = @@ -617,8 +642,8 @@ func delete*[T](s: var seq[T]; slice: Slice[int]) = s[i] = move(s[j]) else: s[i].shallowCopy(s[j]) - inc(i) - inc(j) + unCheckedInc(i) + unCheckedInc(j) setLen(s, newLen) when nimvm: defaultImpl() else: @@ -649,8 +674,8 @@ func delete*[T](s: var seq[T]; first, last: Natural) {.deprecated: "use `delete( s[i] = move(s[j]) else: s[i].shallowCopy(s[j]) - inc(i) - inc(j) + unCheckedInc(i) + unCheckedInc(j) setLen(s, newLen) func insert*[T](dest: var seq[T], src: openArray[T], pos = 0) = @@ -681,10 +706,10 @@ func insert*[T](dest: var seq[T], src: openArray[T], pos = 0) = dec(i) dec(j) # Insert items from `dest` into `dest` at `pos` - inc(j) + unCheckedInc(j) for item in src: dest[j] = item - inc(j) + unCheckedInc(j) template filterIt*(s, pred: untyped): untyped = @@ -743,7 +768,7 @@ template keepItIf*(varSeq: seq, pred: untyped) = varSeq[pos] = move(varSeq[i]) else: shallowCopy(varSeq[pos], varSeq[i]) - inc(pos) + unCheckedInc(pos) setLen(varSeq, pos) since (1, 1): @@ -842,12 +867,7 @@ template anyIt*(s, pred: untyped): bool = assert numbers.anyIt(it > 8) == true assert numbers.anyIt(it > 9) == false - var result = false - for it {.inject.} in items(s): - if pred: - result = true - break - result + findIt(s, pred) != -1 template toSeq1(s: not iterator): untyped = # overload for typed but not iterator @@ -875,7 +895,7 @@ template toSeq2(iter: iterator): untyped = var result = newSeq[typeof(iter2)](iter2.len) for x in iter2: result[i] = x - inc i + unCheckedInc i result else: type OutType = typeof(iter2()) @@ -920,7 +940,7 @@ template toSeq*(iter: untyped): untyped = var i = 0 for x in iter2: result[i] = x - inc i + unCheckedInc i result else: var result: seq[typeof(iter)] = @[] diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim index df0fb1610a..027f9b1195 100644 --- a/tests/stdlib/tsequtils.nim +++ b/tests/stdlib/tsequtils.nim @@ -258,6 +258,17 @@ block: # any doAssert any(anumbers, proc (x: int): bool = return x > 8) == true doAssert any(anumbers, proc (x: int): bool = return x > 9) == false +block: # findIt + let + numbers = @[1, 4, 5, 8, 9, 7, 4] + anumbers = [1, 4, 5, 8, 9, 7, 4] + len0seq: seq[int] = @[] + doAssert findIt(numbers, it == 4) == 1 + doAssert findIt(numbers, it > 9) == -1 + doAssert findIt(len0seq, true) == -1 + doAssert findIt(anumbers, it > 8) == 4 + doAssert findIt(anumbers, it > 9) == -1 + block: # anyIt let numbers = @[1, 4, 5, 8, 9, 7, 4] From 76d07e8caa008c9f3bfd96f1aa3d86a7d0176b08 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Wed, 10 Sep 2025 21:36:39 +0800 Subject: [PATCH 16/21] fixes #25078; filterIt wrongly results in rvalue (#25139) fixes #25078 --- lib/pure/collections/sequtils.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 202f5a3b1c..3dba087aa8 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -740,7 +740,7 @@ template filterIt*(s, pred: untyped): untyped = var result = newSeq[typeof(s[0])]() for it {.inject.} in items(s): if pred: result.add(it) - result + move result template keepItIf*(varSeq: seq, pred: untyped) = ## Keeps the items in the passed sequence (must be declared as a `var`) From 4f09675d8a9b039943fe5214a8c02094ac5f36a9 Mon Sep 17 00:00:00 2001 From: Judd <4046440+foldl@users.noreply.github.com> Date: Wed, 10 Sep 2025 21:37:09 +0800 Subject: [PATCH 17/21] Update asyncfile.nim: support write to > 2GB file on Windows (#25105) `DWORD` is defined as `int32`, so `DWORD(...)` would not work as expected. When writing to files larger than 2GB, exception occurs: ``` unhandled exception: value out of range: 4294967295 notin -2147483648 .. 2147483647 [RangeDefect] ``` This PR is a quick fix for this. P.S. Why `DWORD` is defined as `int32`? --- lib/pure/asyncfile.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim index 3825904781..3a57845c22 100644 --- a/lib/pure/asyncfile.nim +++ b/lib/pure/asyncfile.nim @@ -428,7 +428,7 @@ proc write*(f: AsyncFile, data: string): Future[void] = dealloc buffer buffer = nil ) - ol.offset = DWORD(f.offset and 0xffffffff) + ol.offset = cast[DWORD](f.offset and 0xffffffff) ol.offsetHigh = DWORD(f.offset shr 32) f.offset.inc(data.len) From 49e66e80f0656f5056c606d0f627b4163bdb22a1 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 10 Sep 2025 16:37:55 +0300 Subject: [PATCH 18/21] Optimize @, fixes #25063 (#25064) Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> --- lib/system.nim | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index a18e81d3d7..fbbc2a3398 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1465,6 +1465,8 @@ proc isNil*[T: proc | iterator {.closure.}](x: T): bool {.noSideEffect, magic: " ## Fast check whether `x` is nil. This is sometimes more efficient than ## `== nil`. +proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait".} + when defined(nimHasTopDownInference): # magic used for seq type inference proc `@`*[T](a: openArray[T]): seq[T] {.magic: "OpenArrayToSeq".} = @@ -1472,8 +1474,17 @@ when defined(nimHasTopDownInference): ## ## This is not as efficient as turning a fixed length array into a sequence ## as it always copies every element of `a`. - newSeq(result, a.len) - for i in 0..a.len-1: result[i] = a[i] + let sz = a.len + when supportsCopyMem(T) and not defined(js): + result = newSeqUninit[T](sz) + when nimvm: + for i in 0..sz-1: result[i] = a[i] + else: + if sz != 0: + copyMem(addr result[0], addr a[0], sizeof(T) * sz) + else: + newSeq(result, sz) + for i in 0..sz-1: result[i] = a[i] else: proc `@`*[T](a: openArray[T]): seq[T] = ## Turns an *openArray* into a sequence. @@ -1644,8 +1655,6 @@ when not defined(js) and defined(nimV2): vTable: UncheckedArray[pointer] # vtable for types PNimTypeV2 = ptr TNimTypeV2 -proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait".} - when notJSnotNims and defined(nimSeqsV2): include "system/strs_v2" include "system/seqs_v2" From af6be4f839fc9ff08559320be2deeea47202e859 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 10 Sep 2025 15:38:25 +0200 Subject: [PATCH 19/21] GDB script: minor improvements (#24965) --- tools/debug/nim-gdb.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tools/debug/nim-gdb.py b/tools/debug/nim-gdb.py index 59e6ee99ce..2637481aee 100644 --- a/tools/debug/nim-gdb.py +++ b/tools/debug/nim-gdb.py @@ -4,6 +4,18 @@ import re import sys import traceback +# Add compatibility for older GDB versions +if not hasattr(gdb, 'SYMBOL_FUNCTION_DOMAIN'): + gdb.SYMBOL_FUNCTION_DOMAIN = 0 # This is the value used in newer GDB versions + +# Configure demangling for Itanium C++ ABI (which Nim uses) +try: + gdb.execute("set demangle-style gnu-v3") # GNU v3 style handles Itanium mangling + gdb.execute("set print asm-demangle on") + gdb.execute("set print demangle on") +except Exception as e: + gdb.write(f"Warning: Could not configure demangling: {str(e)}\n", gdb.STDERR) + # some feedback that the nim runtime support is loading, isn't a bad # thing at all. gdb.write("Loading Nim Runtime support.\n", gdb.STDERR) @@ -70,12 +82,12 @@ class NimTypeRecognizer: type_map_static = { 'NI': 'system.int', 'NI8': 'int8', 'NI16': 'int16', 'NI32': 'int32', 'NI64': 'int64', - + 'NU': 'uint', 'NU8': 'uint8','NU16': 'uint16', 'NU32': 'uint32', 'NU64': 'uint64', - + 'NF': 'float', 'NF32': 'float32', 'NF64': 'float64', - + 'NIM_BOOL': 'bool', 'NIM_CHAR': 'char', 'NCSTRING': 'cstring', 'NimStringDesc': 'string', 'NimStringV2': 'string' @@ -556,7 +568,7 @@ class NimSeqPrinter: except RuntimeError: inaccessible = True yield "data[{0}]".format(i), "inaccessible" - + ################################################################################ class NimArrayPrinter: From f90951cc61190beb58c3049a43efb1862447b711 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 11 Sep 2025 14:47:02 +0800 Subject: [PATCH 20/21] move `std/parsesql` to nimble packages (#25156) pending https://github.com/nim-lang/packages/pull/3117 ref https://github.com/nim-lang/parsesql --- changelog.md | 2 ++ lib/pure/parsesql.nim | 2 ++ 2 files changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index 76da277edb..cf2d4cb170 100644 --- a/changelog.md +++ b/changelog.md @@ -23,6 +23,8 @@ errors. - With `-d:nimPreviewCStringComparisons`, comparsions (`<`, `>`, `<=`, `>=`) between cstrings switch from reference semantics to value semantics like `==` and `!=`. +- `std/parsesql` has been moved to a nimble package, use `nimble` or `atlas` to install it. + ## Standard library additions and changes [//]: # "Additions:" diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index 7bc6fcdcee..c02b6dddc6 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -12,6 +12,8 @@ ## ## Unstable API. +{.deprecated: "use `nimble install parsesql` and import `pkg/parsesql` instead".} + import std/[strutils, lexbase] import std/private/decode_helpers From d73f478bdcbf774622c24c1a4ef58cc56beacb49 Mon Sep 17 00:00:00 2001 From: bptato <60043228+bptato@users.noreply.github.com> Date: Thu, 11 Sep 2025 09:22:47 +0200 Subject: [PATCH 21/21] Allow assignment of nested non-closure procs to globals (#25154) For memory-safety, this only seems problematic in case of closures, so I just special cased that. Fixes #25131 --- compiler/semstmts.nim | 2 +- tests/global/tglobalclosure.nim | 14 ++++++++++++++ tests/global/tglobalclosure2.nim | 17 +++++++++++++++++ tests/global/tglobalproc.nim | 17 +++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 tests/global/tglobalclosure.nim create mode 100644 tests/global/tglobalclosure2.nim create mode 100644 tests/global/tglobalproc.nim diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index ce8b59f9cd..6c8542b584 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -725,7 +725,7 @@ template isLocalSym(sym: PSym): bool = sym.typ.kind == tyTypeDesc or sfCompileTime in sym.flags) or sym.kind in {skProc, skFunc, skIterator} and - sfGlobal notin sym.flags + sfGlobal notin sym.flags and sym.typ.callConv == ccClosure proc usesLocalVar(n: PNode): bool = case n.kind diff --git a/tests/global/tglobalclosure.nim b/tests/global/tglobalclosure.nim new file mode 100644 index 0000000000..81cdba37da --- /dev/null +++ b/tests/global/tglobalclosure.nim @@ -0,0 +1,14 @@ +discard """ + errormsg: "cannot assign local to global variable" + line: 11 +""" + +proc main() = + var x = "hi" + proc p() = + echo x + + let a {.global.} = p + p() + +main() diff --git a/tests/global/tglobalclosure2.nim b/tests/global/tglobalclosure2.nim new file mode 100644 index 0000000000..bd6b9bfd61 --- /dev/null +++ b/tests/global/tglobalclosure2.nim @@ -0,0 +1,17 @@ +discard """ + errormsg: "cannot assign local to global variable" + line: 14 +""" + +type X = object + p: proc() {.closure.} + +proc main() = + var x = "hi" + proc p() = + echo x + + let a {.global.} = X(p: p) + a.p() + +main() diff --git a/tests/global/tglobalproc.nim b/tests/global/tglobalproc.nim new file mode 100644 index 0000000000..ba6f5a7999 --- /dev/null +++ b/tests/global/tglobalproc.nim @@ -0,0 +1,17 @@ +discard """ +output: "hi\nhi" +""" + +type X = object + p: proc() {.nimcall.} + +proc main() = + proc p() = + echo "hi" + + let a {.global.} = p + let b {.global.} = X(p: p) + a() + b.p() + +main()