fixes regressions

This commit is contained in:
Araq
2026-07-02 21:26:52 +02:00
parent 54dffbd09c
commit 917cdb5236
6 changed files with 38 additions and 9 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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`

View File

@@ -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 -----------------------------------------------

View File

@@ -2039,6 +2039,10 @@ proc getNullValue(c: PCtx; typ: PType, info: TLineInfo; conf: ConfigRef): PNode
if n <= broadcastArrayThreshold:
for i in 1..<n:
result.add getNullValue(c, elemType(t), info, conf)
else:
# Broadcast form: mark the single-son node so `isDefaultBroadcastArray`
# recognises it unambiguously (see `nfBroadcast`).
result.flags.incl nfBroadcast
of tyTuple:
result = newNodeIT(nkTupleConstr, info, t)
for a in t.kids:

View File

@@ -28,3 +28,17 @@ block:
fun[(int, string)]()
fun[ref Foo]()
fun[seq[int]]()
block: # shrinking an `@[...]` seq literal in the VM
# A `@[a, b, c]` seq value keeps the array-literal type in the VM; shrinking it
# to length 1 must not be misread as a broadcast default array (was: the whole
# thing collapsed to `len` copies of the first element).
proc shrink =
var s = @[10, 20, 30]
s.setLen(1)
doAssert s == @[10]
var t = @["foo", "bar"]
t.delete(1)
doAssert t == @["foo"]
static: shrink()
shrink()