0%

Section 9: Match Expressions

Goal: Full pattern matching support

SPEC: spec/15-patterns.md

Proposals:

  • proposals/approved/match-expression-syntax-proposal.md — Match expression and pattern syntax
  • proposals/approved/pattern-matching-exhaustiveness-proposal.md — Exhaustiveness checking
  • proposals/approved/range-patterns-char-byte-proposal.md — Range patterns on char and byte

9.0 Match Expression Syntax

Proposal: proposals/approved/match-expression-syntax-proposal.md

Documents the existing implementation of match expressions. Key specifications:

  • match expr { pattern -> expression, ... } syntax (comma-separated arms)
  • Guard syntax if condition
  • Pattern types: literal, binding, wildcard, variant, struct, tuple, list, range, or-pattern, at-pattern
  • Top-to-bottom, first-match-wins evaluation
  • Integer-only literal patterns (no float patterns)

Status: IMPLEMENTED — This proposal formalizes existing behavior.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.

  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (9.0) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-9.0 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 9.0: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

9.0.1 Comma-Separated Match Arms

Proposal: proposals/approved/match-arm-comma-separator-proposal.md

Changes match arm separators from newlines to commas (trailing commas optional). Also formally adopts if guard syntax replacing .match(condition). Key changes:

  • match_arms = [ match_arm { "," match_arm } [ "," ] ] — comma-separated
  • match_arm = match_pattern [ "if" expression ] "->" expressionif guards
  • .match() now exclusively means method-style pattern matching
  • Formatter allows single-line matches for short, simple arms

Status: APPROVED — Parser migration part of block-expression-syntax implementation.

  • Implement: Parser — comma-separated match arms in match expr { } block syntax

    • Rust Tests: ori_parse/src/tests/ — comma-separated arm parsing
    • Ori Tests: tests/spec/patterns/match.ori — uses comma syntax throughout (62 tests)
  • Implement: Parser — if guard syntax replacing .match(condition)

    • Rust Tests: ori_parse/src/tests/if guard parsing
    • Ori Tests: tests/spec/patterns/match.ori — migrate guard tests from legacy .match() to if syntax HYGIENE: all spec tests still use legacy .match() syntax; only AOT tests use if
  • Implement: Formatter — emit commas, support single-line short matches

    • Rust Tests: ori_fmt/src/formatter/ — comma emission tests

Implementation


9.1 match Expression


  • Implement: Grammar match_expr = "match" "(" expression "," match_arms ")" — spec/15-patterns.md § match

    • Rust Tests: Parser and evaluator — match expression tests
    • Ori Tests: tests/spec/patterns/match.ori — 62 tests pass
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — full match expression codegen with or-patterns, guards, tuples, bindings, nested match, exhaustiveness (22 tests, 0 ignored)
  • Implement: Grammar match_arms = match_arm { "," match_arm } [ "," ] — spec/15-patterns.md § match

    • Rust Tests: Parser — match arms parsing
    • Ori Tests: tests/spec/patterns/match.ori
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — comma-separated multi-arm match with literals, bindings, wildcards, guards (all 22 tests use multi-arm match)
  • Implement: Grammar match_arm = pattern [ guard ] "->" expression — spec/15-patterns.md § match

    • Rust Tests: Parser — match arm parsing
    • Ori Tests: tests/spec/patterns/match.ori
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — match arm with pattern + guard + expression codegen (test_pattern_guard_basic, test_pattern_guard_with_binding, test_pattern_fizzbuzz)
  • Implement: Evaluate scrutinee expression — spec/15-patterns.md § match

    • Rust Tests: Evaluator — scrutinee evaluation
    • Ori Tests: tests/spec/patterns/match.ori
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — scrutinee evaluation for int, char, bool, tuple, and Result values (all 22 tests evaluate scrutinee expressions)
  • Implement: Test each arm’s pattern in order — spec/15-patterns.md § match

    • Rust Tests: Evaluator — pattern matching order
    • Ori Tests: tests/spec/patterns/match.ori
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — first-match-wins ordering with literal and guard arms (test_pattern_tuple_basic, test_pattern_tuple_second_arm, test_pattern_guard_basic)
  • Implement: If pattern matches and guard passes, evaluate arm — spec/15-patterns.md § match

    • Rust Tests: Evaluator — arm evaluation
    • Ori Tests: tests/spec/patterns/match.ori
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — arm evaluation with guard conditions (test_pattern_guard_basic, test_pattern_guard_with_binding, test_pattern_guard_complex_condition)
  • Implement: Return the result — spec/15-patterns.md § match

    • Rust Tests: Evaluator — result return
    • Ori Tests: tests/spec/patterns/match.ori
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — match expressions return values used in subsequent computation (all 22 tests verify match result usage)

9.2 Pattern Types

HYGIENE: Each pattern type has [ ] LLVM Support + [ ] LLVM Rust Tests items that are redundant with [x] AOT Tests — LLVM codegen works through the ARC IR pipeline, not a separate path. The [ ] items below represent dedicated codegen unit tests, not missing functionality. AOT matrix is incomplete for list, at, struct (direct), variant (direct), and range patterns.


  • Implement: literal_pattern = literal — spec/15-patterns.md § Pattern Types

    • Rust Tests: Parser — literal pattern parsing
    • Ori Tests: tests/spec/patterns/match.ori, tests/spec/patterns/match_patterns.ori
    • LLVM Support: LLVM codegen for literal pattern (REDUNDANT — works via ARC IR, see AOT Tests)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — literal pattern codegen (REDUNDANT — covered by AOT Tests)
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — int, char, and bool literal patterns in match arms (test_pattern_or_int_literals, test_pattern_or_char_literals, test_pattern_match_all_bool_cases, test_pattern_match_many_char_literals)
  • Implement: binding_pattern = identifier — spec/15-patterns.md § Pattern Types

    • Rust Tests: Parser — binding pattern parsing
    • Ori Tests: tests/spec/patterns/match_patterns.ori — 36 tests
    • LLVM Support: LLVM codegen for binding pattern (REDUNDANT — works via ARC IR, see AOT Tests)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — binding pattern codegen (REDUNDANT — covered by AOT Tests)
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — binding capture and mixed binding+literal arms (test_pattern_binding_capture, test_pattern_binding_with_literal_arms)
  • Implement: wildcard_pattern = "_" — spec/15-patterns.md § Pattern Types

    • Rust Tests: Parser — wildcard pattern parsing
    • Ori Tests: tests/spec/patterns/match.ori
    • LLVM Support: LLVM codegen for wildcard pattern (REDUNDANT — works via ARC IR, see AOT Tests)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — wildcard pattern codegen (REDUNDANT — covered by AOT Tests)
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — wildcard catch-all in match arms (test_pattern_tuple_wildcard_fallthrough, test_pattern_tuple_all_wildcards, and _ arms throughout)
  • Implement: variant_pattern = type_path [ "(" ... ")" ] — spec/15-patterns.md § Pattern Types

    • Rust Tests: Parser — variant pattern parsing
    • Ori Tests: tests/spec/patterns/match_patterns.ori, tests/spec/declarations/sum_types.ori
    • LLVM Support: LLVM codegen for variant pattern (REDUNDANT — works via ARC IR, see AOT Tests)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — variant pattern codegen (REDUNDANT — covered by AOT Tests)
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — Result variant dispatch via is_ok/is_err (test_pattern_match_on_result_tag) WEAK TESTS — uses tag check, not direct Ok(v) -> variant pattern
  • Implement: struct_pattern = "{" ... [ ".." ] "}" — spec/15-patterns.md § Pattern Types

    • Rust Tests: Parser — struct pattern parsing
    • Ori Tests: tests/spec/patterns/binding_patterns.ori — struct destructuring tests
    • LLVM Support: LLVM codegen for struct pattern (REDUNDANT — works via ARC IR, see AOT Tests)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — struct pattern codegen (REDUNDANT — covered by AOT Tests)
    • AOT Tests: ori_llvm/tests/aot/recursion.rs — struct construction and field access in recursive context (test_rec_struct_param with Point struct) WEAK TESTS — indirect coverage only, no direct { x, y } -> struct pattern AOT test
  • Implement: field_pattern = identifier [ ":" pattern ] — spec/15-patterns.md § Pattern Types

    • Rust Tests: Parser — field pattern parsing
    • Ori Tests: tests/spec/patterns/binding_patterns.ori
    • LLVM Support: LLVM codegen for field pattern (REDUNDANT — works via ARC IR, see AOT Tests)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — field pattern codegen (REDUNDANT — covered by AOT Tests)
    • AOT Tests: ori_llvm/tests/aot/recursion.rs — struct field access in recursive patterns (test_rec_struct_param with Point { x, y } fields) WEAK TESTS — indirect coverage only
  • Implement: list_pattern = "[" ... "]" — spec/15-patterns.md § Pattern Types

    • Rust Tests: Parser — list pattern parsing
    • Ori Tests: tests/spec/patterns/binding_patterns.ori — list destructure tests
    • LLVM Support: LLVM codegen for list pattern (REDUNDANT — works via ARC IR)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — list pattern codegen
    • AOT Tests: No AOT coverage yet INCOMPLETE MATRIX
  • Implement: list_elem = pattern | ".." [ identifier ] — spec/15-patterns.md § Pattern Types

    • Rust Tests: Parser — list element parsing
    • Ori Tests: tests/spec/patterns/binding_patterns.ori — head/tail, first_two_rest
    • LLVM Support: LLVM codegen for list element pattern (REDUNDANT — works via ARC IR)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — list element pattern codegen
    • AOT Tests: No AOT coverage yet INCOMPLETE MATRIX
  • Implement: range_pattern = const_pattern ( ".." | "..=" ) const_pattern — spec/15-patterns.md § Pattern Types, proposals/approved/range-patterns-char-byte-proposal.md

    • Rust Tests: ori_parse/src/grammar/pattern.rs — range pattern parsing (int, char, byte)
    • Ori Tests: tests/spec/patterns/match_range_patterns.ori — int ranges
    • Ori Tests: tests/spec/patterns/match_range_char.ori — char range patterns ('a'..='z')
    • Ori Tests: tests/spec/patterns/match_range_byte.ori — byte range patterns (b'0'..b'9')
    • Implement: const_pattern = literal | "$" identifier — compile-time constant endpoints
    • Rust Tests: ori_parse/src/grammar/pattern.rs — const pattern with $ identifiers
    • Ori Tests: tests/spec/patterns/match_range_const.ori — constant endpoint patterns
    • Implement: Empty range warning (lo > hi) — proposals/approved/range-patterns-char-byte-proposal.md § Type Checking
    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — empty range warning
    • LLVM Support: LLVM codegen for range pattern (int, char, byte)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — range pattern codegen
    • AOT Tests: No AOT coverage yet INCOMPLETE MATRIX
  • Implement: or_pattern = pattern "|" pattern — spec/15-patterns.md § Pattern Types

    • Rust Tests: ori_parse/src/grammar/pattern.rs — or pattern parsing NEEDS TESTS
    • Ori Tests: tests/spec/patterns/match_patterns.ori — or-patterns including multi-alternative and variant or-patterns
    • LLVM Support: LLVM codegen for or pattern (REDUNDANT — works via ARC IR, see AOT Tests)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — or pattern codegen (REDUNDANT — covered by AOT Tests)
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — or-pattern codegen for int, char, bool literals and in loops (4 tests: or_int_literals, or_char_literals, or_bool, or_in_loop)
  • Implement: at_pattern = identifier "@" pattern — spec/15-patterns.md § Pattern Types

    • Rust Tests: ori_parse/src/grammar/pattern.rs — at pattern parsing NEEDS TESTS
    • Ori Tests: tests/spec/patterns/match_patterns.ori — at-patterns tested
    • LLVM Support: LLVM codegen for at pattern (REDUNDANT — works via ARC IR)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — at pattern codegen
    • AOT Tests: No AOT coverage yet INCOMPLETE MATRIX
  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (9.2) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-9.2 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 9.2: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.

