Skip to content

match arms: accept brace-block bodies#226

Merged
danieljohnmorris merged 3 commits into
mainfrom
fix/match-arm-multistmt
May 13, 2026
Merged

match arms: accept brace-block bodies#226
danieljohnmorris merged 3 commits into
mainfrom
fix/match-arm-multistmt

Conversation

@danieljohnmorris
Copy link
Copy Markdown
Collaborator

Summary

~v:{stmt1;stmt2;final-expr} is now a valid match arm body, alongside the existing inline ~v:stmt1;stmt2;final-expr form. Mirrors the existing =cond{block} grammar so the arm boundary is unambiguous when the body contains call-shapes that resemble patterns.

The manifesto framing: every Result-handling site that wants more than a single expression in an arm currently either uses the inline ; form (which works but is visually noisy and easy for a tired model to mis-segment) or extracts a helper function. Personas reported the helper tax repeatedly (ilo_assessment_feedback.md lines 830, 851, 928). Brace blocks give a visually clear, unambiguous shape that matches what the agent already knows about =cond{block}.

Repro

Before:

go>n;r=num "10";?r{~v:{d=*v 2;+d 1};^e:0}
{"code":"ILO-P009","labels":[...],"message":"expected expression, got LBrace",...}

After:

21

What's in the diff

  • parser: accept brace-block bodies in match arms — in parse_arm_body, when the post-colon token is LBrace and it is not a destructure-pattern start, delegate to parse_brace_body. AST shape unchanged: MatchArm.body stays Vec<Spanned<Stmt>>, last stmt is the arm value. Every backend already iterates that way, so no verifier / interpreter / VM / Cranelift change needed.
  • tests: cross-engine coveragetests/regression_match_block.rs with seven tests across tree / VM / Cranelift: single-expr (existing), brace block with local in Ok arm, brace block on Err arm, nested match in block, bool match with blocks on both branches, inline ;-separated still works, match-as-expression with brace-block arm.
  • examples: examples/match-block.ilo — engine-asserted example picked up by tests/examples_engines.rs so the shape is exercised on every backend.

Test plan

  • cargo fmt
  • cargo clippy --release --features cranelift --all-targets -- -D warnings
  • cargo test --release --features cranelift — full suite green
  • New regression_match_block tests all pass on tree, VM, and Cranelift
  • Existing single-expr and inline-; arm bodies still work (anchored by the first and sixth tests)

Follow-ups

None for this PR. The inline-; form remains valid and is the more token-minimal shape for short arm bodies; brace blocks are the readable escape hatch when you need locals or want the boundary to be unmistakable.

`~v:{stmt1;stmt2;final-expr}` is now valid alongside the existing
`~v:stmt1;stmt2;final-expr` inline form. Mirrors `=cond{block}` grammar
so the arm boundary is unambiguous when the body contains call-shapes
that look like patterns to a tired model.

In parse_arm_body, when the post-colon token is LBrace and not a
destructure-pattern start, delegate to parse_brace_body. AST is
unchanged: MatchArm.body stays Vec<Spanned<Stmt>>, last stmt is the
arm value, every backend already iterates that way.
Seven tests across tree, VM, and Cranelift covering:
- single-expr arms (existing behaviour preserved)
- brace block with a local binding inside an Ok arm
- brace block on the Err arm
- nested match inside a brace-block arm
- bool match with brace blocks on both branches
- inline ;-separated arm body still works (additive change)
- match-as-expression on RHS of a binding with brace-block arm

The single-expr and inline-semi cases anchor that the brace-block path
is purely additive and the old shapes can't silently regress.
Engine-asserted example demonstrating brace-block arm bodies on Ok and
Err arms, nested match inside a block, and bool match with blocks on
both branches. Picked up by tests/examples_engines.rs so the shape is
exercised on every backend.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@danieljohnmorris danieljohnmorris merged commit 35fc72a into main May 13, 2026
5 checks passed
@danieljohnmorris danieljohnmorris deleted the fix/match-arm-multistmt branch May 13, 2026 12:38
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