Repository navigation
fix: skip the else of a for or while loop left by break - #59
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The
elseof aforloop ran even when the loop was left bybreak.has_break := falsewas emitted before the loop, but nothing ever set it:printed
foundand thenmissing. Theelseof awhileloop was dropped entirely, sowhile i < 3: i += 1withelse: print("done", i)printed nothing.Now a
breakthat leaves a loop with anelsesets a flag named for that loop (py2v_broke1), and the else body runs only when the flag is still false (awhile True:loop keeps its plainbreak, since its else can never run). Abreakin a nested loop sets that loop's own flag or none, and abreakinside the else body belongs to the enclosing loop. Awhileloop with a plain condition and nobreakof its own runs its else body right after the loop. A loop without anelseis emitted exactly as before, and so is afor/elsewith nobreakof its own, with one exception: over three or more tuple targets (for a, b, c in rows:) master dropped the else, and it now runs.Two
for/elseloops without abreak, one after the other in the same block, still both declarehas_breakand fail to build, as on master.while/elsewith a walrus condition still drops the else, andasync for/elseover a call still always runs it, as on master.Test plan
tests/cases/for_else_break.pywith its expected V: it covers a break taken and not taken, a break in a nested loop, andwhile/elsewith and without a break. What master emits for it doesn't build; with this change it prints what CPython prints.v tests/run_tests.vsh: 170 passed, 0 failed (on master the new case fails and everything else passes). The other 180 Python files undertests/emit the same bytes as master.forover a list,range,rangewith a step,enumerateand a string, andwhile; break taken, not taken, in a nestedif, in a nested loop, in a nested loop's else, withcontinue,returnandwhile True; with and withoutelse; one loop or two in a row), compared with CPython's output (V ec510e2, Python 3.15.2, macOS arm64): 88 that were wrong or failed to build now match, and every program that matched before still does. The 168 of them without anelseemit the same bytes as master. Of the 208 programs that still don't match, 192 fail underv -W runon both, 14 print the wrong thing on both, and 2 went from failing to printing the wrong thing; all 16 of the wrong ones loop over a string, which V iterates as bytes.