Skip to content

An if/else branch written without braces is a scope of its own (#458) - #475

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix-unbraced-else-forof
Oct 3, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
fix-unbraced-else-forof

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Fixes #458.

In every model, if (x) a(); else for (const c of gen()) ... failed to compile with "operand #0 does not dominate this use".

A braced branch is a Block. A Block keeps its own lists of what it must release at its end: owned locals and using declarations. An unbraced branch was generated straight into the enclosing block's lists instead. So the iterator owned by a for ... of over a generator, which is defined inside the branch's region, was released at the end of the block around the if, outside that region. A number loop, or a for ... of over an array, owns nothing there, which is why those compiled.

mlirGenBranchStatement now generates an unbraced then/else statement with lists of its own, ending in the same scope exit a Block ends with. A braced branch still goes through mlirGen(Block).

Tests

  • New 00unbraced_branch_scope.ts, registered as compile and JIT tests and in the rc/none corpus. It covers:

    • an unbraced else and an unbraced then iterating a generator;
    • the same inside a loop;
    • an unbraced if as a loop body.

    It failed to compile before the change, and now passes under gc, rc, none and own.

  • The own corpus is unchanged.

  • On Linux (WSL, GCC), the rc corpus, own tests and the new tests pass: 1453/1453.

  • Full Release ctest on Windows: 3690/3691. The one failure is test-compile-gc-defaultlib-collector, the known local LNK2005 against the stale installed default library; it fails on main the same way.

🤖 Generated with Claude Code

`if (x) a(); else for (const c of gen()) ...` failed to compile in every model: "operand #0 does
not dominate this use". A braced branch is a Block, and a Block keeps its own lists of what it must
give back at its end - owned locals, `using` declarations. An unbraced branch was generated
straight into the enclosing block's lists, so the iterator a `for ... of` over a generator owns,
defined inside the branch's region, was released at the end of the block around the `if`,
outside that region. A number loop or a `for ... of` over an array owns nothing there, which is
why they compiled.

mlirGenBranchStatement generates an unbraced then/else statement with lists of its own and the
same scope exit a Block ends with; a braced branch still goes through mlirGen(Block).

Test: 00unbraced_branch_scope (compile and JIT, and in the rc/none corpus): an unbraced else and
then iterating a generator, inside a loop, and an unbraced if as a loop body. It failed to compile
before the change; it passes under gc, rc, none and own. The own corpus is unchanged; on Linux
(WSL, GCC) the rc corpus, own and new tests pass (1453/1453).

Fixes #458.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit f013674 into main Oct 3, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix-unbraced-else-forof branch October 3, 2026 21:35
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.

Unbraced else whose body is a for-of over a generator, inside a loop: operand does not dominate this use

1 participant