mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-07 20:34:21 +00:00
fixes #25697
This pull request improves the handling of borrowed routines in the
compiler transformation phase, making the code more robust and
maintainable. The main change is the introduction of a helper function
to properly resolve borrowed routine symbols, which is then used in
multiple places to ensure correct symbol resolution. Additionally, a new
test case is added to cover a previously reported bug related to
borrowed iterators on distinct types.
**Compiler improvements:**
* Added `resolveBorrowedRoutineSym` helper function to follow borrow
aliases and retrieve the underlying implementation symbol for borrowed
routines. This centralizes and clarifies the logic for resolving
borrowed symbols.
* Updated `transformSymAux` and `transformFor` to use the new helper
function, replacing duplicated logic and improving correctness when
handling borrowed routines.
[[1]](diffhunk://#diff-c7b80f51fb685eb22c5b56ee2f320d6c708706f3ae7293478ecd104a2b5b8096L139-R154)
[[2]](diffhunk://#diff-c7b80f51fb685eb22c5b56ee2f320d6c708706f3ae7293478ecd104a2b5b8096L788-R795)
**Testing:**
* Added a test case for bug #25697 to `tests/distinct/tborrow.nim`,
ensuring that iteration over a distinct type with a borrowed iterator
works as expected.
(cherry picked from commit 9a2b0dd045)
This commit is contained in:
@@ -120,6 +120,24 @@ proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode; isFirstWrite
|
||||
le.flags.incl nfFirstWrite
|
||||
result[1] = ri
|
||||
|
||||
proc resolveBorrowedRoutineSym(c: PTransf; s: PSym; info: TLineInfo): PSym =
|
||||
# Follow borrow aliases to the underlying implementation symbol.
|
||||
var s = s
|
||||
while true:
|
||||
# Skips over all borrowed procs getting the last proc symbol without an implementation
|
||||
let body = getBody(c.graph, s)
|
||||
if body.kind == nkSym and sfBorrow in body.sym.flags and getBody(c.graph, body.sym).kind == nkSym:
|
||||
s = body.sym
|
||||
else:
|
||||
break
|
||||
|
||||
let body = getBody(c.graph, s)
|
||||
if body.kind == nkSym:
|
||||
result = body.sym
|
||||
else:
|
||||
result = nil
|
||||
internalError(c.graph.config, info, "wrong AST for borrowed symbol")
|
||||
|
||||
proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
let s = n.sym
|
||||
if s.typ != nil and s.typ.callConv == ccClosure:
|
||||
@@ -138,17 +156,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
var tc = c.transCon
|
||||
if sfBorrow in s.flags and s.kind in routineKinds:
|
||||
# simply exchange the symbol:
|
||||
var s = s
|
||||
while true:
|
||||
# Skips over all borrowed procs getting the last proc symbol without an implementation
|
||||
let body = getBody(c.graph, s)
|
||||
if body.kind == nkSym and sfBorrow in body.sym.flags and getBody(c.graph, body.sym).kind == nkSym:
|
||||
s = body.sym
|
||||
else:
|
||||
break
|
||||
b = getBody(c.graph, s)
|
||||
if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
|
||||
b = newSymNode(b.sym, n.info)
|
||||
b = newSymNode(resolveBorrowedRoutineSym(c, s, n.info), n.info)
|
||||
elif c.inlining > 0:
|
||||
# see bug #13596: we use ref-based equality in the DFA for destruction
|
||||
# injections so we need to ensure unique nodes after iterator inlining
|
||||
@@ -786,7 +794,9 @@ proc transformFor(c: PTransf, n: PNode): PNode =
|
||||
|
||||
discard c.breakSyms.pop
|
||||
|
||||
let iter = call[0].sym
|
||||
var iter = call[0].sym
|
||||
if sfBorrow in iter.flags and iter.kind in routineKinds:
|
||||
iter = resolveBorrowedRoutineSym(c, iter, n.info)
|
||||
|
||||
var v = newNodeI(nkVarSection, n.info)
|
||||
for i in 0..<n.len - 2:
|
||||
|
||||
@@ -130,3 +130,14 @@ block: # issue #22646
|
||||
var x: Vec[3, float]
|
||||
let y = Color(x)
|
||||
doAssert Vec3[float](y) == x
|
||||
|
||||
block: # bug #25697
|
||||
type MyList = distinct seq[int]
|
||||
|
||||
iterator items(x: MyList): lent int {.borrow.}
|
||||
|
||||
let s = MyList(@[1, 2, 3])
|
||||
var count = 0
|
||||
for item in s:
|
||||
count += 1
|
||||
doAssert count == 3, "Expected 3 items, got " & $count
|
||||
|
||||
Reference in New Issue
Block a user