Skip to content

fix(codegen): a for loop over a plain iterator type iterates a copy - #145

Merged
omdxp merged 1 commit into
mainfrom
fix/plain-iterator-copy
Sep 19, 2026
Merged

omdxp merged 1 commit into
mainfrom
fix/plain-iterator-copy

Conversation

@omdxp

@omdxp omdxp commented Sep 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • The language guide says a for loop always iterates a fresh copy of the value it started from, never the caller's own variable, so two loops over one value, or one nested in another, cannot corrupt each other's position. Every generic direct implementor (Vec, Map, Set, a user's own generic type) did that, but a plain, non-generic type with its own Iterator<T> impl drove the variable itself: after for x : c { ... }, c.cur had advanced, and a second or nested loop over c saw an exhausted iterator.
  • The plain path now copies the value into a fresh cursor (__fun_iter_srcN) first and drives that, for both the inlined next() and the call-based fallback, the same shape the generic path already uses.
  • Found while checking the pointer-iteration fix: the same in-place behavior showed through a Counter* parameter.

Test plan

  • 3-stage self-compile bootstrap clean
  • fun test . 33/33 files
  • fun -fmt-check-all clean, fun lint src and fun lint stdlib clean
  • scripts/run_examples.sh 218/218 (known pre-existing let_and_lowlevel_types.fn flake)
  • New test: two sequential loops and a nested pair over one plain iterator all see the full sequence and the variable keeps its own cursor, for an inlinable next() and for an elif-chain next() that takes the call-based path, plus iteration through a pointer parameter

The language guide says a for loop always iterates a fresh copy of the value it started from, never the caller's own variable, and every generic direct implementor (Vec, Map, Set, user generics) did. A plain, non-generic type with its own Iterator impl drove the variable itself, so a loop advanced its cursor and a second loop over the same value, or a nested one, saw an exhausted iterator. It now copies the value into a fresh cursor first, for both the inlined and the call-based next().
@omdxp
omdxp merged commit a117f89 into main Sep 19, 2026
4 checks passed
@omdxp
omdxp deleted the fix/plain-iterator-copy branch September 19, 2026 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant