From 917cdb52363aa9c22c2ac85cb5891f5d38fb4d5d Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 2 Jul 2026 21:26:52 +0200 Subject: [PATCH] fixes regressions --- compiler/astdef.nim | 8 +++++++- compiler/ic/enum2nif.nim | 2 ++ compiler/options.nim | 2 +- compiler/types.nim | 17 ++++++++++------- compiler/vmgen.nim | 4 ++++ tests/vm/tsetlen.nim | 14 ++++++++++++++ 6 files changed, 38 insertions(+), 9 deletions(-) diff --git a/compiler/astdef.nim b/compiler/astdef.nim index bd593577a7..d2af6a9064 100644 --- a/compiler/astdef.nim +++ b/compiler/astdef.nim @@ -342,6 +342,11 @@ type nfLazyBody # IC: this node is a placeholder for a routine body (bodyPos son) # not yet materialized. Reading its children (via `len`/`safeLen`) # triggers `forceLazyBodyHook`. Process-local, stripped on serialize. + nfBroadcast # this `nkBracket` is a *broadcast* default array: a single son + # standing for `lengthOrd` identical zero copies (see + # `broadcastArrayThreshold`). The flag disambiguates it from an + # ordinary 1-element collection (e.g. a seq value that happens to + # carry an array type), so it must survive copies + serialization. TNodeFlags* = set[TNodeFlag] TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47) @@ -869,7 +874,8 @@ const nfFromTemplate, nfDefaultRefsParam, nfExecuteOnReload, nfLastRead, nfFirstWrite, nfSkipFieldChecking, - nfDisabledOpenSym, nfLazyType} + nfDisabledOpenSym, nfLazyType, + nfBroadcast} namePos* = 0 patternPos* = 1 # empty except for term rewriting macros genericParamsPos* = 2 diff --git a/compiler/ic/enum2nif.nim b/compiler/ic/enum2nif.nim index 6b0a809026..b28a4ae4d5 100644 --- a/compiler/ic/enum2nif.nim +++ b/compiler/ic/enum2nif.nim @@ -1474,6 +1474,7 @@ proc genFlags*(s: set[TNodeFlag]; dest: var string) = of nfDisabledOpenSym: dest.add "d3" of nfLazyType: dest.add "l1" of nfLazyBody: discard # process-local placeholder; never serialized + of nfBroadcast: dest.add "v" proc parse*(t: typedesc[TNodeFlag]; s: string): set[TNodeFlag] = @@ -1534,6 +1535,7 @@ proc parse*(t: typedesc[TNodeFlag]; s: string): set[TNodeFlag] = inc i else: result.incl nfSem of 't': result.incl nfTransf + of 'v': result.incl nfBroadcast of 'w': result.incl nfFirstWrite else: discard inc i diff --git a/compiler/options.nim b/compiler/options.nim index a4fadcb471..d16c42904d 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -29,7 +29,7 @@ const nimEnableCovariance* = defined(nimEnableCovariance) - icFormatVersion* = "28" + icFormatVersion* = "29" ## Version of the IC cache format (the sem-NIF module layout written by ## ast2nif.nim plus the iface/impl/edges side files). Bump it whenever ## that layout changes: `commandIc` wipes a nimcache whose `ic.version` diff --git a/compiler/types.nim b/compiler/types.nim index b8e889a3cb..b6da7d4c12 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -641,22 +641,25 @@ const broadcastArrayThreshold* = 32 ## (`.s.bif`/`.t.bif`), in the VM, and in the generated C (`{0}` zero-fills). proc isDefaultBroadcastArray*(n: PNode; conf: ConfigRef): bool = - ## True iff `n` is a broadcast default array: one son that stands for - ## `lengthOrd` identical copies. A normal post-sem array literal always has - ## exactly `lengthOrd` sons, so `len == 1 < lengthOrd` is an unambiguous marker. - result = n != nil and n.kind == nkBracket and n.len == 1 and n.typ != nil and - n.typ.skipTypes(abstractInst).kind == tyArray and - lengthOrd(conf, n.typ.skipTypes(abstractInst)) > One + ## True iff `n` is a broadcast default array: a single son standing for + ## `lengthOrd` identical zero copies. Identified by the explicit `nfBroadcast` + ## marker (set by `getNullValue`), NOT by `len == 1 < lengthOrd` — the latter + ## also matches an ordinary 1-element collection that happens to be an + ## `nkBracket` carrying an array type, e.g. a `@[a, b, c]` seq value shrunk to + ## length 1 by `setLen`/`delete` (its VM node keeps the array-literal type). + result = n != nil and n.kind == nkBracket and nfBroadcast in n.flags proc expandBroadcastArray*(n: PNode; conf: ConfigRef) = ## Materialise a broadcast default array (see `isDefaultBroadcastArray`) into a ## full `lengthOrd`-son `nkBracket`, each son a copy of the single default ## element. Used by VM ops that index-address, mutate, or measure such a node; - ## the common read-only paths leave it compact. + ## the common read-only paths leave it compact. Clears `nfBroadcast` since the + ## node is now a fully materialised literal. if isDefaultBroadcastArray(n, conf): let total = toInt(lengthOrd(conf, n.typ.skipTypes(abstractInst))) let elem = n[0] for i in 1 ..< total: n.add copyTree(elem) + n.flags.excl nfBroadcast # -------------- type equality ----------------------------------------------- diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 118ea07ede..a560665b68 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -2039,6 +2039,10 @@ proc getNullValue(c: PCtx; typ: PType, info: TLineInfo; conf: ConfigRef): PNode if n <= broadcastArrayThreshold: for i in 1..