From 9a2b0dd04578705b40771840bc2e97d287272725 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 9 Apr 2026 17:08:03 +0800 Subject: [PATCH] fixes #25697; {.borrow.} on iterator for distinct seq triggers internal error (#25709) 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. --- compiler/transf.nim | 34 ++++++++++++++++++++++------------ tests/distinct/tborrow.nim | 11 +++++++++++ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index 049ed4fa5b..e85ecd3e07 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -118,6 +118,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: @@ -136,17 +154,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 @@ -785,7 +793,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..