Section 10: Control Flow
Goal: Complete control flow constructs
SPEC:
spec/14-expressions.md,spec/11-blocks-and-scope.md,spec/16-control-flow.md,spec/17-errors-and-panics.mdPROPOSALS:
proposals/approved/if-expression-proposal.md— Conditional expression semanticsproposals/approved/error-return-traces-proposal.md— Automatic error trace collectionproposals/approved/loop-expression-proposal.md— Loop expression semanticsproposals/approved/while-loop-proposal.md— While loop expression (sugar over loop)proposals/approved/labeled-block-early-exit-proposal.md— Labeled block early exit (break:label from blocks)
10.1 if Expression
Proposal: proposals/approved/if-expression-proposal.md
-
Implement: Parse
if cond then expr else expr— spec/14-expressions.md § Conditional [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser and evaluator — if expression
- Ori Tests:
tests/spec/expressions/conditionals.ori— 19 tests - LLVM Support: LLVM codegen for if expression
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— if expression codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/scoping.rs—test_scope_if_else_value,test_scope_if_else_computed,test_scope_nested_if_expression,test_scope_if_block_branches,test_scope_if_else_string_value,test_scope_let_each_branch(if-then-else as expression in value position)
-
Implement: Else-if chains (grammar convenience) — spec/14-expressions.md § Conditional [done] (2026-02-10) (verified 2026-03-29)
- Rust Tests: Parser — chained if parsing
- Ori Tests:
tests/spec/expressions/conditionals.ori - LLVM Support: LLVM codegen for chained conditions
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— chained conditions codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/scoping.rs—test_scope_nested_if_expression(else-if chain with 4 branches:x > 20,x > 10,x > 0, else)
-
Implement: Condition must be
bool— spec/14-expressions.md § Conditional [done] (2026-02-10) (verified 2026-03-29) WEAK TESTS — no#compile_failnegative test rejecting non-bool conditions- Rust Tests: Type checker — condition type checking
- Ori Tests:
tests/spec/expressions/conditionals.ori - LLVM Support: N/A (compile-time check)
- LLVM Rust Tests: N/A
-
Implement: Branch type unification — spec/14-expressions.md § Conditional [done] (2026-02-10) (verified 2026-03-29)
- Rust Tests: Type checker — branch type unification
- Ori Tests:
tests/spec/expressions/conditionals.ori - LLVM Support: LLVM codegen for branch type unification
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— branch type unification codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/scoping.rs—test_scope_if_else_value,test_scope_if_else_computed,test_scope_if_block_branches,test_scope_if_else_string_value,test_scope_let_each_branch(if-else branches producing same type: int, string, block values)
-
Implement: Without else: then-branch must be
voidorNever— spec/14-expressions.md § Conditional — BUG FOUND:if true then 42compiles silently (returns void) instead of producing a type error for non-void/non-Never then-branch without else- Rust Tests:
ori_types/src/infer/expr/mod.rs— void branch validation - Ori Tests:
tests/spec/expressions/conditionals.ori - LLVM Support: N/A (compile-time check)
- LLVM Rust Tests: N/A
- Rust Tests:
-
[partial] Implement: Never coercion in branches — spec/14-expressions.md § Conditional — interpreter handles Never coercion correctly (test_if_coercion in conditionals.ori passes), but no LLVM/AOT coverage
- Rust Tests:
ori_types/src/infer/expr/mod.rs— Never coercion (interpreter works) - Ori Tests:
tests/spec/expressions/conditionals.ori— test_if_coercion verifies Never coerces to int - LLVM Support: LLVM codegen for diverging branches
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— Never coercion codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Rust Tests:
-
[partial] Implement: Struct literal restriction in condition — spec/14-expressions.md § Conditional — parser has NO_STRUCT_LIT context flag (implementation exists), but no
#compile_failnegative test- Rust Tests:
ori_parse/src/grammar/expr.rs— struct literal exclusion (NO_STRUCT_LIT flag confirmed) - Ori Tests:
tests/compile-fail/if_struct_literal.ori[aspirational — file does not exist] - LLVM Support: N/A (parse-time check)
- LLVM Rust Tests: N/A
- Rust Tests:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (10.1) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, 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-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-10.1 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 10.1: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-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 --checkand clean any detected temp files.
10.2 for Expressions
NOTE: This is the
for x in items do/yield exprexpression syntax for iteration. Thefor(over:, match:, default:)pattern with named arguments is a separate construct in Section 8.
Imperative form (do):
-
Implement: Parse
for x in items do expr— spec/14-expressions.md § For Expressions [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser — for-do parsing
- Ori Tests:
tests/spec/expressions/loops.ori— 35 tests - LLVM Support: LLVM codegen for for-do expression
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— for-do codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/for_loops.rs—test_for_range_sum,test_for_range_inclusive,test_for_range_empty,test_for_list_sum,test_for_list_empty,test_for_str_count_chars,test_for_str_empty,test_for_option_some,test_for_option_none,test_for_map_sum,test_for_map_entries(for-do over Range, List, Str, Option, Map including empty iterables)
-
Implement: Bind loop variable — spec/14-expressions.md § For Expressions [done] (2026-02-10) (verified 2026-03-29)
- Rust Tests: Evaluator — loop variable binding
- Ori Tests:
tests/spec/expressions/loops.ori - LLVM Support: LLVM codegen for loop variable binding
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— loop variable binding codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/for_loops.rs—test_for_range_sum,test_for_range_with_guard,test_for_list_sum,test_for_list_with_guard,test_for_str_count_chars,test_for_str_char_values,test_for_option_some,test_for_map_sum(loop variable bound and used in body/guard across Range, List, Str, Option, Map)
-
Implement: Execute body for side effects — spec/14-expressions.md § For Expressions [done] (2026-02-10) (verified 2026-03-29)
- Rust Tests: Evaluator — body execution
- Ori Tests:
tests/spec/expressions/loops.ori - LLVM Support: LLVM codegen for loop body execution
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— loop body execution codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/for_loops.rs—test_for_range_sum,test_for_list_sum,test_for_str_count_chars,test_for_map_sum,test_for_map_entries(loop body executes for side effects across all iterable types),ori_llvm/tests/aot/mutations.rs—test_mut_loop_counter,test_mut_loop_accumulator,test_mut_loop_product,test_mut_loop_conditional_accumulator(loop body with accumulation patterns)
-
Implement: Result type
void— spec/14-expressions.md § For Expressions [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Type checker — for-do type
- Ori Tests:
tests/spec/expressions/loops.ori - LLVM Support: LLVM codegen for for-do void type
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— for-do void type codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/for_loops.rs—test_for_range_sum,test_for_list_sum,test_for_str_count_chars,test_for_option_some,test_for_option_none,test_for_map_sum(for-do expressions used for side effects, result discarded)
Collection building (yield):
-
Implement: Parse
for x in items yield expr— spec/14-expressions.md § For Expressions [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser — for-yield parsing
- Ori Tests:
tests/spec/expressions/loops.ori - LLVM Support: LLVM codegen for for-yield expression
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— for-yield codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/for_loops.rs—test_for_range_yield,test_for_list_yield,test_for_str_yield,test_for_option_yield_some,test_for_option_yield_none,test_for_map_yield,test_for_list_with_guard(for-yield over Range, List, Str, Option, Map)
-
Implement: Collect results into list — spec/14-expressions.md § For Expressions [done] (2026-02-10) (verified 2026-03-29)
- Rust Tests: Evaluator — yield collection
- Ori Tests:
tests/spec/expressions/loops.ori - LLVM Support: LLVM codegen for yield collection
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— yield collection codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/for_loops.rs—test_for_range_yield,test_for_list_yield,test_for_str_yield,test_for_option_yield_some,test_for_option_yield_none,test_for_map_yield(yield collects results into list across all iterable types)
-
Implement: Result type
[T]— spec/14-expressions.md § For Expressions [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Type checker — for-yield type
- Ori Tests:
tests/spec/expressions/loops.ori - LLVM Support: LLVM codegen for for-yield list type
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— for-yield list type codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/for_loops.rs—test_for_range_yield,test_for_list_yield,test_for_str_yield,test_for_option_yield_some,test_for_option_yield_none,test_for_map_yield(yield produces list, verified via.length())
With guards:
-
Implement: Parse
for x in items if guard yield expr— spec/14-expressions.md § For Expressions [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser — for-guard parsing
- Ori Tests:
tests/spec/expressions/loops.ori— for_do_with_guard, for_yield_with_guard tests - LLVM Support: LLVM codegen for for-guard expression
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— for-guard codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/for_loops.rs—test_for_range_with_guard,test_for_list_with_guard(for-if-do and for-if-yield guard parsing and execution)
-
Implement: Only yield when guard true — spec/14-expressions.md § For Expressions [done] (2026-02-10) (verified 2026-03-29)
- Rust Tests: Evaluator — guard filtering
- Ori Tests:
tests/spec/expressions/loops.ori— guard_all_filtered, guard_transform tests - LLVM Support: LLVM codegen for guard filtering
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— guard filtering codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/for_loops.rs—test_for_range_with_guard(range guard filtering),test_for_list_with_guard(list guard filtering with yield)
For-yield comprehensions (proposals/approved/for-yield-comprehensions-proposal.md):
-
Implement: Type inference for collection target — proposals/approved/for-yield-comprehensions-proposal.md § Type Inference
- Infer from context (
let list: [int] = for ...) - Default to list when no context
- Rust Tests:
ori_types/src/infer/expr/mod.rs— for-yield type inference - Ori Tests:
tests/spec/expressions/comprehensions.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for type-directed collection
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— comprehension type inference [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Infer from context (
-
Implement: Collect into any
Collect<T>type — proposals/approved/for-yield-comprehensions-proposal.md § Collect Target- Support
Set<T>collection - Support
{K: V}collection viaCollect<(K, V)> - Duplicate map keys overwrite earlier values
- Rust Tests:
ori_eval/src/interpreter/loops.rs— multi-target collection - Ori Tests:
tests/spec/expressions/comprehensions.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for multi-target collection
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— multi-target collection codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Support
-
Implement: Nested
forclauses — proposals/approved/for-yield-comprehensions-proposal.md § Nested Comprehensions- Parse
for x in xs for y in ys yield expr - Desugar to
flat_map - Support filters on each clause
- Rust Tests:
ori_parse/src/grammar/expr.rs— nested for parsing - Ori Tests:
tests/spec/expressions/comprehensions.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for nested comprehensions
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— nested comprehensions codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Parse
-
Implement: Break/continue in yield context — proposals/approved/for-yield-comprehensions-proposal.md § Break and Continue
-
continueskips current element -
continue valuesubstitutes value for yield expression -
breakstops iteration, collects results so far -
break valuestops and adds final value - Rust Tests:
ori_eval/src/interpreter/loops.rs— yield break/continue - Ori Tests:
tests/spec/expressions/comprehensions.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for yield break/continue
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— yield break/continue codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (10.2) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, 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-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-10.2 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 10.2: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-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 --checkand clean any detected temp files.
10.3 loop Expression
Proposal: proposals/approved/loop-expression-proposal.md
-
Implement: Parse
loop { body }— spec/14-expressions.md § Loop Expressions [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser — loop parsing
- Ori Tests:
tests/spec/expressions/loops.ori— loop_with_break, loop_break_value, loop_int tests - LLVM Support: LLVM codegen for loop expression
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— loop expression codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/mutations.rs—test_mut_loop_break,test_mut_while_pattern(loop expression with break and mutation)
-
Implement: Loop until
break— spec/16-control-flow.md § Break [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Evaluator — break handling
- Ori Tests:
tests/spec/expressions/loops.ori— loop_with_break test - LLVM Support: LLVM codegen for break handling
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— break handling codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/mutations.rs—test_mut_loop_break(loop until break),test_mut_while_pattern(Collatz loop with conditional break)
-
Implement: Body is a block expression
loop { ... }— proposals/approved/loop-expression-proposal.md § Body [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser — loop body parsing
- Ori Tests:
tests/spec/expressions/loops.ori— all loop tests useloop { ... } - LLVM Support: LLVM codegen for loop body
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— loop body codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/mutations.rs—test_mut_loop_break,test_mut_while_pattern(loop body with mutation, conditionals, and break)
-
Implement: Parse
breakwith optional value — spec/16-control-flow.md § Break [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser — break parsing
- Ori Tests:
tests/spec/expressions/loops.ori— loop_break_value, loop_conditional_break tests - LLVM Support: LLVM codegen for break with value
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— break with value codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/mutations.rs—test_mut_loop_break(break without value),test_mut_while_pattern(conditional break in loop)
-
Implement: Parse
continue— spec/16-control-flow.md § Continue [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser — continue parsing
- Ori Tests:
tests/spec/expressions/loops.ori— loop_continue test - LLVM Support: LLVM codegen for continue
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— continue codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
Implement:
continue valueerror in loop — proposals/approved/loop-expression-proposal.md § Continue With Value- Error E0861 when continue has value in loop context
- Helpful suggestion to use break or remove value
- Rust Tests:
ori_types/src/check/loops.rs— continue value validation - Ori Tests:
tests/compile-fail/loop_continue_value.ori[aspirational — file does not exist] - LLVM Support: N/A (compile-time check)
- LLVM Rust Tests: N/A
-
Implement: Result type from
breakvalue — proposals/approved/loop-expression-proposal.md § Loop Type [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Type checker — break type inference
- Ori Tests:
tests/spec/expressions/loops.ori— loop_break_value, loop_int tests - LLVM Support: LLVM codegen for break type inference
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— break type inference codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet (loop break-with-value returning typed result not directly tested)
-
Implement: Type
voidfor break without value — proposals/approved/loop-expression-proposal.md § Break Without Value [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Type checker — void loop type
- Ori Tests:
tests/spec/expressions/loops.ori— loop_with_break (void function) - LLVM Support: LLVM codegen for void loop
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— void loop codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/mutations.rs—test_mut_loop_break(loop with break, no value — void result type)
-
Implement: Type
Neverfor infinite loops — proposals/approved/loop-expression-proposal.md § Infinite Loop Type- Loop with no break has type Never
- Coerces to any type in value context
- Rust Tests:
ori_types/src/infer/expr/mod.rs— Never loop type - Ori Tests:
tests/spec/expressions/loops.ori - LLVM Support: LLVM codegen for Never loop
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— Never loop codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
Implement: Multiple break paths type unification — proposals/approved/loop-expression-proposal.md § Multiple Break Paths
- All breaks must have compatible types
- Error E0860 for type mismatch
- Rust Tests:
ori_types/src/infer/expr/mod.rs— break type unification - Ori Tests:
tests/compile-fail/loop_break_type_mismatch.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for break unification
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— break unification codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
Labeled loops:
-
Implement: Parse
loop:name { body }— spec/16-control-flow.md § Labeled Loops- Rust Tests:
ori_parse/src/grammar/expr.rs— labeled loop parsing - Ori Tests:
tests/spec/expressions/loops.ori - LLVM Support: LLVM codegen for labeled loop
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— labeled loop codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Parse
for:name x in items— spec/16-control-flow.md § Labeled Loops- Rust Tests:
ori_parse/src/grammar/expr.rs— labeled for parsing - Ori Tests:
tests/spec/expressions/loops.ori - LLVM Support: LLVM codegen for labeled for
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— labeled for codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Parse
break:nameandcontinue:name— spec/16-control-flow.md § Label Reference- Rust Tests:
ori_parse/src/grammar/expr.rs— label reference parsing - Ori Tests:
tests/spec/expressions/loops.ori - LLVM Support: LLVM codegen for label references
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— label references codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Rust Tests:
Labeled loop semantics (proposals/approved/labeled-loops-proposal.md):
-
Implement: Label scope rules — proposals/approved/labeled-loops-proposal.md § Label Scope
- Labels visible only within their loop body
- No language-imposed nesting depth limit
- Rust Tests:
ori_eval/src/interpreter/loops.rs— label scope validation - Ori Tests:
tests/spec/expressions/labeled_loops.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for label scope
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— label scope codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
Implement: No label shadowing — proposals/approved/labeled-loops-proposal.md § No Shadowing
- Error if label already in scope
- Error E0871 with helpful suggestion
- Rust Tests:
ori_types/src/check/labels.rs— shadowing detection - Ori Tests:
tests/compile-fail/labeled_loop_shadow.ori[aspirational — file does not exist] - LLVM Support: N/A (compile-time check)
- LLVM Rust Tests: N/A
-
Implement: Type consistency for
break:label value— proposals/approved/labeled-loops-proposal.md § Type Consistency- All break paths for a labeled loop must produce same type
- Error E0872 for type mismatch
- Rust Tests:
ori_types/src/infer/expr/mod.rs— break type unification - Ori Tests:
tests/compile-fail/labeled_break_type.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for typed break
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— typed break codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
Implement:
continue:label valuein for-yield — proposals/approved/labeled-loops-proposal.md § Continue With Value in For-Yield- Value type must match target loop’s yield element type
- Inner loop’s partial collection discarded
- Value contributed to outer loop’s collection
- Rust Tests:
ori_eval/src/interpreter/loops.rs— continue value in yield - Ori Tests:
tests/spec/expressions/labeled_loops.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for continue value
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— continue value codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
Implement:
continue:label valueerror in for-do — proposals/approved/labeled-loops-proposal.md § Continue With Value in For-Do- Error E0873 when continue has value in for-do context
- Helpful suggestion to use for-yield or remove value
- Rust Tests:
ori_types/src/check/loops.rs— continue value validation - Ori Tests:
tests/compile-fail/labeled_continue_in_do.ori[aspirational — file does not exist] - LLVM Support: N/A (compile-time check)
- LLVM Rust Tests: N/A
-
Implement: Undefined label error — proposals/approved/labeled-loops-proposal.md § Error Messages
- Error E0870 for undefined label
- Suggest similar labels if available
- Rust Tests:
ori_types/src/check/labels.rs— undefined label detection - Ori Tests:
tests/compile-fail/undefined_label.ori[aspirational — file does not exist] - LLVM Support: N/A (compile-time check)
- LLVM Rust Tests: N/A
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (10.3) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, 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-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-10.3 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 10.3: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-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 --checkand clean any detected temp files.
10.3B Labeled Block Early Exit
Proposal: proposals/approved/labeled-block-early-exit-proposal.md
block:name { ... break:name value ... } — early exit from named blocks without return. Extends the label system to plain blocks.
-
Implement: Add
blockas context-sensitive keyword — spec/07-lexical-elements.md § 7.3.3- Lexer: Recognize
blockas context-sensitive keyword inori_lexer/src/keywords/mod.rs - Rust Tests: Lexer keyword recognition test
- Ori Tests:
tests/spec/lexical/keywords.ori— verifyblockis context-sensitive (valid as identifier, keyword before:)
- Lexer: Recognize
-
Implement: Parse
block:name { body }— grammar.ebnf § labeled_block- Parser produces
ExprKind::LabeledBlock { label, body }(or desugars to labeled loop) -
blockrecognized only before:;blockas identifier still valid - Rust Tests:
ori_parse/src/grammar/expr.rs— labeled block parsing - Ori Tests:
tests/spec/expressions/labeled_blocks.ori[aspirational — file does not exist]
- Parser produces
-
Implement:
break:name valueexits labeled block — spec/16-control-flow.md § 16.3- All break paths and final expression must have compatible types
- Block type = unified type of all exit paths
- Rust Tests:
ori_types/src/infer/expr/mod.rs— labeled block type inference - Ori Tests:
tests/spec/expressions/labeled_blocks.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for labeled block break
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— labeled block codegen [aspirational — file does not exist]
-
Implement: Unlabeled
breakis loop-only — spec/16-control-flow.md § 16.2.1- Bare
breakinside a labeled block targets the innermost enclosing loop, not the block - Rust Tests:
ori_types/src/check/labels.rs— break target validation - Ori Tests:
tests/spec/expressions/labeled_blocks.ori[aspirational — file does not exist]
- Bare
-
Implement:
continue:block_labelis a compile-time error- Blocks do not iterate —
continuetargeting a block is invalid - Rust Tests:
ori_types/src/check/labels.rs— continue-block error - Ori Tests:
tests/compile-fail/labeled_block_continue.ori[aspirational — file does not exist]
- Blocks do not iterate —
-
Implement: Block labels share namespace with loop labels (no shadowing)
- A block label cannot shadow a loop label and vice versa
- Uses existing E0871 error
- Rust Tests:
ori_types/src/check/labels.rs— cross-construct shadowing - Ori Tests:
tests/compile-fail/labeled_block_shadow.ori[aspirational — file does not exist]
-
Implement: Nesting — labeled blocks can contain labeled blocks and labeled loops
-
break:outerfrom inner block/loop works correctly -
continue:loop_labelpasses through labeled blocks (transparent) - Rust Tests:
ori_eval/src/interpreter/mod.rs— nested labeled block evaluation - Ori Tests:
tests/spec/expressions/labeled_blocks.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for nested labeled blocks
- LLVM Rust Tests:
ori_llvm/tests/control_flow_tests.rs— nested labeled block codegen [aspirational — file does not exist]
-
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (10.3B) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, 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-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-10.3B retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 10.3B: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-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 --checkand clean any detected temp files.
10.3A while Expression
Proposal: proposals/approved/while-loop-proposal.md
Syntactic sugar: while condition do body desugars to loop { if !condition then break; body }. Always void type.
Sync Points: ExprKind::While (multi-crate sync required)
If while is represented as its own ExprKind::While variant (rather than desugared in the parser):
ori_ir— AddExprKind::While { condition, body, label }variantori_types— Type checking: condition must bebool, result type isvoid, handle E0860/E0861ori_eval— Evaluation: desugar to loop+break or direct while executionori_llvm— Codegen:brinstruction with condition check, loop body block, exit block
If desugared in the parser to loop { if !condition then break; body }, only steps 1-2 (parser + IR) are needed.
Implementation
-
Implement: Add
whileas reserved keyword — spec/07-lexical-elements.md § 7.3.1- Lexer: Add
whileto keyword lookup inori_lexer/src/keywords/mod.rs(5-char bucket) - Token: Add
KwWhilevariant toori_ir/src/token/tag.rs - Rust Tests: Lexer keyword recognition test
- Ori Tests:
tests/spec/lexical/keywords.ori— verifywhileis reserved
- Lexer: Add
-
Implement: Parse
while [label] expression do expression— spec/14-expressions.md § 14.12- Parser produces
ExprKind::While { condition, body, label } - Rust Tests:
ori_parse/src/grammar/expr.rs— while parsing - Ori Tests:
tests/spec/expressions/while_loop.ori[aspirational — file does not exist]
- Parser produces
-
Implement: Desugar to
loop { if !condition then break; body }— spec/16-control-flow.md § 16.2.4- Desugaring in parser or early lowering
- Rust Tests: Verify desugared form
- Ori Tests:
tests/spec/expressions/while_loop.ori[aspirational — file does not exist]
-
Implement: Type checking —
while...dohas typevoid-
break valuein while is error E0860 -
continue valuein while is error E0861 - Rust Tests:
ori_types— while type inference - Ori Tests:
tests/compile-fail/while_break_value.ori[aspirational — file does not exist],tests/compile-fail/while_continue_value.ori[aspirational — file does not exist]
-
-
Implement: Labels on while —
while:name condition do body-
break:nameandcontinue:namework correctly - Rust Tests: Parser — labeled while parsing
- Ori Tests:
tests/spec/expressions/while_loop.ori[aspirational — file does not exist]
-
-
Implement: LLVM codegen for while expression
- LLVM Rust Tests:
ori_llvm/tests/aot/while_loops.rs
- LLVM Rust Tests:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (10.3A) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, 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-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-10.3A retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 10.3A: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-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 --checkand clean any detected temp files.
10.4 Error Propagation (?)
-
Implement: Parse postfix
?operator — spec/16-control-flow.md § Error Propagation [done] (verified 2026-03-28) (verified 2026-03-29)- Rust Tests:
ori_parse/src/grammar/postfix.rs— ? operator parsing - Ori Tests:
tests/spec/expressions/postfix.ori[aspirational — file does not exist,?covered only by AOT tests] - LLVM Support: LLVM codegen for ? operator
- LLVM Rust Tests:
ori_llvm/tests/error_propagation_tests.rs— ? operator codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/error_handling.rs—test_err_try_result_ok,test_err_try_result_err,test_err_try_option_some,test_err_try_option_none(postfix?operator on both Result and Option)
- Rust Tests:
-
Implement: On
Result<T, E>: unwrapOkor returnErr— spec/16-control-flow.md § On Result [done] (verified 2026-03-28) (verified 2026-03-29)- Rust Tests:
ori_eval/src/interpreter/postfix.rs— Result propagation - Ori Tests:
tests/spec/expressions/postfix.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for Result propagation
- LLVM Rust Tests:
ori_llvm/tests/error_propagation_tests.rs— Result propagation codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/error_handling.rs—test_err_try_result_ok,test_err_try_result_err,test_err_try_result_chain,test_err_try_result_early_exit,test_err_deep_try_chain(?on Result unwrapping Ok, propagating Err, chaining, and early exit)
- Rust Tests:
-
Implement: On
Option<T>: unwrapSomeor returnNone— spec/16-control-flow.md § On Option [done] (verified 2026-03-28) (verified 2026-03-29)- Rust Tests:
ori_eval/src/interpreter/postfix.rs— Option propagation - Ori Tests:
tests/spec/expressions/postfix.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for Option propagation
- LLVM Rust Tests:
ori_llvm/tests/error_propagation_tests.rs— Option propagation codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/error_handling.rs—test_err_try_option_some,test_err_try_option_none(?on Option with Some and None paths)
- Rust Tests:
-
Implement: Only valid in functions returning
Result/Option— spec/16-control-flow.md § Error Propagation — NEEDS TESTS: status unknown whether type checker validates this context- Rust Tests:
ori_types/src/check/propagation.rs— context validation - Ori Tests:
tests/compile-fail/invalid_propagation.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for propagation context validation
- LLVM Rust Tests:
ori_llvm/tests/error_propagation_tests.rs— context validation codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Rust Tests:
Error Return Traces (proposals/approved/error-return-traces-proposal.md):
-
Implement: Automatic trace collection at
?propagation points-
?operator records source location (file, line, column, function name) - Trace entries stored internally in Error type
- Rust Tests:
ori_eval/src/interpreter/postfix.rs— trace collection - Ori Tests:
tests/spec/errors/trace_collection.ori[aspirational — file does not exist; tests/spec/errors/ directory does not exist] - LLVM Support: LLVM codegen for trace collection
- LLVM Rust Tests:
ori_llvm/tests/error_propagation_tests.rs— trace collection codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
-
Implement:
TraceEntrytype — proposals/approved/error-return-traces-proposal.md § Error Type Enhancement- Fields:
function: str,file: str,line: int,column: int - Rust Tests:
ori_ir/src/types/error.rs— TraceEntry type - Ori Tests:
tests/spec/errors/trace_entry.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for TraceEntry type
- LLVM Rust Tests:
ori_llvm/tests/error_propagation_tests.rs— TraceEntry type codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Fields:
-
Implement: Error trace methods — proposals/approved/error-return-traces-proposal.md § Accessing Traces
-
Error.trace() -> str— formatted trace string -
Error.trace_entries() -> [TraceEntry]— programmatic access -
Error.has_trace() -> bool— check if trace available - Rust Tests:
ori_eval/src/methods.rs— Error trace methods - Ori Tests:
tests/spec/errors/trace_methods.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for Error trace methods
- LLVM Rust Tests:
ori_llvm/tests/error_propagation_tests.rs— Error trace methods codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
-
Implement:
Printablefor Error includes trace — proposals/approved/error-return-traces-proposal.md § Printing Errors-
str(error)includes trace in output - Rust Tests:
ori_eval/src/methods.rs— Error printing - Ori Tests:
tests/spec/errors/trace_printing.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for Error printing with trace
- LLVM Rust Tests:
ori_llvm/tests/error_propagation_tests.rs— Error printing codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
-
Implement:
Result.context()method — proposals/approved/error-return-traces-proposal.md § Result Methods-
.context(msg: str)adds context while preserving trace - Rust Tests:
ori_eval/src/methods.rs— Result.context - Ori Tests:
tests/spec/errors/context_method.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for Result.context method
- LLVM Rust Tests:
ori_llvm/tests/error_propagation_tests.rs— Result.context codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
-
Implement:
Traceabletrait for built-in Error type — implemented in §3.13 (2026-02-17) (verified 2026-03-29)-
@with_trace(self, entry: TraceEntry) -> Self— push trace entry -
@trace(self) -> str— formatted trace string -
@trace_entries(self) -> [TraceEntry]— list of TraceEntry structs -
@has_trace(self) -> bool— check if trace exists - Note: Custom error types implementing Traceable is deferred (requires user-defined trait impls)
- LLVM Support: LLVM codegen for Traceable trait
- LLVM Rust Tests:
ori_llvm/tests/error_propagation_tests.rs— Traceable trait codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (10.4) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, 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-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-10.4 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 10.4: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-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 --checkand clean any detected temp files.
10.5 Let Bindings
-
Implement: Parse
let x = expr— spec/14-expressions.md § Let Bindings [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser and evaluator — let binding
- Ori Tests:
tests/spec/expressions/bindings.ori— 17 tests (let_inferred, let_string, etc.) - LLVM Support: LLVM codegen for let binding
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— let binding codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/scoping.rs—test_scope_let_basic,test_scope_let_type_annotation,test_scope_let_chain,test_scope_block_as_value,test_scope_block_single_expression,test_scope_block_with_side_effects(basic let bindings, chaining, and block-expression values)
-
Implement: Parse
let mut x = expr— spec/14-expressions.md § Mutable Bindings [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser and evaluator — mutable binding
- Ori Tests:
tests/spec/expressions/mutation.ori— 15 tests (mutable_basic, mutable_loop, etc.) - LLVM Support: LLVM codegen for mutable binding
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— mutable binding codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/mutations.rs—test_mut_simple_reassign,test_mut_reassign_multiple,test_mut_reassign_self_reference,test_mut_loop_counter,test_mut_loop_accumulator,test_mut_if_reassign,test_mut_if_else_reassign,test_mut_reassign_string,test_mut_reassign_bool,test_mut_swap_values,test_mut_fibonacci(21 tests covering mutable bindings in all contexts)
-
Implement: Parse
let x: Type = expr— spec/14-expressions.md § Let Bindings [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser and type checker — typed binding
- Ori Tests:
tests/spec/expressions/bindings.ori— let_annotated_int, let_annotated_str, etc. - LLVM Support: LLVM codegen for typed binding
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— typed binding codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/scoping.rs—test_scope_let_type_annotation(int, float, bool type-annotated let bindings)
-
Implement: Parse struct destructuring
let { x, y } = val— spec/14-expressions.md § Destructuring [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser — struct destructure parsing
- Ori Tests:
tests/spec/expressions/bindings.ori— struct_destructure_shorthand, struct_destructure_rename - LLVM Support: LLVM codegen for struct destructuring
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— struct destructuring codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
Implement: Parse tuple destructuring
let (a, b) = val— spec/14-expressions.md § Destructuring [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser — tuple destructure parsing
- Ori Tests:
tests/spec/expressions/bindings.ori— tuple_destructure test - LLVM Support: LLVM codegen for tuple destructuring
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— tuple destructuring codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/scoping.rs—test_scope_tuple_destructure(tuple destructuring in let binding)
-
Implement: Parse list destructuring
let [head, ..tail] = val— spec/14-expressions.md § Destructuring [done] (2026-02-10) (verified 2026-03-29)- Rust Tests: Parser — list destructure parsing
- Ori Tests:
tests/spec/expressions/bindings.ori— list_destructure_basic, list_destructure_head, list_destructure_with_rest - LLVM Support: LLVM codegen for list destructuring
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— list destructuring codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (10.5) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, 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-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-10.5 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 10.5: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-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 --checkand clean any detected temp files.
10.6 Scoping
-
Implement: Lexical scoping — spec/11-blocks-and-scope.md § Lexical Scoping [done] (2026-02-10) (verified 2026-03-29)
- Rust Tests: Evaluator — lexical scope tests
- Ori Tests:
tests/spec/expressions/block_scope.ori— 23 tests - LLVM Support: LLVM codegen for lexical scoping
- LLVM Rust Tests:
ori_llvm/tests/scope_tests.rs— lexical scoping codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/scoping.rs—test_scope_let_basic,test_scope_let_chain,test_scope_block_as_value,test_scope_nested_blocks_as_values,test_scope_shadow_in_nested_block,test_scope_shadow_three_levels,test_scope_shadow_in_loop(lexical scoping with blocks, nesting, and control flow)
-
Implement: No hoisting — spec/11-blocks-and-scope.md § No Hoisting [done] (2026-02-10) (verified 2026-03-29)
- Rust Tests: Evaluator — no hoisting tests
- Ori Tests:
tests/spec/expressions/block_scope.ori— sequential binding verified - LLVM Support: LLVM codegen for no hoisting
- LLVM Rust Tests:
ori_llvm/tests/scope_tests.rs— no hoisting codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/scoping.rs—test_scope_let_chain(sequential let bindings depend on previous values, verifying no hoisting)
-
Implement: Shadowing — spec/11-blocks-and-scope.md § Shadowing [done] (2026-02-10) (verified 2026-03-29)
- Rust Tests: Evaluator — shadowing tests
- Ori Tests:
tests/spec/expressions/bindings.ori— let_shadow, let_shadow_different_type;mutation.ori— shadow_mutability - LLVM Support: LLVM codegen for shadowing
- LLVM Rust Tests:
ori_llvm/tests/scope_tests.rs— shadowing codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/scoping.rs—test_scope_shadow_same_type,test_scope_shadow_different_type,test_scope_shadow_uses_previous,test_scope_shadow_in_nested_block,test_scope_shadow_three_levels,test_scope_many_lets_same_name,test_scope_string_shadow(same-type, cross-type, self-referential, and nested-block shadowing)
-
Implement: Lambda capture by value — spec/11-blocks-and-scope.md § Lambda Capture [done] (2026-02-10) (verified 2026-03-29)
- Rust Tests: Evaluator — capture tests
- Ori Tests:
tests/spec/expressions/lambdas.ori— 30 tests (closure_capture, closure_capture_multiple, closure_nested) - LLVM Support: LLVM codegen for lambda capture by value
- LLVM Rust Tests:
ori_llvm/tests/scope_tests.rs— lambda capture codegen [aspirational — file does not exist, covered by AOT tests] - AOT Tests:
ori_llvm/tests/aot/scoping.rs—test_scope_closure_captures_outer,test_scope_shadow_before_closure(closure capture by value),ori_llvm/tests/aot/higher_order.rs—test_hof_closure_capture_computation,test_hof_closure_capture_in_loop,test_hof_closure_bool_capture,test_hof_two_closures_same_capture,test_hof_nested_closure_deep,test_hof_make_adder,test_hof_make_multiplier,test_hof_make_predicate(closure captures and returns)
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (10.6) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, 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-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-10.6 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 10.6: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-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 --checkand clean any detected temp files.
10.7 Panics
-
[partial] Implement: Implicit panics (index out of bounds, division by zero) — spec/17-errors-and-panics.md § Implicit Panics — evaluator handles div-by-zero/index OOB panics, AOT has zero-step panic tests, but no dedicated panics.ori spec test
- Rust Tests:
ori_eval/src/interpreter/binary.rs— implicit panic tests (evaluator handles panics) - Ori Tests:
tests/spec/expressions/panics.ori[aspirational — file does not exist] - LLVM Support: LLVM codegen for implicit panics
- LLVM Rust Tests:
ori_llvm/tests/panic_tests.rs— implicit panics codegen [aspirational — file does not exist] - AOT Tests:
ori_llvm/tests/aot/for_loops.rs—test_for_range_zero_step_panics(3 tests for zero step panics)
- Rust Tests:
-
Implement:
panic(message)function — spec/17-errors-and-panics.md § Explicit Panic [done] (2026-02-10) (verified 2026-03-29) WRONG TEST REFERENCE CORRECTED: wascoalesce.oriwhich tests??operator, notpanic()- Rust Tests: Evaluator — panic function
- Ori Tests:
panic(msg:)is a prelude function used as helper in many test files;operators_bitwise.ori— assert_panics tests - LLVM Support: LLVM codegen for panic function
- LLVM Rust Tests:
ori_llvm/tests/panic_tests.rs— panic function codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
-
Implement:
catch(expr)pattern — spec/17-errors-and-panics.md § Catching Panics [done] (2026-02-19) (verified 2026-03-29)- Rust Tests:
ori_patterns/src/builtins/catch/tests.rs— catch_success, catch_error, name, required_props;ori_types/src/infer/expr/tests.rs— catch type inference - Ori Tests:
tests/spec/patterns/catch.ori— 7 tests: success, panic, message, div_zero, ok_value, string, nested - LLVM Support: LLVM codegen for catch pattern (simplified placeholder exists)
- LLVM Rust Tests:
ori_llvm/tests/panic_tests.rs— catch pattern codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement:
PanicInfotype — spec/17-errors-and-panics.md § PanicInfo- Rust Tests:
ori_ir/src/types/panic.rs— PanicInfo type tests - Ori Tests:
tests/spec/patterns/catch.ori - LLVM Support: LLVM codegen for PanicInfo type
- LLVM Rust Tests:
ori_llvm/tests/panic_tests.rs— PanicInfo type codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Rust Tests:
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (10.7) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, 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-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-10.7 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 10.7: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-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 --checkand clean any detected temp files.
10.8 Index Expressions — [partial] Evaluator Complete
- Implement:
#length symbol in index brackets (list[# - 1]) — spec/14-expressions.md § Index Access [done] (2026-02-10) (verified 2026-03-29)- Parser: Parse
#asExprKind::HashLengthinside[...]—ori_parse/src/grammar/expr/postfix.rs - Type Checker: Resolve
HashLengthto receiver’s length type (int) —ori_types/src/infer/ - Evaluator: Evaluate
HashLengthaslen(receiver)in index context —ori_eval/src/interpreter/mod.rs - ARC Lowering:
CanExpr::HashLengthresolves to storedhash_lengthvariable vialen()call — properly flows through to LLVM - Ori Tests:
tests/spec/expressions/index_access.ori— hash_last, hash_second_last, hash_first, hash_middle, hash_arithmetic (35 total tests) - LLVM Support: LLVM codegen for hash length in index — ARC lowering resolves HashLength to len() variable which flows through correctly
- LLVM Rust Tests:
ori_llvm/tests/collection_tests.rs— hash length codegen [aspirational — file does not exist] - AOT Tests: No AOT coverage yet
- Parser: Parse
Implementation Notes:
-
Added
IN_INDEXcontext flag toParseContext -
Parser recognizes
#(TokenKind::Hash) asExprKind::HashLengthonly inside index brackets -
Type checker and evaluator already had full support for
HashLength -
ARC lowering properly handles HashLength by resolving to a
len()call variable -
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — hygiene review clean. MUST run AFTER/tpr-reviewis clean. -
Subsection close-out (10.8) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, 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-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-10.8 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 10.8: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-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 --checkand clean any detected temp files.
10.9 Section Completion Checklist
- All items above have all three checkboxes marked
[ ] - Spec updated:
spec/14-expressions.md,spec/16-control-flow.mdreflect implementation - CLAUDE.md updated if syntax/behavior changed
- 80+% test coverage
- Run full test suite:
./test-all.sh -
/tpr-reviewpassed — independent Codex review found no critical or major issues (or all findings triaged) -
/impl-hygiene-reviewpassed — implementation hygiene review clean (phase boundaries, SSOT, algorithmic DRY, naming). MUST run AFTER/tpr-reviewis clean. -
/improve-toolingretrospective completed — MANDATORY at section close, after both reviews are clean. Reflect on the section’s debugging journey (whichdiagnostics/scripts you ran, which command sequences you repeated, where you added ad-hocdbg!/tracingcalls, 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. - NEGATIVE TESTS GAP: Add
#compile_failnegative tests for control flow features (zero exist as of 2026-03-29) — non-bool condition, branch type mismatch, non-void if-without-else, break type mismatch in loop, continue-with-value in loop,?in non-Result/Option function
Exit Criteria: All control flow constructs work including labeled loops, scoping, and panic handling
-
/tpr-reviewpassed — independent review found no critical or major issues (or all findings triaged) - Subsection close-out (10.9) — MANDATORY before starting the next subsection. Run
/improve-toolingretrospectively on THIS subsection’s debugging journey (per.claude/skills/improve-tooling/SKILL.md“Per-Subsection Workflow”): whichdiagnostics/scripts you ran, where you addeddbg!/tracingcalls, 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-pushusing a valid conventional-commit type (build(diagnostics): ... — surfaced by section-10.9 retrospective—build/test/chore/ci/docsare valid;tools(...)is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 10.9: no tooling gaps”. Update this subsection’sstatusin section frontmatter tocomplete. -
/sync-claudesection-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 --checkand clean any detected temp files.
Verification Notes (2026-03-29)
BUG: if true then 42 compiles silently (returns void) instead of producing a type error for non-void/non-Never then-branch without else. infer_if() returns Idx::UNIT regardless of then-branch type when else is absent. Per spec (14-expressions.md Conditional), non-void/non-Never then-branches without else should produce a type error.
Stale data corrected: loops.ori 29->35 tests, block_scope.ori 3->23 tests, lambdas.ori 29->30 tests. Three [ignored] markers on scoping AOT tests removed (all pass). HashLength LLVM placeholder note removed (ARC lowering properly handles it). Wrong test reference on panic(message) corrected (was coalesce.ori which tests ??, not panic).
Status changes: 4 items changed from [ ] to [partial] — Never coercion in branches (10.1), struct literal restriction (10.1), implicit panics (10.7), all have partial implementation but missing tests.
Critical gap: ZERO #compile_fail negative tests exist for any control flow feature. 5 LLVM unit test files referenced in roadmap are aspirational (do not exist) — covered by AOT integration tests instead. 23 referenced test files total do not exist (annotated as aspirational).
Verification Stats
- total_items: 82
- verified: 40
- correct_unchecked: 35
- should_be_partial: 4
- stale_data: 6
- wrong_test_ref: 1
- bugs_found: 1
- negative_test_gap: ZERO
#compile_failnegative tests for any control flow feature