9.3 Pattern Guards


  • Implement: Grammar guard = "if" expression (was .match(cond), changed by match-arm-comma-separator-proposal) — spec/15-patterns.md § Guards

    • Rust Tests: Parser — guard parsing
    • Ori Tests: tests/spec/patterns/match.ori — guard tests included HYGIENE: tests use legacy .match() syntax only, not if
    • LLVM Support: LLVM codegen for guard expression (REDUNDANT — works via ARC IR, see AOT Tests)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — guard expression codegen (REDUNDANT — covered by AOT Tests)
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — guard clause codegen with comparisons, logical ops, modulo (4 tests: basic, binding, complex_condition, in_loop)
  • Implement: Guard expression must evaluate to bool — spec/15-patterns.md § Guards

    • Rust Tests: Type checker — guard type checking
    • Ori Tests: tests/spec/patterns/match.ori
    • LLVM Support: LLVM codegen for guard type checking (REDUNDANT — works via ARC IR, see AOT Tests)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — guard type checking codegen (REDUNDANT — covered by AOT Tests)
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — guards evaluate bool conditions (test_pattern_guard_basic, test_pattern_guard_complex_condition)
  • Implement: Variables bound by pattern are in scope — spec/15-patterns.md § Guards

    • Rust Tests: Evaluator — guard scoping
    • Ori Tests: tests/spec/patterns/match.ori
    • LLVM Support: LLVM codegen for guard scoping (REDUNDANT — works via ARC IR, see AOT Tests)
    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — guard scoping codegen (REDUNDANT — covered by AOT Tests)
    • AOT Tests: ori_llvm/tests/aot/patterns.rs — guard with bound variables in scope (test_pattern_guard_with_binding, test_pattern_guard_with_tuple)
  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (9.3) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-9.3 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 9.3: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.

