fixes #24720; std lib iterators unnecessarily require value copies

This commit is contained in:
ringabout
2026-04-30 21:30:02 +08:00
parent 4bcb706d49
commit 70c30284b2
4 changed files with 61 additions and 7 deletions

View File

@@ -65,7 +65,7 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
t.incl tfNonConstExpr
else:
t = base
result.typ = makeTypeDesc(c, t)
result.typ = makeTypeDesc(c, decayTypeOfView(c, t))
type
SemAsgnMode = enum asgnNormal, noOverloadedSubscript, noOverloadedAsgn

View File

@@ -1879,6 +1879,38 @@ proc fixupTypeOf(c: PContext, prev: PType, typ: PType) =
if prev.kind != tyGenericBody:
assignType(prev, result)
proc decayTypeOfView(c: PContext, typ: PType): PType =
if typ == nil: return nil
let t = typ.skipTypes({tyGenericInst, tyAlias, tySink})
case t.kind
of tyVar, tyLent:
result = decayTypeOfView(c, t.elementType)
of tyTuple:
var changed = false
var kids = newSeq[PType](t.len)
for i in 0..<t.len:
kids[i] = decayTypeOfView(c, t[i])
if kids[i] != t[i]: changed = true
if changed:
result = copyType(t, c.idgen, t.owner)
for i in 0..<kids.len:
result[i] = kids[i]
if t.n != nil:
result.n = copyNode(t.n)
for it in t.n:
if it.kind == nkSym and it.sym.kind == skField:
let field = copySym(it.sym, c.idgen)
field.ast = it.sym.ast
if field.position >= 0 and field.position < kids.len:
field.typ = kids[field.position]
result.n.add newSymNode(field, it.info)
else:
result.n.add copyTree(it)
else:
result = typ
else:
result = typ
proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
var n = semExprWithType(c, n, {efDetermineType})
if n.typ.kind == tyTypeDesc:
@@ -2078,6 +2110,7 @@ proc semTypeOf(c: PContext; n: PNode; prev: PType): PType =
result.incl tfNonConstExpr
else:
result = base
result = decayTypeOfView(c, result)
fixupTypeOf(c, prev, result)
proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
@@ -2103,6 +2136,7 @@ proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
result.incl tfNonConstExpr
else:
result = base
result = decayTypeOfView(c, result)
fixupTypeOf(c, prev, result)
proc semTypeIdent(c: PContext, n: PNode): PSym =

View File

@@ -739,7 +739,7 @@ template withValue*[A, B](t: Table[A, B], key: A,
discard
iterator pairs*[A, B](t: Table[A, B]): (A, B) =
iterator pairs*[A, B](t: Table[A, B]): (lent A, lent B) =
## Iterates over any `(key, value)` pair in the table `t`.
##
## See also:
@@ -1201,7 +1201,7 @@ proc `==`*[A, B](s, t: TableRef[A, B]): bool =
iterator pairs*[A, B](t: TableRef[A, B]): (A, B) =
iterator pairs*[A, B](t: TableRef[A, B]): (lent A, lent B) =
## Iterates over any `(key, value)` pair in the table `t`.
##
## See also:
@@ -1789,7 +1789,7 @@ proc `==`*[A, B](s, t: OrderedTable[A, B]): bool =
iterator pairs*[A, B](t: OrderedTable[A, B]): (A, B) =
iterator pairs*[A, B](t: OrderedTable[A, B]): (lent A, lent B) =
## Iterates over any `(key, value)` pair in the table `t` in insertion
## order.
##
@@ -2212,7 +2212,7 @@ proc `==`*[A, B](s, t: OrderedTableRef[A, B]): bool =
iterator pairs*[A, B](t: OrderedTableRef[A, B]): (A, B) =
iterator pairs*[A, B](t: OrderedTableRef[A, B]): (lent A, lent B) =
## Iterates over any `(key, value)` pair in the table `t` in insertion
## order.
##
@@ -2622,7 +2622,7 @@ proc `==`*[A](s, t: CountTable[A]): bool =
equalsImpl(s, t)
iterator pairs*[A](t: CountTable[A]): (A, int) =
iterator pairs*[A](t: CountTable[A]): (lent A, int) =
## Iterates over any `(key, value)` pair in the table `t`.
##
## See also:
@@ -2899,7 +2899,7 @@ proc `==`*[A](s, t: CountTableRef[A]): bool =
else: result = s[] == t[]
iterator pairs*[A](t: CountTableRef[A]): (A, int) =
iterator pairs*[A](t: CountTableRef[A]): (lent A, int) =
## Iterates over any `(key, value)` pair in the table `t`.
##
## See also:

20
tests/arc/t24720.nim Normal file
View File

@@ -0,0 +1,20 @@
discard """
matrix: "--mm:orc"
output: '''
found entry
'''
"""
import std/tables
type NoCopies = object
proc `=copy`(a: var NoCopies, b: NoCopies) {.error.}
# bug #24720
proc foo() =
var t: Table[int, NoCopies]
t[3] = NoCopies() # only moves
for k, v in t.pairs(): # lent values, no need to copy!
echo "found entry"
foo()