Skip to content

fix(runtime): preserve control flow in statement-position expressions - #605

Open
summer-boythink wants to merge 1 commit into
tokio-rs:mainfrom
summer-boythink:fix/statement-position-control-flow
Open

summer-boythink wants to merge 1 commit into
tokio-rs:mainfrom
summer-boythink:fix/statement-position-control-flow

Conversation

@summer-boythink

@summer-boythink summer-boythink commented Nov 11, 2026 •

Copy link
Copy Markdown

Summary

Fixes #603.

Conditional and block expressions were lowered to JavaScript IIFEs even when their value was discarded. The IIFE created a function boundary, so return exited the IIFE instead of the enclosing event handler, and break or continue became illegal.

This change lowers non-trailing if and block expressions directly in statement position and discards their JavaScript value instead of turning it into a return statement. Discarded values are evaluated as statements rather than awaited, so lazy runtime futures are not started, matching Rust's drop behavior. The Rust token stream still keeps the block value, so branch type checking and inference match the source expression. Expression-position lowering is unchanged.

The production change is limited to the expression grammar: stmt.rs separates the Rust block value from the JavaScript value usage, and block.rs / expr_if.rs gain an explicit JavaScript value-usage choice.

The coherence suite previously recorded return_inside_if, break_inside_if, and continue_inside_if as known mismatches. They now agree in Rust and JavaScript, so their baselines and known-mismatch tests are removed and replaced with regular control-flow coverage. The new tests also check that statement values are discarded, including async branches and an unpolled future.

Testing

  • cargo test -p topcoat-runtime-coherence
  • cargo test -p topcoat-runtime-macro
  • cargo test -p topcoat-runtime-grammar
  • cargo test -p topcoat-view-macro
  • cargo test -p topcoat-runtime
  • Checked that if branches with incompatible types still produce a Rust type error
  • cargo clippy -p topcoat-runtime-grammar -p topcoat-runtime-macro --all-targets --all-features --locked -- -D warnings
  • cargo clippy -p topcoat-runtime-coherence --tests --all-features --locked -- -D warnings
  • cargo +nightly fmt --all -- --check
  • cargo topcoat fmt --check (only the pre-existing Leptos benchmark errors)
  • RUSTDOCFLAGS="--cfg docsrs -Dwarnings" cargo +nightly doc -p topcoat-runtime-grammar --all-features --no-deps --locked

AI disclaimer

This PR was prepared with the assistance of DeepSeek V4.1 Flash 1017. The model inspected the runtime expression codegen, implemented the statement-position lowering and value-discard handling, updated the known-mismatch baselines and tests, and ran the checks above. A human should review the diff before merging.

@summer-boythink
summer-boythink force-pushed the fix/statement-position-control-flow branch 4 times, most recently from 850ae66 to f16c583 Compare November 11, 2026 06:54
Conditional and block expressions were lowered to JavaScript IIFEs even when their value was discarded. The IIFE created a function boundary, so return exited the IIFE instead of the enclosing handler and break or continue became illegal.

Lower non-trailing if and block expressions directly in statement position and discard their JavaScript value instead of returning it. The Rust token stream keeps the block value, so branch type checking still matches the source expression. Expression-position lowering is unchanged.

This also removes the return/break/continue known mismatches from the coherence suite.

Closes tokio-rs#603
@summer-boythink
summer-boythink force-pushed the fix/statement-position-control-flow branch from f16c583 to 82be57e Compare November 11, 2026 06:59
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.

Early return has no effect in generated JS event handler

1 participant