fixes #25849; fixes #25872; Iteration on elements of array (#25860)

fixes #25849
fixes https://github.com/nim-lang/Nim/issues/25872
This commit is contained in:
ringabout
2026-06-06 13:58:19 +08:00
committed by GitHub
parent 46259cd0b8
commit f1ff8b6d9e
3 changed files with 53 additions and 5 deletions

View File

@@ -22,7 +22,7 @@ import std / tables
import
options, ast, astalgo, trees, msgs,
idents, renderer, types, semfold, magicsys, cgmeth,
idents, renderer, types, semfold, magicsys, cgmeth, parampatterns,
lowerings, liftlocals,
modulegraphs, lineinfos
@@ -675,7 +675,7 @@ type
paDirectMapping, paFastAsgn, paFastAsgnTakeTypeFromArg
paVarAsgn, paComplexOpenarray, paViaIndirection
proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
proc putArgInto(arg: PNode, formal: PType; borrowedFirstArg = false): TPutArgInto =
# This analyses how to treat the mapping "formal <-> arg" in an
# inline context.
if formal.kind == tyTypeDesc: return paDirectMapping
@@ -726,6 +726,13 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
if skipTypes(formal, abstractInst).kind in {tyVar, tyLent}: result = paVarAsgn
else: result = paFastAsgn
if borrowedFirstArg and result == paDirectMapping and parampatterns.exprRoot(arg) == nil and
parampatterns.isAssignable(nil, arg) == arNone:
# Inline iterators like `items(array)` borrow from the first argument.
# If that argument is just a transient expression, materialize it so the
# lifted closure keeps the backing storage alive across yields.
result = paFastAsgnTakeTypeFromArg
proc findWrongOwners(c: PTransf, n: PNode) =
if n.kind == nkVarSection:
let x = n[0][0]
@@ -824,13 +831,16 @@ proc transformFor(c: PTransf, n: PNode): PNode =
if iter.kind != skIterator: return result
# generate access statements for the parameters (unless they are constant)
pushTransCon(c, newC)
let borrowedIterResult =
iter.typ != nil and iter.typ.returnType != nil and
skipTypes(iter.typ.returnType, abstractInst).kind in {tyLent, tyVar}
for i in 1..<call.len:
var arg = transform(c, call[i])
let ff = skipTypes(iter.typ, abstractInst)
# can happen for 'nim check':
if i >= ff.n.len: return result
var formal = ff.n[i].sym
let pa = putArgInto(arg, formal.typ)
let pa = putArgInto(arg, formal.typ, borrowedIterResult and i == 1)
case pa
of paDirectMapping:
newC.mapping[formal.itemId] = arg

View File

@@ -3,7 +3,7 @@
when defined(nimPreviewSlimSystem):
import std/assertions
when not defined(nimNoLentIterators):
when (not defined(nimNoLentIterators)) and not defined(js) and not defined(nimscript):
template lent2(T): untyped = lent T
else:
template lent2(T): untyped = T
@@ -37,7 +37,7 @@ iterator mitems*[T](a: var openArray[T]): var T {.inline.} =
yield a[i]
unCheckedInc(i)
iterator items*[IX, T](a: array[IX, T]): T {.inline.} =
iterator items*[IX, T](a: array[IX, T]): lent2 T {.inline.} =
## Iterates over each item of `a`.
when a.len > 0:
var i = low(IX)

View File

@@ -0,0 +1,38 @@
discard """
targets: "c cpp js"
"""
template sameAddress(a, b): bool =
when defined(js):
a == b
else:
a.unsafeAddr == b.unsafeAddr
proc main() =
block:
let a = [10, 11, 12]
for ai in items(a):
doAssert sameAddress(ai, a[0])
break
block:
let a = [[1, 2], [1, 2], [1, 2]]
for ai in items(a):
doAssert sameAddress(ai[0], a[0][0])
break
block:
let s = @[(1, 2), (3, 4), (5, 6)]
doAssert (3, 4) in s
main()
static:
main()
block: # issue #25849
static:
const key = "NIM_TESTS_TOSENV_KEY"
for val in ["val", "", "\xc3\x86"]:
let s = @[(key, "val"), (key, ""), (key, "\xc3\x86")]
doAssert (key, val) in s