9.4 Exhaustiveness Checking

Proposal: proposals/approved/pattern-matching-exhaustiveness-proposal.md

Pattern matrix decomposition algorithm (Maranget’s algorithm) for exhaustiveness verification.

9.4.1 Core Algorithm

Actual implementation is in compiler/ori_canon/src/exhaustiveness/ (mod.rs, walk.rs, tests.rs) — NOT ori_types/src/check/exhaustiveness/ which does not exist. 45 Rust tests, all pass.

  • Implement: Pattern matrix decomposition — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Algorithm

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — 45 tests covering bool, int, str, list, option, result, user enum, Never, nested, redundant
    • Ori Tests: tests/spec/patterns/exhaustiveness.ori — 12 tests + exhaustiveness_fail.ori — 10 compile_fail tests
  • Implement: Constructor enumeration for types — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Algorithm

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — type constructor tests
    • Ori Tests: tests/spec/patterns/exhaustiveness.ori

9.4.2 Exhaustiveness Errors

  • Implement: Match expressions must be exhaustive (E0123) — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Error Policy tests + 12 positive tests)

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — exhaustiveness checking
    • Ori Tests: tests/spec/patterns/exhaustiveness_fail.ori — 8 non-exhaustive compile_fail tests
  • Implement: Let binding refutability check — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Refutability Requirements

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — refutability errors NEEDS TESTS
    • Ori Tests: tests/spec/patterns/match_exhaustive.ori
  • Implement: Function clause exhaustiveness — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Error Policy

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — clause exhaustiveness NEEDS TESTS
    • Ori Tests: tests/spec/patterns/function_clauses_exhaustive.ori

9.4.3 Guard Handling

  • Implement: Guards not considered for exhaustiveness — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Guards

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — guard handling
    • Ori Tests: tests/spec/patterns/match_patterns.ori — guard_requires_catchall
  • Implement: Guards require catch-all pattern (E0124) — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Guards

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — guard catch-all requirement
    • Ori Tests: tests/spec/patterns/match_patterns.ori — guard_requires_catchall

9.4.4 Pattern Coverage

  • Implement: Or-pattern combined coverage — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Or-Patterns

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — or-pattern coverage NEEDS TESTS
    • Ori Tests: tests/spec/patterns/match_or_patterns.ori
  • Implement: Or-pattern binding consistency — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Binding Rules

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — or-pattern bindings NEEDS TESTS
    • Ori Tests: tests/spec/patterns/match_or_patterns.ori
  • Implement: At-pattern coverage (same as inner) — proposals/approved/pattern-matching-exhaustiveness-proposal.md § At-Patterns

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — at-pattern coverage NEEDS TESTS
    • Ori Tests: tests/spec/patterns/match_at_patterns.ori
  • Implement: List pattern length coverage — proposals/approved/pattern-matching-exhaustiveness-proposal.md § List Patterns

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — list length coverage NEEDS PIN
    • Ori Tests: tests/spec/patterns/match_list_patterns.ori
  • Implement: Range pattern requires wildcard for integers — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Range Patterns

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — range coverage NEEDS TESTS
    • Ori Tests: tests/spec/patterns/match_range_patterns.ori

