Section 15D: Bindings & Types
Goal: Implement binding syntax changes and type system simplifications
Source:
docs/ori_lang/proposals/approved/
15D.1 Function-Level Contracts: pre() / post()
Proposal: proposals/approved/checks-proposal.md (semantics), proposals/approved/block-expression-syntax.md (syntax)
Function-level pre() and post() contract declarations for defensive programming. Contracts go between the return type and =:
@divide (a: int, b: int) -> int
pre(b != 0)
post(r -> r * b <= a)
= a div b
// Multiple conditions
@transfer (from: Account, to: Account, amount: int) -> (Account, Account)
pre(amount > 0 | "amount must be positive")
pre(from.balance >= amount | "insufficient funds")
post((f, t) -> f.balance == from.balance - amount)
post((f, t) -> t.balance == to.balance + amount)
= {
// ... body ...
}
Key Design Decisions
- Function-level placement: Contracts go on the declaration between return type and
= - Multiple declarations: Use multiple
pre()/post()declarations (not list syntax) |for messages: Custom messages usecondition | "message"syntax- Scope constraints:
pre()can only access function parameters and module-level bindings;post()can access the result via lambda parameter - Void return: Compile error if
post()used on a function returningvoid - Check modes deferred:
check_mode:(enforce/observe/ignore) deferred to future proposal
Implementation
-
Implement: Parser: Parse
pre()andpost()on function declarations (verified 2026-03-29)-
ori_parse/src/grammar/item/function/mod.rs—parse_contracts()at line 221 returns(Vec<PreContract>, Vec<PostContract>). Contracts parsed between return type and=. - AST:
PreContract { condition, message, span }andPostContract { param, condition, message, span }inori_ir/src/ast/items/function.rs.FunctionDefhaspre_contractsandpost_contractsfields. - Rust Tests: NEEDS TESTS — parser is implemented but no dedicated parser test exists
- Ori Tests:
tests/spec/patterns/checks.ori— not yet created - LLVM Support: NOT DONE
- AOT Tests: No AOT coverage yet
-
-
Implement: Parser: Support
| "message"custom message syntax (verified 2026-03-29)-
PreContracthasmessage: Option<ExprId>.PostContracthasmessage: Option<ExprId>. Parser handles|separator. - Rust Tests: NEEDS TESTS — parsing works but no tests
- Ori Tests:
tests/spec/patterns/check_messages.ori— not yet created - LLVM Support: NOT DONE
- AOT Tests: No AOT coverage yet
-
-
Implement: Type checker: Validate
pre()condition isbool- Rust Tests:
ori_types/src/check/function.rs— pre type validation - Ori Tests:
tests/compile-fail/checks/pre_not_bool.ori - LLVM Support: LLVM codegen for pre type validation
- LLVM Rust Tests:
ori_llvm/tests/syntax_tests.rs— pre type validation codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Type checker: Validate
post()isT -> boollambda- Rust Tests:
ori_types/src/check/function.rs— post type validation - Ori Tests:
tests/compile-fail/checks/post_not_lambda.ori - LLVM Support: LLVM codegen for post type validation
- LLVM Rust Tests:
ori_llvm/tests/syntax_tests.rs— post type validation codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Type checker: Error when
post()used on void-returning function- Rust Tests:
ori_types/src/check/function.rs— void return error - Ori Tests:
tests/compile-fail/checks/post_void_return.ori - LLVM Support: LLVM codegen for void return error
- LLVM Rust Tests:
ori_llvm/tests/syntax_tests.rs— void return error codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Scope checker:
pre()can only access parameters and module-level bindings- Rust Tests:
ori_types/src/check/scope.rs— pre scope validation - Ori Tests:
tests/compile-fail/checks/pre_scope.ori - LLVM Support: LLVM codegen for pre scope validation
- LLVM Rust Tests:
ori_llvm/tests/syntax_tests.rs— pre scope validation codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Codegen: Desugar to conditional checks and panics at function entry/exit
- Rust Tests:
ori_types/src/check/checks.rs— contract desugaring - Ori Tests:
tests/spec/patterns/checks_desugaring.ori - LLVM Support: LLVM codegen for contract desugaring
- LLVM Rust Tests:
ori_llvm/tests/syntax_tests.rs— contract desugaring codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Codegen: Embed source text for default error messages
- Rust Tests:
ori_types/src/check/checks.rs— source text embedding - Ori Tests:
tests/spec/patterns/checks_error_messages.ori - LLVM Support: LLVM codegen for source text embedding
- LLVM Rust Tests:
ori_llvm/tests/syntax_tests.rs— source text embedding codegen - 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 (15D.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-15D.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 15D.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.
15D.2 as Conversion Syntax
Proposal: proposals/approved/as-conversion-proposal.md
Replace int(), float(), str(), byte() with as/as? keyword syntax backed by As<T> and TryAs<T> traits.
LLVM/AOT GAP (verified 2026-03-29):
as/as?works in the interpreter but is broken in AOT compilation.lower_cast()inori_arc/src/lower/collections/mod.rsemitsApply(dst, __cast, [val])but__castis NOT a registered protocol builtin and is NOT handled by the LLVM ARC emitter. AOT compilation will fail at link time or crash at runtime.
TEST COVERAGE GAP (verified 2026-03-29):
tests/spec/expressions/type_conversion.oricontains comprehensive test cases foras/as?but ALL tests are commented out. Zero active tests for this feature.
// Before (special-cased positional args)
let x = int("42")
let y = float(value)
// After (consistent keyword syntax)
let x = "42" as? int
let y = value as float
Lexer
- Implement:
askeyword token (verified 2026-03-29)-
TokenKind::Asinori_lexer/src/keywords/mod.rsline 50. Test at line 183 confirms. - LLVM Support: N/A — lexer token, not codegen
- AOT Tests: No AOT coverage yet
-
Parser
-
Implement: Parse
expression as Typeas conversion expression (verified 2026-03-29)-
ori_parse/src/grammar/expr/postfix.rsline 120 checks forTokenKind::As. ProducesExprKind::Cast { expr, ty, fallible: false }. - LLVM Support: LLVM codegen for as expression — BROKEN (see LLVM/AOT GAP above)
- AOT Tests: No AOT coverage yet
-
-
Implement: Parse
expression as? Typeas fallible conversion (verified 2026-03-29)- Same parser function checks for
?afterasto setfallible: true. - LLVM Support: LLVM codegen for as? expression — BROKEN (see LLVM/AOT GAP above)
- AOT Tests: No AOT coverage yet
- Same parser function checks for
Type Checker
-
Implement: Type resolution for
ascasts (verified 2026-03-29)-
infer_cast()inori_types/src/infer/expr/operators.rsline 466 resolves target type and returns it. - [partial] Trait-based validation (
As<T>) NOT implemented — any type can be cast to any type at typeck level. Runtime catches invalid casts.
-
-
Implement: Validate
asonly used withAs<T>trait implementations- Ori Tests:
tests/compile-fail/as_not_implemented.ori
- Ori Tests:
-
Implement: Validate
as?only used withTryAs<T>trait implementations- Ori Tests:
tests/compile-fail/try_as_not_implemented.ori
- Ori Tests:
-
Implement: Error when using
asfor fallible conversion (must useas?)- Ori Tests:
tests/compile-fail/as_fallible_conversion.ori
- Ori Tests:
Codegen (Evaluator)
- Implement: Evaluate
x as Twith hardcoded primitive conversion logic (verified 2026-03-29)-
eval_can_cast()atori_eval/src/interpreter/can_eval/operators.rsline 119 handles: int->float, int->byte (range checked), int->char, float->int, byte->int, char->int, str->int (fallible), str->float (fallible), str->bool (fallible). - NOT via trait dispatch — hardcoded conversion logic. Works correctly for all primitive conversions.
-
- Implement: Evaluate
x as? Twith fallible flag (verified 2026-03-29)- Same code path with
fallibleflag. ReturnsNoneon failure.
- Same code path with
Codegen (LLVM/AOT)
- Implement: Register
__castas protocol builtin inori_ir/src/builtin_constants/protocol/and handle in LLVM ARC emitter with appropriate LLVM cast instructions (sitofp, fptosi, trunc, zext)- LLVM Rust Tests:
ori_llvm/tests/aot/conversions.rs— as/as? codegen - AOT Tests: No AOT coverage yet
- LLVM Rust Tests:
Migration
-
Implement: Remove
int(),float(),str(),byte()from parser -
Implement: Update error messages to suggest
assyntax -
/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 (15D.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-15D.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 15D.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.
15D.3 Simplified Bindings with $ for Immutability
Proposal: proposals/approved/simplified-bindings-proposal.md
Simplify the binding model: let x is mutable, let $x is immutable. Remove mut keyword. Module-level bindings require $ prefix.
// Before
let x = 5 // immutable
let mut x = 5 // mutable
$timeout = 30s // config variable
// After
let x = 5 // mutable
let $x = 5 // immutable
let $timeout = 30s // module-level constant (let and $ required)
Lexer
- Implement: Remove
mutfrom reserved keywords (verified 2026-03-29)- No
mutinori_lexer/src/keywords/mod.rs. NoKwMuttoken. Fully removed. - LLVM Support: N/A — lexer keyword removal, not codegen
- No
Parser
-
Implement: Update
let_exprto accept$prefix in binding pattern (2026-02-20)- Rust Tests:
ori_parse/src/tests/parser.rs— block let binding with$prefix - Ori Tests:
tests/spec/expressions/immutable_bindings.ori - LLVM Support: LLVM codegen for immutable binding parsing
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— immutable binding parsing codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Remove
mutfromlet_exprgrammar- Rust Tests:
ori_parse/src/grammar/expr.rs— mut removal - Ori Tests: All 151
let mutoccurrences migrated toletacross 25 test files + AOT tests - LLVM Support: LLVM codegen for mut removal
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— mut removal codegen - AOT Tests:
ori_llvm/tests/aot/mutations.rs— all 21 tests uselet x(mutable-by-default) with reassignment, confirming mut removal works end-to-end in AOT
- Rust Tests:
-
Implement: Update
constant_declto requirelet $name = expr- Rust Tests:
ori_parse/src/grammar/decl.rs— constant declaration parsing - Ori Tests:
tests/spec/declarations/constants.ori - LLVM Support: LLVM codegen for constant declaration
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— constant declaration codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Remove old const function syntax
$name (params) -> Type- Rust Tests:
ori_parse/src/grammar/decl.rs— const function removal - Ori Tests:
tests/compile-fail/old_const_function_syntax.ori - LLVM Support: LLVM codegen for const function removal
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— const function removal codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Support
$prefix in destructuring patterns (2026-02-20)- Rust Tests:
ori_parse/src/grammar/expr/primary.rs—parse_binding_patternhandles$for Name, Tuple, Struct, List - Ori Tests:
tests/spec/expressions/immutable_bindings.ori— tuple, struct, list destructuring with$ - LLVM Support: LLVM codegen for destructure immutable
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— destructure immutable codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Fix: List rest binding
..resttracks$mutability (2026-02-20)- IR:
BindingPattern::List.restchanged fromOption<Name>toOption<(Name, bool)>(ori_ir/src/ast/patterns/binding.rs:31) - IR:
CanBindingPattern::List.restchanged toOption<(Name, bool)>(ori_ir/src/canon/patterns.rs:32) - Parser:
parse_binding_patternhandles$before rest identifier (ori_parse/src/grammar/expr/primary.rs:1386) - Type checker:
bind_pattern()usesbind_with_mutability()for rest (ori_types/src/infer/expr/sequences.rs:489) - Evaluator:
bind_can_pattern()uses per-bindingrest_mutable(ori_eval/src/interpreter/can_eval.rs:758) - Canon: lowering passes through
(Name, bool)tuple (ori_canon/src/lower/patterns.rs:261) - Formatter: emits
$prefix on immutable rest bindings (ori_fmt/src/formatter/patterns.rs:183) - Grammar:
grammar.ebnfupdated to allow[ "$" ]on rest identifier (line 581)
- IR:
Semantic Analysis
-
Implement: Track
$modifier separately from identifier name (2026-02-20)- Rust Tests:
ori_types/src/infer/env/mod.rs—TypeEnvInner::mutabilityFxHashMap tracks per-binding mutability - Ori Tests:
tests/spec/expressions/mutable_vs_immutable.ori— verifies$bindings preserve immutability - LLVM Support: N/A — mutability is a type-checker concern, not codegen
- LLVM Rust Tests: N/A — mutability is a type-checker concern, not codegen
- Rust Tests:
-
Implement: Prevent
$xandxcoexisting in same scope- Rust Tests:
ori_types/src/check/binding.rs— same-name conflict detection - Ori Tests:
tests/compile-fail/dollar_and_non_dollar_conflict.ori - LLVM Support: LLVM codegen for same-name conflict detection
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— same-name conflict detection codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Enforce module-level bindings require
$prefix- Rust Tests:
ori_types/src/check/module.rs— module binding immutability - Ori Tests:
tests/compile-fail/module_level_mutable.ori - LLVM Support: LLVM codegen for module binding immutability
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— module binding immutability codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Enforce
$-prefixed bindings cannot be reassigned (2026-02-20)- Rust Tests:
ori_types/src/infer/expr/operators.rs— immutability check ininfer_assign - Ori Tests:
tests/compile-fail/assign_to_immutable.ori,assign_to_immutable_in_loop.ori,assign_to_immutable_destructured.ori - LLVM Support: N/A — compile-time type error (E2039) prevents codegen
- LLVM Rust Tests: N/A — compile-time type error prevents codegen
- Rust Tests:
Imports
-
Implement: Require
$in import statements for immutable bindings- Rust Tests:
ori_types/src/check/import.rs— import with dollar - Ori Tests:
tests/spec/modules/import_immutable.ori - LLVM Support: LLVM codegen for import with dollar
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— import with dollar codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Error when importing
$xasxor vice versa- Rust Tests:
ori_types/src/check/import.rs— import modifier mismatch - Ori Tests:
tests/compile-fail/import_dollar_mismatch.ori - LLVM Support: LLVM codegen for import modifier mismatch
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— import modifier mismatch codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
Shadowing
- Implement: Allow shadowing to change mutability
- Rust Tests:
ori_types/src/check/binding.rs— shadowing mutability change - Ori Tests:
tests/spec/expressions/shadow_mutability.ori - LLVM Support: LLVM codegen for shadowing mutability change
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— shadowing mutability change codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
Error Messages
-
Implement: Clear error for reassignment to immutable binding (2026-02-20)
- Rust Tests:
ori_types/src/type_error/check_error/mod.rs—AssignToImmutablevariant + formatting - Ori Tests:
tests/compile-fail/assign_to_immutable.ori(verifies “cannot assign to immutable binding” message) - LLVM Support: N/A — compile-time type error prevents codegen
- LLVM Rust Tests: N/A — compile-time type error prevents codegen
- Rust Tests:
-
Implement: Clear error for module-level mutable binding
- Rust Tests:
ori_diagnostic/src/problem.rs— module mutable error - Ori Tests:
tests/compile-fail/module_mutable_message.ori - LLVM Support: LLVM codegen for module mutable error
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— module mutable error codegen - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Migration hint for old
let mutsyntax- Rust Tests:
ori_diagnostic/src/problem.rs— let mut migration hint - Ori Tests:
tests/compile-fail/let_mut_migration.ori - LLVM Support: LLVM codegen for let mut migration hint
- LLVM Rust Tests:
ori_llvm/tests/binding_tests.rs— let mut migration hint codegen - 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 (15D.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-15D.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 15D.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.
15D.4 Remove dyn Keyword for Trait Objects
Proposal: proposals/approved/remove-dyn-keyword-proposal.md
Remove the dyn keyword for trait objects. Trait names used directly as types mean “any value implementing this trait.”
// Before
@process (item: dyn Printable) -> void = ...
let items: [dyn Serializable] = ...
// After
@process (item: Printable) -> void = ...
let items: [Serializable] = ...
Implementation
-
Implement: Remove
"dyn" typefrom grammar type production- Rust Tests:
ori_parse/src/grammar/ty.rs— dyn removal tests - Ori Tests:
tests/spec/types/trait_objects.ori - LLVM Support: LLVM codegen for trait objects without dyn
- LLVM Rust Tests:
ori_llvm/tests/trait_object_tests.rs - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Parser recognizes trait name in type position as trait object
- Rust Tests:
ori_parse/src/grammar/ty.rs— trait-as-type parsing - Ori Tests:
tests/spec/types/trait_objects.ori - LLVM Support: LLVM codegen for trait-as-type
- LLVM Rust Tests:
ori_llvm/tests/trait_object_tests.rs - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Type checker distinguishes
item: Trait(trait object) vs<T: Trait>(generic bound)- Rust Tests:
ori_types/src/check/trait_objects.rs - Ori Tests:
tests/spec/types/trait_vs_bound.ori - LLVM Support: LLVM codegen for trait object vs bound distinction
- LLVM Rust Tests:
ori_llvm/tests/trait_object_tests.rs - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Object safety validation with clear error messages
- Rust Tests:
ori_types/src/check/object_safety.rs - Ori Tests:
tests/compile-fail/non_object_safe_trait.ori - LLVM Support: LLVM codegen for object safety validation
- LLVM Rust Tests:
ori_llvm/tests/trait_object_tests.rs - AOT Tests: No AOT coverage yet
- Rust Tests:
-
Implement: Error if
dynkeyword is used (helpful migration message)- Rust Tests:
ori_parse/src/grammar/ty.rs— dyn keyword error - Ori Tests:
tests/compile-fail/dyn_keyword_removed.ori
- 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 (15D.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-15D.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 15D.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.
15D.5 Index and Field Assignment
Proposal: proposals/approved/index-assignment-proposal.md
Supersedes: bug-tracker/section-04-codegen-llvm.md::BUG-04-070 (E4003 ARC-lowering symptom), bug-tracker/section-07-tooling-cli.md::BUG-07-016 (typeck-layer naming of the same fix). Both bugs are symptoms of the unimplemented typeck.md §EX-17 desugar; §15D.5’s 5-phase plan IS the fix.
Extend assignment targets to support index expressions (list[i] = x), field access (state.name = x), mixed chains (state.items[i] = x, list[i].name = x), and compound assignment on all forms (list[i] += 1). All forms desugar to copy-on-write reassignment via IndexSet trait (for index) or struct spread (for fields).
let list = [1, 2, 3]
list[0] = 10 // list = list.updated(key: 0, value: 10)
let state = GameState { score: 0, level: 1 }
state.score = 100 // state = { ...state, score: 100 }
state.items[i] = new_item // mixed chain
list[i].name = "new" // index then field
list[0] += 5 // compound: list[0] = list[0] + 5
Phase 1: IndexSet Trait and updated Method
-
Implement: Define
IndexSet<Key, Value>trait in prelude —@updated (self, key: Key, value: Value) -> Self- Rust Tests:
ori_types/src/infer/— IndexSet trait resolution - Ori Tests:
tests/spec/traits/index_set/basic.ori
- Rust Tests:
-
Implement: Register
updatedas built-in method on[T],{K: V},[T, max N]in evaluator- Rust Tests:
ori_eval/src/method_dispatch/— updated method dispatch - Ori Tests:
tests/spec/traits/index_set/updated_method.ori
- Rust Tests:
-
Implement:
updatedwith ARC-aware copy-on-write inori_patterns/ori_eval- Rust Tests:
ori_patterns/src/value/— copy-on-write behavior - Ori Tests:
tests/spec/traits/index_set/cow_behavior.ori
- Rust Tests:
Phase 2: Parser Changes
-
Implement: Extend parser to accept
assignment_target(identifier + index/field chains) on LHS of=and compound operators- Rust Tests:
ori_parse/src/grammar/expr/— assignment target parsing - Ori Tests:
tests/spec/expressions/index_assignment_syntax.ori
- Rust Tests:
-
Implement: Emit AST node capturing chain of index/field accesses in assignment target
- Rust Tests:
ori_ir/src/ast/expr.rs— AssignTarget AST node - Ori Tests:
tests/spec/expressions/field_assignment_syntax.ori
- Rust Tests:
Phase 3: Type-Directed Desugaring
-
Implement: Desugar
[key]steps toupdated()calls (requiresIndexSettrait resolution)- Rust Tests:
ori_types/src/infer/expr/— index assignment desugaring - Ori Tests:
tests/spec/expressions/index_assignment_desugar.ori
- Rust Tests:
-
Implement: Desugar
.fieldsteps to struct spread reconstruction (requires struct type info)- Rust Tests:
ori_types/src/infer/expr/— field assignment desugaring - Ori Tests:
tests/spec/expressions/field_assignment_desugar.ori
- Rust Tests:
-
Implement: Handle nested cases, mixed field-index chains, and compound assignment
- Rust Tests:
ori_types/src/infer/expr/— mixed chain desugaring - Ori Tests:
tests/spec/expressions/mixed_chain_assignment.ori
- Rust Tests:
Phase 4: Type Checker Integration
-
Implement: Validate mutability of root binding (not
$, not parameter, not loop variable)- Rust Tests:
ori_types/src/infer/expr/— mutability validation - Ori Tests:
tests/spec/expressions/assignment_mutability.ori
- Rust Tests:
-
Implement: Validate field names against struct types in assignment chains
- Rust Tests:
ori_types/src/infer/expr/— field validation - Ori Tests:
tests/compile-fail/assignment/invalid_field.ori
- Rust Tests:
-
Implement: Validate key and value types against
IndexSetimpl- Rust Tests:
ori_types/src/infer/expr/— IndexSet type validation - Ori Tests:
tests/compile-fail/assignment/type_mismatch.ori
- Rust Tests:
-
Implement: Emit diagnostics for all error cases (immutable binding, parameter, loop var, missing IndexSet, field mismatch, type mismatch)
- Rust Tests:
ori_diagnostic/— assignment error diagnostics - Ori Tests:
tests/compile-fail/assignment/all_errors.ori
- Rust Tests:
Phase 5: LLVM Support
-
LLVM Support: LLVM codegen for index assignment desugaring
- LLVM Rust Tests:
ori_llvm/tests/— index assignment codegen - AOT Tests: No AOT coverage yet
- LLVM Rust Tests:
-
LLVM Support: LLVM codegen for field assignment desugaring
- LLVM Rust Tests:
ori_llvm/tests/— field assignment codegen - AOT Tests: No AOT coverage yet
- LLVM Rust Tests:
-
LLVM Support: LLVM codegen for compound assignment on extended targets
- LLVM Rust Tests:
ori_llvm/tests/— compound assignment codegen - AOT Tests: No AOT coverage yet
- 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 (15D.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-15D.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 15D.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.
15D.6 Mutable Self
Proposal: proposals/approved/mutable-self-proposal.md
Make self a mutable binding in method bodies with implicit mutation propagation back to the caller. Extends the existing field/index assignment desugaring pattern to method calls.
impl Cursor {
@advance (self) -> void = {
self.pos += 1
}
}
cursor.advance() // cursor is updated via desugaring
Phase 1: Self Mutability
-
Implement: Make
selfa mutable binding in method bodies (type checker)- Rust Tests:
ori_types/src/infer/— self mutability in methods - Ori Tests:
tests/spec/methods/mutable_self_basic.ori
- Rust Tests:
-
Implement: Mutation detection dataflow analysis (classify methods as mutating/non-mutating)
- Rust Tests:
ori_types/src/infer/— mutation classification - Ori Tests:
tests/spec/methods/mutation_detection.ori
- Rust Tests:
Phase 2: Call-Site Desugaring
-
Implement: Void-returning mutating methods desugar to
-> Self+ implicit reassignment- Rust Tests:
ori_types/src/infer/expr/— void method desugaring - Ori Tests:
tests/spec/methods/mutable_self_void.ori
- Rust Tests:
-
Implement: Value-returning mutating methods desugar to
-> (Self, T)+ tuple split- Rust Tests:
ori_types/src/infer/expr/— value method desugaring - Ori Tests:
tests/spec/methods/mutable_self_value_return.ori
- Rust Tests:
-
Implement: No desugaring for
-> Selfmethods (already return Self)- Rust Tests:
ori_types/src/infer/expr/— Self return carve-out - Ori Tests:
tests/spec/methods/mutable_self_returns_self.ori
- Rust Tests:
-
Implement: Nested field mutation cascading (
self.inner.advance())- Rust Tests:
ori_types/src/infer/expr/— nested mutation desugaring - Ori Tests:
tests/spec/methods/mutable_self_nested.ori
- Rust Tests:
Phase 3: Caller Validation
-
Implement: Error when calling mutating method on immutable (
$) binding- Rust Tests:
ori_types/src/infer/expr/— immutable receiver error - Ori Tests:
tests/compile-fail/methods/mutating_on_immutable.ori
- Rust Tests:
-
Implement: Diagnostics for mutation-related errors
- Rust Tests:
ori_diagnostic/— mutation error diagnostics - Ori Tests:
tests/compile-fail/methods/mutation_errors.ori
- Rust Tests:
Phase 4: Trait Integration
-
Implement: Infer mutation classification across trait implementations
- Rust Tests:
ori_types/src/infer/— trait mutation consistency - Ori Tests:
tests/spec/traits/mutable_self_trait.ori
- Rust Tests:
-
Implement: Conservative mutating classification for trait objects without local impls
- Rust Tests:
ori_types/src/infer/— trait object mutation - Ori Tests:
tests/spec/traits/mutable_self_trait_object.ori
- Rust Tests:
Phase 5: Extension Support
- Implement: Extension methods follow same mutation propagation rules
- Rust Tests:
ori_types/src/infer/— extension mutation propagation - Ori Tests:
tests/spec/methods/mutable_self_extension.ori
- Rust Tests:
Phase 6: Evaluator
-
Implement: Evaluator support for mutable self in method bodies
- Rust Tests:
ori_eval/src/— mutable self evaluation - Ori Tests:
tests/spec/methods/mutable_self_eval.ori
- Rust Tests:
-
Implement: Evaluator call-site desugaring (implicit reassignment)
- Rust Tests:
ori_eval/src/— call-site desugaring evaluation - Ori Tests:
tests/spec/methods/mutable_self_propagation.ori
- Rust Tests:
Phase 7: LLVM Support
-
LLVM Support: LLVM codegen for mutable self desugaring
- LLVM Rust Tests:
ori_llvm/tests/— mutable self codegen - AOT Tests:
tests/spec/methods/mutable_self_aot.ori
- LLVM Rust Tests:
-
LLVM Support: COW integration for self-mutating methods
- LLVM Rust Tests:
ori_llvm/tests/— mutable self COW codegen - AOT Tests:
tests/spec/methods/mutable_self_cow.ori
- 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 (15D.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-15D.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 15D.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.
15D.7 Section Completion Checklist
- All implementation items have checkboxes marked
[ ] - All spec docs updated
- CLAUDE.md updated with syntax changes
- Migration tools working
- All tests pass:
./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.
Exit Criteria: Binding and type syntax proposals implemented
- Subsection close-out (15D.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-15D.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 15D.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.