Skip to content

fix: Allow break inside a switch inside an unrolled loop - #3152

Open
dchaudhari7177 wants to merge 1 commit into
software-mansion:mainfrom
dchaudhari7177:fix/3068-break-in-switch-in-unroll
Open

dchaudhari7177 wants to merge 1 commit into
software-mansion:mainfrom
dchaudhari7177:fix/3068-break-in-switch-in-unroll

Conversation

@dchaudhari7177

Copy link
Copy Markdown
Contributor

Fixes #3068.

Cause

WgslGenerator rejects every break while #unrollingChain is non-empty ("Cannot unroll loop containing break"). A break inside a switch exits the switch, not the loop, and the switch is still there after unrolling. So this threw:

for (const foo of tgpu.unroll([1, 2])) {
  switch (mode) {
    case 0:
      r += foo;
      break;
    default:
      r -= foo;
      break;
  }
}

Fix

A new #breakExitsSwitch flag says whether the innermost statement a break would exit is a switch.

  • While a switch's case consequents are generated, it is true.
  • For each unrolled iteration's body it is reset to false. An unrolled loop nested inside a switch case therefore still rejects a break of its own, which would otherwise end up exiting the switch after unrolling.
  • break is rejected only when unrolling and the flag is false.
  • continue is unchanged: inside a switch it still targets the unrolled loop, so it still throws.

Ordinary for/while loops already reset #unrollingChain, so break inside them was never affected.

Tests (tests/unroll.test.ts)

  • break in a runtime switch inside tgpu.unroll: unrolls, one switch per iteration, and the trailing breaks are pruned as usual.
  • The same with a comptime-known discriminant (the folded single-default switch).
  • continue in a switch inside the unrolled loop still throws "Cannot unroll loop containing continue".
  • An unrolled loop with a break nested inside a switch case still throws "Cannot unroll loop containing break".

On main the first two fail. On this branch, packages/typegpu gives 192 files, 2735 passed, and packages/typegpu-gl passes. oxfmt is clean.

A `break` in a switch case exits the switch, which survives unrolling,
so it is not a `break` of the unrolled loop. Track whether the innermost
`break` target is a switch, reset it for each unrolled iteration, and
only reject a `break` that would exit the unrolled loop itself.
`continue` inside such a switch still targets the loop and still throws.

Closes software-mansion#3068
Copilot AI balanced review requested due to automatic review settings October 3, 2026 09:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • break in a switch inside an unrolled loop — added a #breakExitsSwitch flag to WgslGenerator that is set while generating a switch case consequent and reset per unrolled iteration, so break is only rejected when it would actually exit the unrolled loop.
  • Tests — four new cases in unroll.test.ts covering the runtime-discriminant switch, the comptime-folded switch, continue still throwing, and a break in an unrolled loop nested inside a switch case still throwing.

I traced the flag through nested switches, switches in unrolled loops, unrolled loops in switch cases, and runtime for/while loops nested in either (these reset #unrollingChain, so they need no flag handling). Save/restore via finally is correct in every path. I also confirmed the two positive tests fail with the fix condition reverted to the base form, so they genuinely pin the change. The full packages/typegpu suite (2735 tests) and packages/typegpu-gl (118 tests) pass; GlslGenerator inherits _statement, so it picks up the fix.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

This branch has not been deployed

No deployments
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.

fix: Allow for break inside switch statements that are inside of unroll

2 participants