9.4.5 Unreachable Pattern Detection


  • Implement: Detect completely unreachable patterns (W0456) — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Unreachable Pattern Detection tests in exhaustiveness_fail.ori)

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — unreachable detection (redundant_arm test)
    • Ori Tests: tests/spec/patterns/exhaustiveness_fail.ori — 2 redundant pattern compile_fail tests
  • Implement: Detect overlapping range patterns (W0457) — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Range Overlap

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — range overlap detection
    • Ori Tests: tests/spec/patterns/match_range_overlap.ori
  • Implement: Suggest missing patterns in error messages — proposals/approved/pattern-matching-exhaustiveness-proposal.md § Error Messages

    • Rust Tests: ori_canon/src/exhaustiveness/tests.rs — suggestions NEEDS TESTS to verify message content
    • Ori Tests: tests/spec/patterns/match_exhaustive.ori
  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (9.4) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-9.4 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 9.4: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.

9.5 Named Variant Pattern Fields (Argument Punning)

Proposal: proposals/approved/argument-punning-proposal.md

Allow named field syntax in variant patterns, with punning when the binding variable matches the field name: Circle(radius:) for Circle(radius: radius).

type Shape = Circle(radius: float) | Rectangle(width: float, height: float)

// Before (positional only):
match shape {
    Circle(r) -> r * r * 3.14
    Rectangle(w, h) -> w * h
}

// After (named + punned):
match shape {
    Circle(radius:) -> radius * radius * 3.14
    Rectangle(width:, height:) -> width * height
}

Parser

  • Implement: Support name: and name: pattern in variant pattern fields

    • Rust Tests: ori_parse/src/grammar/pattern/tests.rs — named variant field parsing NEEDS TESTS
    • Ori Tests: tests/spec/patterns/variant_punning.ori — single/multi-field punning, Option, Result
  • Implement: Mixed named and positional fields in same variant pattern

    • Ori Tests: tests/spec/patterns/variant_punning_mixed.ori NEEDS TESTS
  • Implement: Positional variant patterns unchanged (no regression)

    • Ori Tests: tests/spec/patterns/variant_positional_regression.ori NEEDS TESTS

IR

  • Implement: Extend variant pattern representation to support named fields

    • Rust Tests: ori_ir/src/ast/pattern/tests.rs — named variant field IR NEEDS TESTS

Type Checker

  • Implement: Validate named fields match variant definition

    • Rust Tests: ori_types/src/check/ — variant field name validation NEEDS TESTS
    • Ori Tests: tests/compile-fail/variant_punning_unknown_field.ori NEEDS TESTS
  • Implement: Named fields can appear in any order

    • Ori Tests: tests/spec/patterns/variant_punning_reorder.ori NEEDS TESTS

Evaluator

  • Implement: Match named variant fields by name (reorder to definition order)

    • Rust Tests: ori_eval/src/interpreter/ — named variant field matching NEEDS TESTS
    • Ori Tests: tests/spec/patterns/variant_punning.ori

LLVM

  • Implement: LLVM codegen for named variant field patterns (REDUNDANT — likely works via ARC IR)

    • LLVM Rust Tests: ori_llvm/tests/aot/patterns.rs — named variant field codegen
    • AOT Tests: No AOT coverage yet INCOMPLETE MATRIX

Formatter

  • Implement: Detect name: name in variant patterns and emit name: form

    • Rust Tests: ori_fmt/src/formatter/ — variant pattern punning canonicalization

Documentation


  • Implement: Update spec 10-patterns.md with named variant field patterns
  • Implement: Update grammar.ebnf with variant_field production
  • Implement: Update .claude/rules/ori-syntax.md with pattern punning syntax [partial]
  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)
  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.
  • Subsection close-out (9.5) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-9.5 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 9.5: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.
  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.
  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.

9.6 Section Completion Checklist

Verification 2026-03-29: 6 implemented items were marked [ ] (now fixed to [x]). 17 stale path references fixed. 11 test gaps identified. 3 hygiene violations noted. Full test suite passes (4181 passed, 0 failed, 42 skipped). No bugs found.

  • All items above have all three checkboxes marked [ ]
  • Spec updated: spec/15-patterns.md reflects implementation
  • CLAUDE.md updated if syntax/behavior changed
  • 80+% test coverage
  • Run full test suite: ./test-all.sh
  • /tpr-review passed — independent Codex review found no critical or major issues (or all findings triaged)
  • /impl-hygiene-review passed — implementation hygiene review clean (phase boundaries, SSOT, algorithmic DRY, naming). MUST run AFTER /tpr-review is clean.
  • /improve-tooling retrospective completed — MANDATORY at section close, after both reviews are clean. Reflect on the section’s debugging journey (which diagnostics/ scripts you ran, which command sequences you repeated, where you added ad-hoc dbg!/tracing calls, where output was hard to interpret) and identify any tool/log/diagnostic improvement that would have made this section materially easier OR that would help the next section touching this area. Implement every accepted improvement NOW (zero deferral) and commit each via SEPARATE /commit-push. The retrospective is mandatory even when nothing felt painful — that is exactly when blind spots accumulate. See .claude/skills/improve-tooling/SKILL.md “Retrospective Mode” for the full protocol.

Test Gaps

  1. No Rust-level parser tests for pattern parsing (no tests.rs in grammar/expr/patterns/)
  2. No Ori tests using if guard syntax (all use legacy .match())
  3. No AOT test for direct variant pattern matching (Ok(v) -> ... not is_ok())
  4. No AOT test for struct pattern matching ({ x, y } -> ...)
  5. No AOT test for list pattern matching
  6. No AOT test for at-pattern matching
  7. No variant_punning_mixed.ori (mixed named/positional in patterns)
  8. No variant_punning_reorder.ori (reordered named fields)
  9. No variant_punning_positional_regression.ori (positional still works)
  10. No variant_punning_unknown_field.ori (compile-fail for bad field name)
  11. No dedicated test for or-pattern binding consistency across alternatives

Hygiene Violations

  1. STALE PATH (17 occurrences, FIXED): Roadmap referenced non-existent ori_types/src/check/exhaustiveness/tests.rs. Actual module at ori_canon/src/exhaustiveness/.
  2. REDUNDANT TRACKING: Each [x] pattern has [ ] LLVM Support + [ ] LLVM Rust Tests AND [x] AOT Tests pointing at same functionality. LLVM codegen works via ARC IR pipeline, not separate path.
  3. LEGACY SYNTAX IN SPEC TESTS: All guard tests in Ori spec files use .match(condition) syntax; approved if syntax only tested in AOT Rust tests.

Incomplete AOT Matrix

FeatureInterpreterAOTGap
List patterns5+ testsNoneAOT gap
At-patterns2 testsNoneAOT gap
Struct patterns5+ testsIndirect onlyAOT gap
Variant patterns (direct)5+ testsIndirect only (tag check)AOT gap
Range patterns (int)2 testsNoneAOT gap
Named variant fields5 testsNoneAOT gap

Exit Criteria: Match expressions work like spec

Verification Notes

  • 6 items marked [ ] were actually implemented (exhaustiveness) — fixed to [x].

  • CRITICAL: 17 stale path references fixed (ori_types/src/check/exhaustiveness/ -> ori_canon/src/exhaustiveness/).

  • Redundant LLVM Support/LLVM Rust Tests items noted (work via ARC IR pipeline, covered by AOT Tests).

  • 11 test gaps identified. Incomplete AOT matrix for list/struct/at/variant/range/named-field patterns.

  • 3 hygiene violations: stale paths (fixed), redundant LLVM items (noted), legacy guard syntax in spec tests.

  • Verified by: Claude Opus 4.6 (1M context)

  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (9.6) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-9.6 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 9.6: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.