69%

Section 3: Traits and Implementations

Goal: Trait-based polymorphism

SPEC: spec/09-properties-of-types.md, spec/10-declarations.md

Status: In-progress — Core evaluator complete (3.0-3.7, 3.14, 3.16, 3.18-3.21). LLVM AOT: 88 trait tests, 43 derive tests, 17 formattable tests, 26 iterator tests — all passing. 4181 spec tests pass, 0 fail, 42 skip. Evaluator verified complete for all subsections through 3.21. LLVM gaps remain for: Debug (3.9), Traceable (3.13), iterator advanced features (3.8), Index (3.12), derived sum/generic/recursive (3.15). Not started: 3.23 (impl colon syntax), 3.24 (Value trait). 3.22 eliminated per capability-unification decision. Last verified 2026-03-29.


Implementation Location

SYNC POINT: Adding a new derived trait (e.g., Debug, Comparable, Reflect) requires updating ALL 5 crates simultaneously. See CLAUDE.md “Adding a New Derived Trait” and memory “Derived Trait Sync — DO NOT” for the full protocol: ori_ir (DerivedTrait enum), ori_types (registration), ori_eval (eval dispatch), ori_llvm (codegen), library/std/prelude.ori (trait definition).

All items in this section (3.0-3.21) are implemented in ori_types (the unified type checker crate).

Key Files:

  • ori_types/src/check/registration/ — Trait/impl registration
  • ori_types/src/check/bounds/ — Constraint satisfaction and bound checking
  • ori_types/src/infer/ — Type inference including built-in method signatures

PRIORITY NOTE

Per the “Lean Core, Rich Libraries” principle, most built-in functions have been moved from the compiler core to trait methods. The compiler now only provides:

Remaining built-ins:

  • print(msg: str) - I/O
  • panic(msg: str) - Control flow

Moved to traits (must implement in this section):

  • len(collection) -> Len trait with .len() method
  • is_empty(collection) -> IsEmpty trait with .is_empty() method
  • is_some(option), is_none(option) -> Option methods
  • is_ok(result), is_err(result) -> Result methods
  • compare(left, right) -> Comparable trait with .compare() method
  • min(a, b), max(a, b) -> Comparable trait or standalone functions via traits
  • assert(condition) -> Assert trait or testing module
  • assert_eq(actual, expected), assert_ne(actual, unexpected) -> Testing traits

Without traits, tests cannot use assertions - this blocks the testing workflow.


3.0 Core Library Traits

STATUS: COMPLETE (verified 2026-03-29 — evaluator complete, map/set LLVM equals/hash pending AOT collection infrastructure)

Core library traits are implemented via:

  1. Runtime: Evaluator’s MethodRegistry provides hardcoded Rust dispatch for methods like .len(), .is_empty(), .is_some(), etc.
  2. Type checking: infer_builtin_method() provides type inference for these methods
  3. Trait bounds: primitive_implements_trait() in bound_checking.rs recognizes when types implement these traits

This approach follows the “Lean Core, Rich Libraries” principle — the runtime implementation stays in Rust for efficiency, while the type system recognizes the trait bounds for generic programming.

3.0.1 Len Trait

Proposal: proposals/approved/len-trait-proposal.md (approved 2026-02-18)

  • Implemented: Trait bound Len recognized for [T], str, {K: V}, Set<T>, Range<T> [done] (2026-02-10)
    • Rust Tests: ori_types/src/check/tests.rstest_len_bound_satisfied_by_*
    • Ori Tests: tests/spec/traits/core/len.ori — 14 tests (all pass)
  • Implemented: .len() method works on all collection types [done] (2026-02-10)
    • Tests: ori_eval/src/methods.rs — list/string/range method tests
    • LLVM Support: LLVM codegen for .len() — inline IR via field extraction in lower_calls.rs
    • AOT Tests: ori_llvm/tests/aot/traits.rs.len() on lists (3 tests) and strings (2 tests) [done] (2026-02-13)
  • Implement: Add tuple Len bound recognition — (T₁, T₂, ...) (approved in proposal) [done] (2026-02-18)
    • Rust Tests: ori_types/src/infer/expr/tests.rstest_len_satisfied_by_tuple, test_len_satisfied_by_triple_tuple, test_len_satisfied_by_single_tuple, test_len_not_satisfied_by_result
    • Ori Tests: tests/spec/traits/core/len.ori — 3 tuple len tests (pair, triple, single)
  • Implement: Update prelude len() to use <T: Len> bound (generic function) [done] (2026-02-18)
    • Implement: Add Len trait definition to library/std/prelude.ori
    • Ori Tests: tests/spec/traits/core/len.ori — generic len tests (str, list, tuple via <T: Len> bound)
  • Spec: Add Len Trait section to 09-properties-of-types.md [done] (2026-02-18)

3.0.2 IsEmpty Trait

Proposal: proposals/approved/is-empty-trait-proposal.md (approved 2026-02-21)

  • Implemented: Trait bound IsEmpty recognized for [T], str, {K: V}, Set<T> [done] (2026-02-10)
    • Rust Tests: ori_types/src/check/tests.rstest_is_empty_bound_satisfied_by_*
    • Ori Tests: tests/spec/traits/core/is_empty.ori — 13 tests (all pass)
  • Implemented: .is_empty() method works on all collection types [done] (2026-02-10)
    • Tests: ori_eval/src/methods.rs — list/string method tests
    • LLVM Support: LLVM codegen for .is_empty() — inline IR in lower_calls.rs
    • AOT Tests: ori_llvm/tests/aot/traits.rs.is_empty() on lists (2 tests) and strings (2 tests) [done] (2026-02-13)
  • Implement: Add Range<int> and [T, max N] to IsEmpty trait bound recognition
    • Rust Tests: ori_typestest_is_empty_bound_satisfied_by_range, test_is_empty_bound_satisfied_by_fixed_list
    • Ori Tests: tests/spec/traits/core/is_empty.ori — range and fixed-size list is_empty tests
  • Implement: Update prelude is_empty() to use <T: IsEmpty> bound (generic function)
    • Implement: Add IsEmpty trait definition to library/std/prelude.ori
    • Ori Tests: tests/spec/traits/core/is_empty.ori — generic is_empty tests (str, map via <T: IsEmpty> bound)
  • Spec: Verify IsEmpty Trait section in 09-properties-of-types.md (note: IsEmpty IS present at 9.11; previously this item referenced nonexistent 07-properties-of-types.md, corrected 2026-03-29)

3.0.3 Option Methods

  • Implemented: .is_some(), .is_none(), .unwrap(), .unwrap_or(default:) methods [done] (2026-02-10)
    • Rust Tests: ori_eval/src/methods.rsoption_methods module
    • Ori Tests: tests/spec/traits/core/option.ori — 16 tests (all pass)
    • LLVM Support: LLVM codegen for Option — tag-based dispatch in lower_calls.rs
    • AOT Tests: ori_llvm/tests/aot/traits.rs.is_some() (2), .is_none() (2), .unwrap() (1), .unwrap_or() (2) all pass [done] (2026-02-13)
  • Type checking: infer_builtin_method() handles Option methods [done] (2026-02-10)

3.0.4 Result Methods

  • Implemented: .is_ok(), .is_err(), .unwrap() methods [done] (2026-02-10)
    • Rust Tests: ori_eval/src/methods.rsresult_methods module
    • Ori Tests: tests/spec/traits/core/result.ori — 14 tests (all pass)
    • LLVM Support: LLVM codegen for Result — tag-based dispatch in lower_calls.rs
    • AOT Tests: ori_llvm/tests/aot/traits.rs.is_ok() (2), .is_err() (2), .unwrap() (1) all pass [done] (2026-02-13)
  • Type checking: infer_builtin_method() handles Result methods [done] (2026-02-10)

3.0.5 Comparable Trait

  • Implemented: Trait bound Comparable recognized for int, float, bool, str, char, byte, Duration, Size, [T], Option<T>, Result<T, E>, Ordering [done] (2026-02-10)
    • Rust Tests: ori_types/src/check/tests.rstest_comparable_bound_satisfied_by_*
    • Ori Tests: tests/spec/traits/core/comparable.ori — 58 tests (all pass)
  • Type checking: All comparable types have .compare(other:) returning Ordering [done] (2026-02-10)
    • Type Checking: ori_types/src/infer/ — numeric.rs, string.rs, list.rs, option.rs, result.rs, units.rs, ordering.rs
    • LLVM Support: LLVM codegen for .compare() — inline arithmetic/comparison in lower_calls.rs
    • AOT Tests: ori_llvm/tests/aot/traits.rs — 7 tests passing: .compare() + Ordering methods (is_less, is_equal, is_greater, reverse, is_less_or_equal, is_greater_or_equal) [done] (2026-02-13)

3.0.6 Eq Trait

  • Implemented: Trait bound Eq recognized for all primitive types [done] (2026-02-10)
    • Rust Tests: ori_types/src/check/tests.rstest_eq_bound_satisfied_by_*
    • Ori Tests: tests/spec/traits/core/eq.ori — 23 tests (all pass)
    • LLVM Support: LLVM codegen for ==/!= on all primitives [done]
    • AOT Tests: ori_llvm/tests/aot/traits.rs==/!= for int, bool, str (3 tests) [done] (2026-02-13)

Additional Traits

The following traits are also recognized in trait bounds:

  • Clone: All primitives, collections
  • Hashable: int, bool, str, char, byte
  • Default: int, float, bool, str, Unit, Option<T>
  • Printable: All primitives

3.1 Trait Declarations

STATUS: COMPLETE (verified 2026-03-29)

  • Implement: Parse trait Name { ... } — spec/10-declarations.md § Trait Declarations [done] (2026-02-10)

    • Write test: tests/spec/traits/declaration.ori — 16 tests (all pass)
    • Run test: ori test tests/spec/traits/declaration.ori
  • Implement: Required method signatures — spec/10-declarations.md § Trait Declarations [done] (2026-02-10)

    • Write test: tests/spec/traits/declaration.ori — Greeter, Counter, Calculator traits
    • Run test: All pass
  • Implement: Default method implementations — spec/10-declarations.md § Trait Declarations [done] (2026-02-10)

    • Write test: tests/spec/traits/declaration.ori (test_default_method: summarize(), is_large())
    • Run test: All pass
    • Note: Added default trait method dispatch in module_loading.rs:collect_impl_methods()
    • LLVM Support: LLVM codegen for default trait method dispatch [done] (2026-02-13)
      • Fixed at 3 levels: method registration (register_impl), body type checking (check_impl_block), LLVM codegen (compile_impls)
    • AOT Tests: ori_llvm/tests/aot/traits.rstest_aot_trait_default_method passing [done] (2026-02-13)
  • Implement: Associated types — spec/10-declarations.md § Associated Types [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/tests.rs — associated type parsing
    • Ori Tests: tests/spec/traits/associated_types.ori — 2 tests + 1 compile_fail (all pass)
  • Implement: self parameter — spec/10-declarations.md § self Parameter [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/tests.rs — self parameter handling
    • Ori Tests: tests/spec/traits/self_param.ori — 9 tests (all pass)
  • Implement: Self type reference — spec/10-declarations.md § Self Type [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/tests.rs — Self type resolution
    • Ori Tests: tests/spec/traits/self_type.ori — 7 tests (all pass)
  • Implement: Trait inheritance trait Child: Parent — spec/10-declarations.md § Trait Inheritance [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/tests.rs — trait inheritance
    • Ori Tests: tests/spec/traits/inheritance.ori — 6 tests including 3-level deep inheritance (all pass)
  • BUG: Static methods Type.method() not supported — commented out in declaration.ori (Point.new(), Point.origin()) [done] (2026-02-13)

    • Infrastructure was already working (TypeRef dispatch in method_dispatch.rs). Test file was missing @new/@origin impl methods + had stale TODO comments. Added methods, uncommented tests, 2 new tests pass.

3.2 Trait Implementations

STATUS: COMPLETE (verified 2026-03-29 — evaluator complete; LLVM generic impls intentionally deferred, no monomorphization pipeline)

  • Implement: Inherent impl impl Type { ... } — spec/10-declarations.md § Inherent Implementations [done] (2026-02-10)

    • Write test: tests/spec/traits/declaration.ori (Widget.get_name(), Widget.get_value(), Point.distance_from_origin())
    • Run test: All pass
    • LLVM Support: LLVM codegen — type-qualified method dispatch (_ori_Type$method mangling)
    • AOT Tests: ori_llvm/tests/aot/traits.rs — inherent impl (3 tests: method, params, field access), impl_method_field_access (1 test) [done] (2026-02-13)
  • Implement: Trait impl impl Type: Trait { ... } — spec/10-declarations.md § Trait Implementations [done] (2026-02-10)

    • Write test: tests/spec/traits/declaration.ori (Widget.greet(), Widget.describe(), Widget.summarize())
    • Run test: All pass
    • LLVM Support: LLVM codegen — trait method dispatch (_ori_Type$$Trait$method mangling)
    • AOT Tests: ori_llvm/tests/aot/traits.rs — trait impl (2 tests: single method, multiple methods) [done] (2026-02-13)
  • Implement: Generic impl impl<T: Bound> Container<T>: Trait — spec/10-declarations.md § Generic Implementations [done] (2026-02-10)

    • Rust Tests: Parser tests in ori_parse/src/grammar/item.rs
    • Ori Tests: tests/spec/traits/generic_impl.ori — 4 tests (inherent + trait impls on generic types, all pass)
    • Note: Added parse_impl_type() to handle Box<T> syntax in impl blocks. Also added Type::Applied for tracking instantiated generic types with their type arguments.
    • LLVM Support: LLVM codegen for generic impl method dispatch — not explicitly tested (no monomorphization)
    • LLVM Rust Tests: Skipped — generic functions are skipped in AOT codegen (no monomorphization pipeline)
  • Implement: Where clauses — spec/10-declarations.md § Where Clauses [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/tests.rs — where clause parsing
    • Ori Tests: tests/spec/traits/associated_types.oriwhere C.Item: Eq verified
  • Implement: Method resolution in type checker — spec/10-declarations.md § Method Resolution [done] (2026-02-10)

    • TraitRegistry.lookup_method() checks inherent impls, then trait impls, then default methods
    • infer_method_call() uses trait registry, falls back to built-in methods
    • Rust Tests: Covered by existing tests in typeck/infer/call.rs
    • Ori Tests: tests/spec/traits/declaration.ori, tests/spec/traits/generic_impl.ori, tests/spec/traits/method_call_test.ori
    • LLVM Support: 4-tier dispatch: built-in → type-qualified → bare-name → LLVM module lookup
    • AOT Tests: ori_llvm/tests/aot/traits.rs — method resolution (1 test: inherent takes priority over trait impl) [done] (2026-02-13)
  • Implement: User-defined impl method dispatch in evaluator [done] (2026-02-10)

    • Created UserMethodRegistry to store impl method definitions
    • Methods registered via load_module -> register_impl_methods
    • eval_method_call checks user methods first, falls back to built-in
    • Added self_path to ImplDef AST for type name resolution
    • Write test: Rust unit tests in eval/evaluator.rs (4 tests covering dispatch, self access, args, fallback)
    • Run test: All pass
    • LLVM Support: LLVM codegen for user-defined impl method dispatch — compile_impls() in function_compiler.rs
    • AOT Tests: ori_llvm/tests/aot/traits.rs — user method dispatch covered by inherent impl and trait impl tests [done] (2026-02-13)
  • Implement: Coherence checking — spec/10-declarations.md § Coherence [done] (2026-02-10)

    • register_impl returns Result<(), CoherenceError> and checks for conflicts
    • Duplicate trait impls for same type rejected
    • Duplicate inherent methods on same type rejected
    • Multiple inherent impl blocks allowed if methods don’t conflict (merged)
    • Added E2010 error code for coherence violations
    • Write test: Rust unit tests in typeck/type_registry.rs (3 tests)
    • Run test: All pass

3.3 Trait Bounds

Complete Implementation: [done] (verified 2026-02-14, re-verified 2026-03-29)

  • Parser supports generic parameters with bounds <T: Trait>, <T: A + B>parse_generics() + parse_bounds() in ori_parse/src/grammar/item/generics/mod.rs
  • Parser supports where clauses where T: Clone, U: Defaultparse_where_clauses() in ori_parse/src/grammar/item/generics/mod.rs
  • Function AST node stores generics: GenericParamRange and where_clauses: Vec<WhereClause>ori_ir/src/ast/items/function.rs
  • FunctionSig in type checker stores type_param_bounds: Vec<Vec<Name>> with bounds — ori_types/src/output/mod.rs
  • Param AST stores type annotation as ty: Option<ParsedType>ori_ir/src/ast/items/function.rs
  • Type parsing captures identifier names implicitly in ParsedType nodes — ori_parse/src/grammar/ty/mod.rs
  • infer_function_signature_with_arena() creates fresh type vars for generics and maps params — ori_types/src/check/signatures/mod.rs
  • signatures: FxHashMap<Name, FunctionSig> stores signatures for call-time lookup — ori_types/src/check/mod.rs
  • Bound checking at call sites via inline checks + type_satisfies_trait()ori_types/src/infer/expr/calls.rs
  • E2009 error code for missing trait bound violations — ori_diagnostic/src/error_code/mod.rs
  • Unit tests verify end-to-end — ori_parse/src/grammar/item/generics/tests.rs (5 where-clause tests), ori_parse/src/grammar/ty/tests.rs (trait bound tests), ori_types/src/infer/expr/tests.rs

What Works Now:

  • Parsing generic functions: @compare<T: Comparable> (a: T, b: T) -> Ordering
  • Parsing multiple bounds: @process<T: Eq + Clone> (x: T) -> T
  • Parsing where clauses: @transform<T> (x: T) -> T where T: Clone = x
  • Constraint satisfaction checking at call sites
  • Error messages when types don’t satisfy required bounds

Implementation Details:

  • Param.ty stores type annotations as ParsedType; generic parameter names resolved via FunctionSig.type_params

  • FunctionSig.type_param_bounds stores bounds per generic parameter as Vec<Vec<Name>>

  • infer_function_signature_with_arena() creates fresh type vars and builds generic_param_mapping

  • When a param’s type matches a generic, the type var is used instead of inferring

  • Bound checking in calls.rs resolves type vars after unification and verifies trait impls

  • type_satisfies_trait() uses trait registry to verify implementations

  • Implement: Single bound <T: Trait> — spec/10-declarations.md § Generic Declarations [done] (2026-02-10)

    • Write test: Rust unit tests in typeck/checker.rs::tests (10 tests pass)
    • Run test: All pass
  • Implement: Multiple bounds <T: A + B> — spec/10-declarations.md § Generic Declarations [done] (2026-02-10)

    • Write test: test_multiple_bounds_parsing in Rust unit tests
    • Run test: All pass
  • Implement: Constraint satisfaction checking — spec/09-properties-of-types.md § Trait Bounds [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/tests.rs — 10+ constraint satisfaction tests
    • Ori Tests: tests/spec/traits/associated_types.orineeds_eq_item + compile_fail for violated bound

3.4 Associated Types

STATUS: COMPLETE (verified 2026-03-29)

Infrastructure implemented:

  • ParsedType::AssociatedType variant in ori_ir/src/parsed_type.rs

  • Type::Projection variant in ori_types/src/lib.rs

  • Parser handles Self.Item and T.Item syntax in type positions

  • ImplAssocType for associated type definitions in impl blocks

  • ImplEntry.assoc_types stores associated type definitions

  • TraitRegistry.lookup_assoc_type() resolves associated types

  • Implement: Associated type declarations — spec/10-declarations.md § Associated Types [done] (2026-02-10)

    • Rust Tests: ori_parse/src/grammar/ty.rs — associated type parsing tests
    • Ori Tests: tests/spec/traits/associated_types.ori — 2 tests (all pass)
    • Ori Tests: tests/spec/traits/associated_types_verify.ori — 2 tests (all pass)
  • Implement: Constraints where T.Item: Eq — spec/10-declarations.md § Where Clauses [done] (2026-02-10)

    • Rust Tests: Parser/type checker support in bound_checking.rs
    • Ori Tests: tests/spec/traits/associated_types.oritest_fnbox_fails_eq_constraint compile_fail passes
    • Note: Added WhereConstraint struct with projection support. Parser handles where C.Item: Eq. Bound checking resolves associated types via lookup_assoc_type_by_name().
  • Implement: Impl validation (require all associated types defined) [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/registration/ (trait registration)validate_associated_types
    • Ori Tests: tests/compile-fail/impl_missing_assoc_type.ori — test exists and passes [done] (verified 2026-02-14)
    • Note: Added validation in register_impls() that checks all required associated types are defined.

3.5 Derive Traits

STATUS: COMPLETE (verified 2026-03-29 — all 7 DerivedTrait variants synced across ori_ir, ori_types, ori_eval, ori_llvm)

All 5 derive traits implemented in ori_types/src/check/ (derives).

BLOAT: compiler/ori_eval/src/interpreter/derived_methods.rs is 504 lines — at the 500-line limit. Monitor for growth. Tests at tests/spec/traits/derive/all_derives.ori (7 tests pass).

  • Implement: Auto-implement Eq — spec/10-declarations.md § Attributes [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/ (derives)test_process_struct_derives
    • Ori Tests: tests/spec/traits/derive/all_derives.ori + tests/spec/traits/derive/eq.ori — 3+13 tests (all pass)
    • LLVM Support: Synthetic LLVM IR for derived Eq — field-by-field icmp eq with short-circuit AND [done] (2026-02-13)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 4 AOT tests (basic, strings, mixed types, single field) [done] (2026-02-13)
  • Implement: Auto-implement Clone — spec/10-declarations.md § Attributes [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/ (derives)test_process_multiple_derives
    • Ori Tests: tests/spec/traits/derive/all_derives.ori.clone() on derived Point (passes)
    • LLVM Support: Synthetic LLVM IR for derived Clone — identity return for value types [done] (2026-02-13)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 2 AOT tests (basic, large struct sret) [done] (2026-02-13)
  • Implement: Auto-implement Hashable — spec/10-declarations.md § Attributes [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/ (derives)
    • Ori Tests: tests/spec/traits/derive/all_derives.ori.hash() on derived Point (passes)
    • LLVM Support: Synthetic LLVM IR for derived Hashable — FNV-1a in pure LLVM IR [done] (2026-02-13)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 2 AOT tests (equal values, different values) [done] (2026-02-13)
  • Implement: Auto-implement Printable — spec/10-declarations.md § Attributes [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/ (derives)
    • Ori Tests: tests/spec/traits/derive/all_derives.ori.to_string() on derived Point (passes)
    • LLVM Support: Synthetic LLVM IR for derived Printable — runtime str concat via ori_str_* [done] (2026-02-13)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 1 AOT test (basic non-empty check) [done] (2026-02-13)
  • Implement: Auto-implement Default — spec/10-declarations.md § Attributes [done] (2026-02-14)

    • Rust Tests: ori_types/src/check/ (derives)create_derived_method_def handles Default
    • Ori Tests: tests/spec/traits/derive/default.ori — 6 tests (basic, multi-type, single field, float, eq integration, nested) [done] (2026-02-14)
    • LLVM Support: LLVM codegen for derived Default — const_zero produces correct zero-init structs [done] (2026-02-14)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 3 AOT tests (basic, mixed types, eq integration) [done] (2026-02-15)
      • Fixed: Static method dispatch bug in LLVM codegen — TypeRef receivers now handled as static calls (no self param)

3.6 Section Completion Checklist

  • Core library traits (3.0): Len, IsEmpty, Option, Result, Comparable, Eq — mostly complete [partial] (2026-02-10)
    • Remaining: IsEmpty — add Range/[T, max N] support, generic prelude function, spec section (approved 2026-02-21)
    • Gap: Clone/Hashable/Default/Printable methods NOT callable on primitives — FIXED: V2 type checker resolvers return correct types for clone/hash/equals on primitives [done] (2026-02-15). Clone also works on compound types (collections, wrappers, tuples). hash/equals on compound types reverted (phase boundary leak — evaluator/LLVM not implemented); tracked under 3.14.
  • Trait declarations (3.1): Parse, required methods, default methods, self, Self, inheritance — all complete [done] (2026-02-10)
    • Gap: Static methods Type.method() — FIXED, was stale TODO [done] (2026-02-13)
  • Trait implementations (3.2): Inherent, trait, generic impls, method resolution, coherence — all complete [done] (2026-02-10)
  • Trait bounds (3.3): Single, multiple, constraint satisfaction — all complete [done] (2026-02-10)
  • Associated types (3.4): Declaration, Self.Item, where constraints — all complete [done] (2026-02-10)
  • Derive traits (3.5): Eq, Clone, Hashable, Printable complete; Default NOT tested [done] (2026-02-10)
  • ~239 trait test annotations pass (len: 14, is_empty: 13, option: 16, result: 14, comparable: 58, eq: 23, declaration: 16, self_param: 9, self_type: 7, inheritance: 6, generic_impl: 4, associated_types: 4, default_type_params: 2, default_assoc_types: 4, derive: 16, ordering: 32, method_call: 1) [done] (2026-02-10)
  • Run full test suite: ./test-all.sh — 4181 passed, 0 failed, 42 skipped (verified 2026-03-29)
  • LLVM AOT tests: 88 trait + 43 derive + 17 formattable + 26 iterator = 174 total, all passing (verified 2026-03-29)
    • Fixed: .compare() return type resolved as Ordering — added to V2 type checker [done] (2026-02-13)
    • Fixed: .unwrap_or() added to LLVM Option dispatch table [done] (2026-02-13)
    • Fixed: Default trait methods compiled in LLVM [done] (2026-02-13)
    • Fixed: Indirect ABI parameter passing — self loaded from pointer for >16B structs [done] (2026-02-13)
    • Fixed: Derive methods wired into LLVM codegen — synthetic IR functions for Eq, Clone, Hashable, Printable [done] (2026-02-13)
  • Operator traits (3.21): User-defined operator dispatch complete — type checker desugaring, evaluator dispatch, LLVM codegen, error messages [done] (2026-02-15)
    • Remaining: spec and CLAUDE.md updates verified complete (2026-02-15). Derive for newtypes tracked as optional in 3.21 [done] (2026-02-18)
  • Proposals (3.8-3.17): Evaluator verified complete for all proposals (verified 2026-03-29). LLVM gaps remain: Debug (3.9 all items), Traceable (3.13), iterator advanced features (3.8 Phase 2+), Index (3.12), derived sum/generic/recursive (3.15). See per-subsection LLVM items for details.
  • /tpr-review passed — independent Codex review found no critical or major issues (or all findings triaged)
  • /impl-hygiene-review passed — implementation hygiene review clean (phase boundaries, SSOT, algorithmic DRY, naming). MUST run AFTER /tpr-review is clean.
  • HYGIENE: compiler/ori_types/src/registry/traits/mod.rs is 762 source lines — exceeds the 500-line limit. Split into submodules.
  • WEAK TESTS: tests/spec/traits/iterator/collect_set.ori has 6 #skip markers with tautological stub bodies (assert(cond: true)) — exceeds 3-skip budget per file. Replace with real tests or remove stubs and track Set collect as a plan item.
  • WEAK TESTS: Default type parameters (3.19) has only 2 spec tests. Add edge case tests (multiple defaults, complex cross-references, error cases for invalid ordering).
  • WEAK TESTS: Default associated types (3.20) has only 4 spec tests. Add bounds checking tests when feature is implemented.

Exit Criteria: Core trait-based code compiles and runs in evaluator [done]. LLVM codegen for built-in and user methods works [done]. User-defined operator traits complete [done] (2026-02-15). Formal trait proposals (3.8-3.17) evaluator complete, LLVM partial.

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

3.7 Clone Trait Formal Definition

STATUS: COMPLETE (verified 2026-03-29)

Proposal: proposals/approved/clone-trait-proposal.md

Formalizes the Clone trait that enables explicit value duplication. The trait is already recognized in trait bounds and derivable, but this proposal adds the formal definition and comprehensive prelude implementations.

Implementation

  • Implement: Formal Clone trait definition in type system

    • Ori Tests: tests/spec/traits/clone/definition.ori — derived Clone on structs (6 tests)
    • LLVM Support: LLVM codegen for Clone trait (identity for value types, derive for structs)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — Clone definition codegen (derive_clone_basic, derive_clone_large_struct)
    • Note: Type checker V2 resolve_*_method returns correct types for clone on all primitives and compound types. Static method dispatch fix enabled Type.default() calls in LLVM codegen. hash/equals resolved for primitives only (compound types deferred to 3.14 — evaluator/LLVM codegen not yet implemented).
  • Implement: Clone implementations for all primitives (int, float, bool, str, char, byte, Duration, Size)

    • Ori Tests: tests/spec/traits/clone/primitives.ori — all 8 primitive types (13 tests)
    • LLVM Support: LLVM codegen for primitive clone methods (identity operation)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — primitive clone codegen (clone_int, clone_float, clone_bool, clone_str)
  • Implement: Clone implementations for collections ([T], {K: V}, Set) with element-wise cloning [done] (2026-02-15)

    • Rust Tests: ori_types/src/infer/expr/tests.rstest_clone_satisfied_by_list, test_clone_satisfied_by_map, test_clone_satisfied_by_set
    • Ori Tests: tests/spec/traits/clone/collections.ori — list clone (3 tests)
    • LLVM Support: LLVM codegen for collection clone — identity (ARC shares data) in lower_list_method()
    • AOT Tests: ori_llvm/tests/aot/derives.rstest_aot_clone_list_int, test_aot_clone_list_empty
  • Implement: Clone implementations for Option and Result<T, E> [done] (2026-02-15)

    • Rust Tests: ori_types/src/infer/expr/tests.rstest_clone_satisfied_by_option, test_clone_satisfied_by_result
    • Ori Tests: tests/spec/traits/clone/wrappers.ori — Option Some/None, Result Ok/Err (4 tests)
    • LLVM Support: LLVM codegen for Option/Result clone — identity (value types) in lower_option_method(), lower_result_method()
    • AOT Tests: ori_llvm/tests/aot/derives.rstest_aot_clone_option_some, test_aot_clone_option_none, test_aot_clone_result_ok, test_aot_clone_result_err
  • Implement: Clone implementations for tuples (all arities) [done] (2026-02-15)

    • Rust Tests: ori_types/src/infer/expr/tests.rstest_clone_satisfied_by_tuple, test_clone_satisfied_by_tuple_triple
    • Ori Tests: tests/spec/traits/clone/tuples.ori — pair and triple clone (2 tests)
    • LLVM Support: LLVM codegen for tuple clone — identity (value type) via TypeInfo::Tuple match in lower_builtin_method()
    • AOT Tests: ori_llvm/tests/aot/derives.rstest_aot_clone_tuple_pair, test_aot_clone_tuple_triple
  • Update Spec: 06-types.md — add Clone trait section (already present at § Clone Trait, lines 924–970+)

  • Update Spec: 12-modules.md — update prelude traits description (Clone listed in prelude traits table, line 269/279)

  • Update: CLAUDE.md — Clone is documented in spec; CLAUDE.md is a compiler dev guide, not language reference

  • Hygiene review (2026-02-15): Phase boundary audit of commit 01051607

    • Fixed LEAK: LLVM codegen missing byte.clone() and char.clone() — added Idx::BYTE | Idx::CHAR identity arms in lower_builtin_method() (lower_calls.rs)
    • Fixed LEAK: Type checker speculatively accepted hash/equals on collections (list, map, set), wrappers (Option, Result), and tuples — reverted. Evaluator and LLVM codegen have no handlers for these methods. Type checker now only accepts clone on compound types. hash/equals on compound types tracked under 3.14.
    • Deferred WASTE: abi.clone() in lower_calls.rs (4 sites) — pre-existing borrow-conflict workaround, cheap clone. Not worth refactoring risk now.
    • Deferred WASTE: method_str String allocation per method call — pre-existing, requires Name-based API change across many call sites.
    • Hygiene review pass 2 (2026-02-15): Phase boundary audit of commit da22ae17
      • Fixed LEAK: type_satisfies_trait() claimed compound types satisfy Eq (COLLECTION_TRAITS, WRAPPER_TRAITS, RESULT_TRAITS all contained "Eq") — but no .equals() method exists in any downstream phase. Removed "Eq" from all 3 arrays. Re-add under 3.14 when equals() is implemented.
      • Fixed LEAK: resolve_tuple_method() accepted to_list — dubious semantics (only works if all elements same type), no evaluator/LLVM handler. Removed; simplified function signature (dropped unused engine param).
      • Fixed LEAK: dispatch_map_method() in evaluator had no clone handler — fell through to no_such_method("clone", "map"). Added clone handler (Arc identity, same as list).
      • Fixed LEAK: dispatch_tuple_method() in evaluator had no len handler — fell through to no_such_method("len", "tuple"). Added len handler extracting Value::Tuple(elems).len().
      • Fixed LEAK: lower_builtin_method() in LLVM codegen had no Map/Set clone handling — fell through to None → “unresolved method call”. Added Map | Set identity pattern (Arc-managed structs).
      • Fixed LEAK: lower_builtin_method() in LLVM codegen had no Tuple.len() handling. Added compile-time constant from TypeInfo::Tuple { elements } count.
      • Added Tests: 6 unit tests verifying compound types do NOT satisfy Eq (test_eq_not_satisfied_by_{list,map,set,option,result,tuple}).

3.8 Iterator Traits

STATUS: Evaluator COMPLETE, LLVM PARTIAL (verified 2026-03-29 — evaluator verified complete; LLVM Phase 1 done with 26 AOT tests; Phase 2+ LLVM items unchecked; collect_set.ori has 6 skips with stub bodies — WEAK TESTS)

Proposal: proposals/approved/iterator-traits-proposal.md

Formalizes iteration with four core traits: Iterator, DoubleEndedIterator, Iterable, and Collect. Enables generic programming over any iterable, user types participating in for loops, and transformation methods.

Implementation

  • Implement: Iterator trait with functional next() returning (Option<Self.Item>, Self) (2026-02-15)

    • Rust Tests: ori_patterns/src/value/iterator/tests.rs — 13 unit tests for IteratorValue (2026-02-15)
    • Ori Tests: tests/spec/traits/iterator/iterator.ori — 9 spec tests (2026-02-15)
    • LLVM Support: LLVM codegen for iterator trait methods
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: DoubleEndedIterator trait with next_back() method (2026-02-16)

    • Rust Tests: ori_patterns/src/value/iterator/tests.rs — 18 unit tests for next_back (List, Range, Str, interleaved, is_double_ended, size_hint) (2026-02-16)
    • Ori Tests: tests/spec/traits/iterator/double_ended.ori — 12 spec tests (2026-02-16)
    • LLVM Support: LLVM codegen for double-ended iterator methods
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: Iterable trait with iter() method — built-in dispatch for list, map, range, str (2026-02-15)

    • Rust Tests: Consistency tests verify eval/typeck method sync (2026-02-15)
    • Ori Tests: tests/spec/traits/iterator/iterator.ori — covers .iter() on all types (2026-02-15)
    • LLVM Support: LLVM codegen for iterable trait
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: Collect trait with from_iter() method — type-directed collect via bidirectional inference (2026-02-16)

    • Rust Tests: ori_types/src/check/integration_tests.rs — 4 integration tests for bidirectional collect inference (2026-02-16)
    • Ori Tests: tests/spec/traits/iterator/collect.ori — 8 spec tests for Set collect, dedup, chained adapters (2026-02-16)
    • LLVM Support: LLVM codegen for collect trait
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: Iterator Phase 2 methods — consumers (fold, count, find, any, all, for_each, collect) and lazy adapters (map, filter, take, skip) (2026-02-15)

    • Rust Tests: ori_patterns/src/value/iterator/tests.rs — 10 adapter variant unit tests (2026-02-15)
    • Ori Tests: tests/spec/traits/iterator/methods.ori — 31 spec test assertions (2026-02-15)
    • LLVM Support: LLVM codegen for all iterator methods (2026-02-21) — Phase 1: map, filter, take, skip, enumerate, collect, count; Phase 2: fold, find, any, all, for_each, zip, chain
    • AOT Tests: ori_llvm/tests/aot/iterators.rs — 25 AOT tests (2026-02-21)
    • Phase 2C/2D: enumerate, zip, chain, flatten, flat_map, cycle (2026-02-15)
    • Remaining: DoubleEndedIterator — next_back() implemented (2026-02-16)
  • Implement: DoubleEndedIterator default methods (rev, last, rfind, rfold) (2026-02-16)

    • Rust Tests: ori_patterns/src/value/iterator/tests.rs — 7 unit tests for Reversed variant (is_double_ended, size_hint, Debug, PartialEq, Hash) (2026-02-16)
    • Ori Tests: tests/spec/traits/iterator/double_ended_methods.ori — 21 spec tests (rev/last/rfind/rfold on list, range, string, empty, adapters) (2026-02-16)
    • LLVM Support: LLVM codegen for double-ended methods
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: repeat(value) function for infinite iterators (2026-02-16)

    • Rust Tests: ori_patterns/src/value/iterator/tests.rs — 9 unit tests (basic, string, never_exhausts, not_double_ended, size_hint, debug, equality, inequality, cross-variant) (2026-02-16)
    • Ori Tests: tests/spec/traits/iterator/infinite.ori — 13 spec tests (basic, string, bool, take_zero, map, filter, enumerate, skip_take, count, fold, any, all, zip) (2026-02-16)
    • LLVM Support: LLVM codegen for repeat
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: Standard implementations for built-in types

    • [T] implements Iterable (2026-02-15) (DoubleEndedIterator, Collect pending)
    • {K: V} implements Iterable (2026-02-15) (NOT double-ended — unordered)
    • Set<T> implements Iterable (2026-02-15) (Collect pending) (NOT double-ended — unordered)
    • str implements Iterable (2026-02-15) (DoubleEndedIterator pending)
    • Range<int> implements Iterable (2026-02-15) (DoubleEndedIterator pending)
    • Option<T> implements Iterable (2026-02-16) — Some(x) → 1-element list iter, None → empty iter
    • Note: Range<float> does NOT implement Iterable (precision issues) (2026-02-16) — compile-time rejection with diagnostic in type checker: for loops, .iter(), .collect(), .to_list() all rejected; compile-fail tests in tests/compile-fail/range_float_iteration.ori (4 tests)
    • Ori Tests: tests/spec/traits/iterator/builtin_impls.ori — 13 spec tests (some/none iter, map, filter, count, fold, any, chain, zip) (2026-02-16)
    • LLVM Support: LLVM codegen for all builtin iterator impls
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: Helper iterator types (ListIterator, RangeIterator, MapIterator, SetIterator, StrIterator) + adapter types (Mapped, Filtered, TakeN, SkipN) (2026-02-15)

    • Rust Tests: ori_patterns/src/value/iterator/tests.rs — 22 unit tests (2026-02-15)
    • Ori Tests: Coverage across existing files — ListIterator/RangeIterator/StrIterator in iterator.ori+double_ended.ori, SetIterator in for_loop.ori, MapIterator in iterator.ori, adapters in methods.ori+double_ended.ori (2026-02-16)
    • LLVM Support: LLVM codegen for all helper iterator types
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: Fused iterator guarantee (once None, always None) (2026-02-15)

    • Rust Tests: ori_patterns/src/value/iterator/tests.rs — list_iterator_fused (2026-02-15)
    • Ori Tests: tests/spec/traits/iterator/iterator.ori — test_list_iter_fused (2026-02-15)
    • LLVM Support: LLVM codegen respects fused guarantee
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: for loop desugaring to Iterable.iter() and functional next() (2026-02-16)

    • Rust Tests: ori_types/src/infer/expr/tests.rs — 4 for-loop type inference tests (infer_for_do, infer_for_yield, infer_for_with_guard, infer_for_guard_not_bool) (2026-02-16)
    • Ori Tests: tests/spec/traits/iterator/for_loop.ori — 19 spec tests (list, range, str, set, option, iterator pass-through, guards, break) (2026-02-16)
    • LLVM Support: LLVM codegen for desugared for loops
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: for...yield desugaring to .iter().map().collect() (2026-02-16)

    • Rust Tests: ori_types/src/infer/expr/tests.rs — test_infer_for_yield verifies yield produces List (2026-02-16)
    • Ori Tests: tests/spec/traits/iterator/for_loop.ori — 12+ yield tests (list, empty, range, inclusive, str, option, guard, transform, break) (2026-02-16)
    • LLVM Support: LLVM codegen for desugared for yield
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: Add traits and repeat to prelude (2026-02-16)

    • Iterator, DoubleEndedIterator, Iterable, Collect traits in prelude (TraitRegistry) (2026-02-16) — defined in library/std/prelude.ori with pub trait syntax; Iterator<T>/DoubleEndedIterator<T> added to well-known types match in all three type resolution paths (resolve_parsed_type_simple, resolve_type_with_vars, resolve_parsed_type); type annotations like let it: Iterator<int> and let it: DoubleEndedIterator<int> now resolve correctly
    • Gate double-ended methods (rev, last, rfind, rfold, next_back) behind DoubleEndedIterator trait bound in type checker (2026-02-16) — Tag::DoubleEndedIterator added; list/range/str return DEI, map/set/option return Iterator; map/filter preserve DEI, take/skip/enumerate downgrade; error diagnostic for DEI-only methods on plain Iterator; tests: tests/spec/traits/iterator/double_ended_gating.ori (16 spec tests), tag/tests.rs (5 unit tests), unify/tests.rs (7 unit tests)
    • repeat function in prelude (2026-02-16) — registered in register_prelude() + type sig in infer_ident()
    • Ori Tests: tests/spec/traits/iterator/prelude.ori (2026-02-16) — 8 spec tests (Iterator annotation, DoubleEndedIterator annotation, method chains, collect, repeat, for-loop, for-yield)
  • Update Spec: 06-types.md — Iterator traits section already present (lines 1304-1344) (verified 2026-02-16)

  • Update Spec: 10-patterns.md — for loop desugaring already documented (lines 887-911) (verified 2026-02-16)

  • Update Spec: 12-modules.md — Iterator traits in prelude table (lines 281-288) (verified 2026-02-16)

  • Update: CLAUDE.md — Iterator documentation in .claude/rules/ori-syntax.md (lines 177-182) (verified 2026-02-16)

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

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

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

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

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


3.8.1 Iterator Performance and Semantics

STATUS: Evaluator COMPLETE, LLVM/optimizations NOT STARTED (verified 2026-03-29 — evaluator items verified; all LLVM items unchecked; optimization items correctly marked as not started)

Proposal: proposals/approved/iterator-performance-semantics-proposal.md

Formalizes the performance characteristics and precise semantics of Ori’s functional iterator model. Specifies copy elision guarantees, lazy evaluation, compiler optimizations, and introduces infinite range syntax (start..).

Implementation

  • Implement: Copy elision for iterator rebinding patterns (2026-02-17)

    • Rust Tests: ori_patterns/src/value/iterator/tests.rs + heap/tests.rs — copy elision verification (2026-02-17)
    • Ori Tests: tests/spec/traits/iterator/copy_elision.ori (2026-02-17)
    • LLVM Support: LLVM codegen respects copy elision
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: Infinite range syntax start.. in lexer/parser

    • Rust Tests: ori_patterns/src/value/composite/tests.rs — unbounded range unit tests
    • Ori Tests: tests/spec/expressions/infinite_range.ori
    • LLVM Support: LLVM codegen for infinite ranges
    • LLVM Rust Tests: ori_llvm/tests/range_tests.rs
  • Implement: Infinite range with step start.. by step

    • Rust Tests: ori_patterns/src/value/iterator/tests.rs — unbounded range iterator tests
    • Ori Tests: tests/spec/expressions/infinite_range.ori (step tests included)
    • LLVM Support: LLVM codegen for stepped infinite ranges
    • LLVM Rust Tests: ori_llvm/tests/range_tests.rs
  • Implement: Infinite range iteration (implements Iterable but NOT DoubleEndedIterator)

    • Rust Tests: ori_patterns/src/value/iterator/tests.rs — unbounded range not double-ended
    • Ori Tests: tests/spec/traits/iterator/infinite_range.ori
    • LLVM Support: LLVM codegen for infinite range iteration
    • LLVM Rust Tests: ori_llvm/tests/iterator_tests.rs
  • Implement: Lint warnings for obvious infinite iteration patterns (SHOULD warn) (2026-02-16)

    • repeat(...).collect() without take — W2001 warning in type checker
    • (start..).collect() without take — unbounded range detection via ExprKind::Range { end: INVALID }
    • iter.cycle().collect() without take — cycle() detected as infinite source
    • Rust Tests: ori_types/src/infer/expr/tests.rs — 12 find_infinite_source_* unit tests (2026-02-16)
    • Ori Tests: tests/lint/infinite_iteration.ori — 14 spec tests (bounded, finite, adapter chains) (2026-02-16)
  • Implement: Guaranteed compiler optimizations

    • Copy elision when iterator rebound immediately
    • Inline expansion for iterator methods
    • Deforestation (intermediate iterator elimination)
    • Loop fusion (adjacent maps/filters combined)
    • Rust Tests: ori_llvm/tests/optimization_tests.rs
  • Update Spec: 06-types.md — add infinite range type variant (already documented)

  • Update Spec: 09-expressions.md — add infinite range syntax section (already documented)

  • Update Spec: grammar.ebnf — update range_expr production (already correct: end is optional)

  • Update: CLAUDE.md — add infinite range syntax and iterator performance notes (verified 2026-02-16: .claude/rules/ori-syntax.md lines 102+182 already document infinite range syntax, repeat(), take-before-collect guidance, and lazy/fused semantics)

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

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

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

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

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


3.9 Debug Trait

STATUS: Evaluator COMPLETE, LLVM NOT STARTED (verified 2026-03-29 — all evaluator items verified; all LLVM items unchecked)

Proposal: proposals/approved/debug-trait-proposal.md

Adds a Debug trait separate from Printable for developer-facing structural representation of values. Debug is automatically derivable and shows complete internal structure, while Printable remains for intentional user-facing output. Mirrors Rust’s Display vs Debug distinction.

Dependencies

  • as conversion syntax (as-conversion-proposal.md) — for self as str conversions
  • str.escape() method — stdlib method for escaping special characters
  • Iterator.join() method — stdlib method for joining iterator elements

Implementation

  • Implement: Debug trait definition in type system

    • Rust Tests: ori_ir/src/derives/tests.rs — DerivedTrait::Debug parsing/method_name
    • Ori Tests: tests/spec/traits/debug/definition.ori
  • Implement: Debug implementations for all primitives (int, float, bool, str, char, byte, void)

    • Rust Tests: ori_eval/src/methods/helpers/tests.rs — escape helpers
    • Ori Tests: tests/spec/traits/debug/primitives.ori
    • LLVM Support: LLVM codegen for primitive debug methods
    • LLVM Rust Tests: ori_llvm/tests/debug_tests.rs
  • Implement: Debug implementations for Duration and Size

    • Ori Tests: tests/spec/traits/debug/primitives.ori (included with primitives)
    • LLVM Support: LLVM codegen for duration/size debug
    • LLVM Rust Tests: ori_llvm/tests/debug_tests.rs
  • Implement: Debug implementations for collections ([T], {K: V}, Set)

    • Ori Tests: tests/spec/traits/debug/collections.ori
    • LLVM Support: LLVM codegen for collection debug
    • LLVM Rust Tests: ori_llvm/tests/debug_tests.rs
  • Implement: Debug implementations for Option and Result<T, E>

    • Ori Tests: tests/spec/traits/debug/wrappers.ori
    • LLVM Support: LLVM codegen for option/result debug
    • LLVM Rust Tests: ori_llvm/tests/debug_tests.rs
  • Implement: Debug implementations for tuples (all arities)

    • Ori Tests: tests/spec/traits/debug/tuples.ori
    • LLVM Support: LLVM codegen for tuple debug
    • LLVM Rust Tests: ori_llvm/tests/debug_tests.rs
  • Implement: #[derive(Debug)] macro for user-defined types

    • Ori Tests: tests/spec/traits/debug/derive.ori
    • LLVM Support: LLVM codegen for derived debug
    • LLVM Rust Tests: ori_llvm/tests/debug_tests.rs
  • Implement: str.escape() method (user-callable) (2026-02-17)

    • Ori Tests: tests/spec/traits/debug/escape.ori (2026-02-17)
    • LLVM Support: LLVM codegen for string escape
    • LLVM Rust Tests: ori_llvm/tests/debug_tests.rs
  • Implement: Iterator.join() method (user-callable) (2026-02-17)

    • Ori Tests: tests/spec/traits/debug/join.ori (2026-02-17)
    • LLVM Support: LLVM codegen for iterator join
    • LLVM Rust Tests: ori_llvm/tests/debug_tests.rs
  • Update Spec: 06-types.md — add Debug trait section (verified 2026-02-17: already present)

  • Update Spec: 08-declarations.md — add Debug to derivable traits list (verified 2026-02-17: already present)

  • Update Spec: 12-modules.md — add Debug to prelude traits (verified 2026-02-17: already present)

  • Update: CLAUDE.md — add Debug to prelude traits list (verified 2026-02-17: already present, added .join to iterator methods)

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

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

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

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

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


3.10 Trait Resolution and Conflict Handling

STATUS: PARTIAL (verified 2026-03-29 — implemented items verified; blocked items correctly annotated with dependencies)

Proposal: proposals/approved/trait-resolution-conflicts-proposal.md

Specifies rules for resolving trait implementation conflicts: diamond problem, coherence/orphan rules, method resolution order, super trait calls, and extension method conflicts.

Implementation

  • Implement: Diamond problem resolution — single impl satisfies all inheritance paths

    • Rust Tests: ori_types/src/registry/traits/tests.rsall_super_traits_diamond, collected_methods_deduplication
    • Ori Tests: tests/spec/traits/resolution/diamond.ori
  • Implement: Conflicting default detection — error when multiple supertraits provide conflicting defaults (E2022)

    • Rust Tests: ori_types/src/registry/traits/tests.rsfind_conflicting_defaults covered in unit tests
    • Ori Tests: tests/compile-fail/conflicting_defaults.ori, tests/spec/traits/resolution/conflicting_defaults.ori
  • Implement: Coherence/orphan rules — at least one of trait or type must be local

    • Rust Tests: orphan rule tests
    • Ori Tests: tests/compile-fail/orphan_impl.ori
  • Implement: Blanket impl restrictions — orphan rules for impl<T> T: Trait

    • Rust Tests: blanket impl tests
    • Ori Tests: tests/compile-fail/orphan_blanket.ori
  • Implement: Method resolution order — Inherent > Trait > Extension priority

    • Rust Tests: ori_types/src/registry/traits/tests.rslookup_method_checked tests
    • Ori Tests: tests/spec/traits/resolution/method_priority.ori
    • LLVM Support: LLVM codegen for method resolution order dispatch
    • LLVM Rust Tests: ori_llvm/tests/trait_resolution_tests.rs — method resolution codegen
  • Implement: Ambiguous method detection (E2023) — error when multiple trait impls provide same method

    • Rust Tests: ori_types/src/registry/traits/tests.rsMethodLookupResult::Ambiguous tested
    • Ori Tests: tests/spec/traits/resolution/ambiguous_method.ori
    • Implement: Fully-qualified syntax Trait.method(x) for disambiguation
  • Implement: Super trait calls with Trait.method(self) syntax

    • Rust Tests: super call tests
    • Ori Tests: tests/spec/traits/resolution/super_calls.ori
    • LLVM Support: LLVM codegen for super trait call dispatch
    • LLVM Rust Tests: super trait call codegen
  • Implement: Extension method conflict detection (including re-exports)

    • Rust Tests: extension conflict tests
    • Ori Tests: tests/compile-fail/extension_conflict.ori
  • Implement: Associated type disambiguation with Type::Trait::AssocType syntax

    • Rust Tests: associated type disambiguation
    • Ori Tests: tests/spec/traits/resolution/assoc_type_disambiguation.ori
  • Implement: Implementation specificity (Concrete > Constrained > Generic)

    • Rust Tests: ori_types/src/registry/traits/tests.rsImplSpecificity enum + specificity-aware lookup
    • Ori Tests: tests/spec/traits/resolution/specificity.ori — needs generic impls in type checker
  • Implement: Overlapping impl detection — compile error for equal-specificity impls (E2021)

    • Rust Tests: ori_types/src/registry/traits/tests.rs — overlap detection in lookup_method_checked
    • Ori Tests: tests/compile-fail/overlapping_impls.ori — needs generic impls in type checker
  • Implement: Error codes E2010, E2021-E2023

    • E2010: Duplicate implementation — TypeErrorKind::DuplicateImpl, tests/compile-fail/duplicate_impl.ori
    • E2021: Overlapping implementations — TypeErrorKind::OverlappingImpls, errors/E2021.md
    • E2022: Conflicting defaults — TypeErrorKind::ConflictingDefaults, errors/E2022.md
    • E2023: Ambiguous method call — TypeErrorKind::AmbiguousMethod, errors/E2023.md
  • Update Spec: 08-declarations.md — coherence, resolution, super calls sections already present (lines 458-583); added error code cross-references (E2010, E2021, E2023) [done] (2026-02-18)

  • Update: CLAUDE.md — trait resolution rules already documented in .claude/rules/ori-syntax.md via Len trait and operator traits [done] (2026-02-18)

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

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

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

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

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


3.11 Object Safety Rules

STATUS: COMPLETE (verified 2026-03-29)

Proposal: proposals/approved/object-safety-rules-proposal.md

Formalizes the rules that determine whether a trait can be used as a trait object for dynamic dispatch. Defines three object safety rules and associated error codes.

Implementation

  • Implement: Object safety checking in type checker (2026-02-17)

    • ObjectSafetyViolation enum + TraitEntry::is_object_safe()ori_types/src/registry/traits/mod.rs
    • compute_object_safety_violations() at registration — ori_types/src/check/registration/mod.rs
    • check_parsed_type_object_safety() at signature sites — ori_types/src/check/signatures/mod.rs
    • Rust Tests: ori_types/src/check/registration/tests.rs — 11 tests
    • Ori Tests: tests/spec/traits/object_safety.ori
  • Implement: Rule 1 — No Self in return position (2026-02-17)

    • Rust Tests: self_return_violates_object_safety
    • Ori Compile-Fail Tests: tests/compile-fail/object_safety_self_return.ori
  • Implement: Rule 2 — No Self in parameter position (except receiver) (2026-02-17)

    • Rust Tests: self_param_violates_object_safety, self_in_receiver_position_is_allowed
    • Ori Compile-Fail Tests: tests/compile-fail/object_safety_self_param.ori
  • Implement: Rule 3 — No generic methods (2026-02-17)

    • ObjectSafetyViolation::GenericMethod variant exists in enum
    • Note: Cannot currently be violated — TraitMethodSig has no generics field; per-method generics are not yet parseable. Detection code ready for when syntax is added.
  • Implement: Error code E2024 (not object-safe) (2026-02-17)

    • Single error code following Rust’s E0038 pattern (proposal’s E0800-E0802 consolidated)
    • TypeErrorKind::NotObjectSafe variant with violation list
    • TypeCheckError::not_object_safe() constructor with per-violation suggestions
    • Rich formatting with method names and violation descriptions
    • Documentation: compiler/ori_diagnostic/src/errors/E2024.md
  • Implement: Object safety checking at trait object usage sites (2026-02-17)

    • ParsedType::Named — checks if name resolves to a non-object-safe trait
    • ParsedType::TraitBounds — checks each bound individually
    • Recursive walk through compound types (List, Map, Tuple, Function)
    • Ori Compile-Fail Tests: tests/compile-fail/object_safety_nested.ori
  • Implement: Bounded trait objects (Printable + Hashable) — all components must be object-safe (2026-02-17)

    • Ori Compile-Fail Tests: tests/compile-fail/object_safety_trait_bounds.ori
  • Spec: 06-types.md already has Object Safety section (lines 864-930) covering all three rules

  • Spec: 08-declarations.md already references object safety in trait design guidance


3.12 Custom Subscripting (Index Trait)

STATUS: Evaluator COMPLETE, LLVM NOT STARTED (verified 2026-03-29 — evaluator verified; no LLVM codegen tests)

Proposals:

  • proposals/approved/custom-subscripting-proposal.md — Design and motivation
  • proposals/approved/index-trait-proposal.md — Formal specification and error messages

Introduces the Index trait for read-only custom subscripting, allowing user-defined types to use [] syntax. Supports multiple index types per type (e.g., JsonValue with both str and int keys) and flexible return types (T, Option<T>, or Result<T, E>).

Implementation

  • Implement: Index<Key, Value> trait definition in prelude (2026-02-17)

    • Ori Tests: tests/spec/traits/index/definition.ori (2026-02-17)
    • Ori Tests: tests/spec/traits/index/option_return.ori (2026-02-17)
  • Implement: Desugaring x[k] to x.index(key: k) via type checker + evaluator fallback (2026-02-17)

    • Type checker: infer_index() falls back to resolve_index_via_trait() for non-builtin types
    • Evaluator: CanExpr::Index handler splits built-in (fast path) vs trait dispatch
    • LLVM Support: LLVM codegen for desugared index calls
    • LLVM Rust Tests: ori_llvm/tests/index_tests.rs
  • Implement: Type inference for subscript expressions (resolve which Index impl based on key type) (2026-02-17)

    • Replaced lookup_method_checked() with direct impls_for_type() iteration + key-type tag filtering
  • Implement: Multiple Index impls per type (different key types) (2026-02-17)

    • Type checker: resolve_index_via_trait filters candidates by key type tag, disambiguates single match
    • Evaluator: eval_index_user_type matches key_type_hint against runtime type
    • Registry: UserMethodRegistry stores Vec<UserMethod> per key, with lookup_all() for multi-dispatch
    • Canon IR: method_root_for_nth assigns correct canonical body to each impl
    • Ori Tests: tests/spec/traits/index/multiple_impls.ori (2026-02-17)
  • Implement: Built-in Index implementations for [T], [T, max N], {K: V}, str (2026-02-17)

    • These work via direct dispatch (hardcoded in infer_index and eval_index)
    • Formal trait impls (register in TraitRegistry for coherence) — deferred until generic impl support
    • Ori Tests: tests/spec/traits/index/builtin_impls.ori (2026-02-17)
    • LLVM Support: LLVM codegen for builtin Index impls
    • LLVM Rust Tests: ori_llvm/tests/index_tests.rs
  • Implement: Error messages for Index trait (E2025-E2027) (2026-02-17)

    • E2025: type does not implement Index (not indexable)
    • E2026: wrong key type for Index impl
    • E2027: ambiguous index key type (multiple impls match)
    • Error documentation: E2025.md, E2026.md, E2027.md
    • Ori Compile-Fail Tests: tests/compile-fail/index_no_impl.ori, tests/compile-fail/index_wrong_key.ori
  • Update Spec: 09-expressions.md — Index Trait section already complete with multiple impls, return types, built-in impls (2026-02-17)

  • Update Spec: 06-types.md — Index already listed in .claude/rules/ori-syntax.md traits list (2026-02-17)

  • Update: .claude/rules/ori-syntax.md — added multiple impls dispatch note to Index entry (2026-02-17)

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

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

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

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

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


3.13 Additional Core Traits

STATUS: Evaluator COMPLETE, LLVM PARTIAL (verified 2026-03-29 — Printable and Default have LLVM support; Traceable LLVM pending)

Proposal: proposals/approved/additional-traits-proposal.md

Formalizes three core traits: Printable, Default, and Traceable. The Iterable, Iterator, DoubleEndedIterator, and Collect traits are already defined in the spec and implemented in Section 3.8.

Implementation

  • Implement: Printable trait formal definition in type system [done] (2026-02-17)

    • Pre-existing: trait defined in prelude.ori, type checker registration in ori_types, evaluator dispatch, LLVM codegen
    • Rust Tests: Existing coverage in ori_types registration, ori_eval dispatch, ori_llvm derive_codegen
    • Ori Tests: tests/spec/traits/printable/definition.ori — 8 tests (int, float, bool, str, char, Ordering, generic bound, interpolation)
    • LLVM Support: LLVM codegen for Printable trait methods — existing in derive_codegen.rs
    • AOT Tests: ori_llvm/tests/aot/derives.rs — derive_printable_basic test passing
  • Implement: Printable derivation with Point(1, 2) format (type name + values) [done] (2026-02-17)

    • Fixed: eval_derived_to_str() and compile_derive_printable() now produce spec-compliant compact format
    • Added: format_value_printable() for recursive nested struct formatting (no quotes on strings)
    • Rust Tests: Existing coverage in ori_eval/derives, ori_llvm/derive_codegen
    • Ori Tests: tests/spec/traits/printable/derive.ori — 7 tests (basic, single field, mixed types, nested, many fields, printable-vs-debug, interpolation)
    • LLVM Support: LLVM codegen for Printable derivation — compile_derive_printable() updated
    • AOT Tests: ori_llvm/tests/aot/derives.rs — derive_printable_basic test passing
  • Implement: Default trait formal definition in type system (2026-02-17)

    • Pre-existing: trait defined in prelude.ori, type checker registration in ori_types, evaluator dispatch, LLVM codegen
    • Rust Tests: Existing coverage in ori_types registration, ori_eval derived_methods, ori_ir derives tests
    • Ori Tests: tests/spec/traits/default/definition.ori — 10 tests (int, float, bool, str defaults via struct fields, Duration/Size defaults, nested structs, deep nesting, idempotency) (2026-02-17)
    • LLVM Support: LLVM codegen for Default trait — compile_derive_default() in derive_codegen.rs
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 5 tests (basic, mixed_types, eq_integration, str_field, nested) (2026-02-17)
  • Implement: Default derivation for structs only (error on sum types) (2026-02-17)

    • Pre-existing: derive processing in ori_eval, LLVM codegen in derive_codegen.rs
    • Fixed: Added E2028 compile-time rejection of #[derive(Default)] on sum types (2026-02-17)
    • Rust Tests: Existing coverage in ori_ir/derives/tests.rs, ori_eval/derives
    • Ori Tests: tests/spec/traits/default/derive.ori — 7 tests (basic struct, single field, mixed fields, nested, eq integration, modify, multi-derive) (2026-02-17)
    • Ori Compile-Fail Tests: tests/compile-fail/default_sum_type.ori — E2028 error (2026-02-17)
    • LLVM Support: LLVM codegen for Default derivation — compile_derive_default() working
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 5 tests passing (2026-02-17)
  • Implement: Traceable trait formal definition in type system (2026-02-17)

    • Traceable trait with 4 methods (with_trace, trace, trace_entries, has_trace) in prelude.ori
    • TraceEntry struct registered as built-in type with 4 fields (function, file, line, column)
    • Error constructor added to type checker (infer_ident) and evaluator (function_val_error)
    • Rust Tests: ErrorValue construction/trace accumulation tests in ori_patterns, consistency tests in oric (2026-02-17)
    • Ori Tests: tests/spec/traits/traceable/definition.ori — 5 tests (2026-02-17)
    • LLVM Support: LLVM codegen for Traceable trait methods
    • LLVM Rust Tests: ori_llvm/tests/trait_method_tests.rs — Traceable codegen
  • Implement: Traceable for Error type with trace storage (2026-02-17)

    • Value::Error changed from String to Heap with trace Vec
    • ? operator injects trace entries via inject_trace_entry() in can_eval.rs
    • Error methods (trace, trace_entries, has_trace, with_trace, message) dispatched in methods/error.rs
    • Rust Tests: ErrorValue tests in ori_patterns, method dispatch tests in ori_eval (2026-02-17)
    • Ori Tests: tests/spec/traits/traceable/error_trace.ori — 7 tests, tests/spec/traits/traceable/no_trace.ori — 3 tests (2026-02-17)
    • LLVM Support: LLVM codegen for Traceable Error type
    • LLVM Rust Tests: ori_llvm/tests/trait_method_tests.rs — Traceable Error codegen
  • Implement: Traceable delegation for Result<T, E: Traceable> (2026-02-17)

    • Result.has_trace/trace/trace_entries delegate to inner Error value
    • Ok and non-Error Err return empty traces
    • Type checker recognizes trace methods on Result via TYPECK_BUILTIN_METHODS
    • Rust Tests: Consistency tests updated in oric (2026-02-17)
    • Ori Tests: tests/spec/traits/traceable/result_delegation.ori — 6 tests (2026-02-17)
    • LLVM Support: LLVM codegen for Traceable Result delegation
    • LLVM Rust Tests: ori_llvm/tests/trait_method_tests.rs — Traceable Result codegen
  • Implement: Error messages (E1040→E2038, E1042→E2028) (2026-02-18)

    • E2038: Missing Printable for string interpolation (was E1040) — TypeErrorKind::MissingPrintable, check in template literal inference, type_satisfies_trait + WellKnownNames updated with Printable for compound types; compile-fail test tests/compile-fail/interpolation_missing_printable.ori, Rust unit test printable_satisfaction_primitives_and_compounds (2026-02-18)
    • E2028: Cannot derive Default for sum type (was E1042) — implemented with TypeErrorKind::CannotDeriveDefaultForSumType (2026-02-17)
  • Update Spec: 09-properties-of-types.md — add Printable, Default, Traceable sections (verified 2026-02-17: already present)

  • Update: CLAUDE.md — traits documented in .claude/rules/ori-syntax.md (prelude traits, operator traits, iterator traits) [done] (verified 2026-02-18)

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

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

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

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

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


3.14 Comparable and Hashable Traits

STATUS: COMPLETE (verified 2026-03-29 — excellent coverage: 120+ test assertions, all relevant types covered, AOT coverage for list/tuple/option/result; map/set LLVM pending AOT collection infrastructure)

Proposal: proposals/approved/comparable-hashable-traits-proposal.md

Formalizes the Comparable and Hashable traits with complete definitions, mathematical invariants, standard implementations, and derivation rules. Adds Result<T, E> to both trait implementations and introduces hash_combine as a prelude function.

Phase boundary discipline: Each method must be implemented across ALL THREE phases (type checker → evaluator → LLVM codegen) before the type checker may accept it. Commit 01051607 added hash/equals to the type checker for compound types without evaluator/LLVM handlers — this was reverted in the hygiene review (see 3.7). When implementing items below, add to type checker LAST, after evaluator and LLVM codegen are working.

equals() on compound types is also tracked here. The Eq trait (3.0.6) covers primitives only. Collection/wrapper equals() methods (list, map, set, Option, Result, tuple) require the same all-phase implementation as hash().

Implementation

  • Implement: Formal Comparable trait definition in type system (2026-02-17)

    • Trait defined in library/std/prelude.ori: pub trait Comparable: Eq { @compare (self, other: Self) -> Ordering }
    • DerivedTrait::Comparable variant in ori_ir/src/derives/mod.rs
    • Trait registered in ori_types/src/check/registration/mod.rs
    • Ori Tests: tests/spec/traits/core/comparable.ori — 58 tests covering all types + operators
  • Implement: Comparable implementations for all primitives (int, float, bool, str, char, byte, Duration, Size) (2026-02-17)

    • Evaluator: ori_eval/src/methods/numeric.rs (int, float), variants.rs (bool, char, byte), collections.rs (str), units.rs (Duration, Size)
    • Type Checker: ori_types/src/infer/expr/methods.rs — compare() returns Ordering for all primitives
    • Ori Tests: tests/spec/traits/core/comparable.ori — all primitive compare() tests (58 tests)
    • LLVM Support: Primitive compare already in LLVM — ori_llvm/tests/aot/traits.rs (7 tests)
    • AOT Tests: ori_llvm/tests/aot/traits.rs — compare/is_less/is_equal/is_greater/reverse/is_less_or_equal/is_greater_or_equal
  • Implement: Comparable implementations for lists ([T]) (2026-02-17)

    • Evaluator: ori_eval/src/methods/collections.rs — dispatch_list_method with compare() via compare_lists()
    • Type Checker: ori_types/src/infer/expr/methods.rs — compare() returns Ordering for list
    • Ori Tests: tests/spec/traits/core/comparable.ori — list compare() tests (6 tests incl. empty, length diff)
    • LLVM Support: ori_llvm/src/codegen/lower_collection_methods.rsemit_list_compare() lexicographic loop with phi-merge (2026-02-18)
    • AOT Tests: ori_llvm/tests/aot/traits.rstest_aot_list_compare, test_aot_list_compare_empty (2026-02-18)
  • Implement: Comparable implementations for tuples (2026-02-17)

    • Evaluator: ori_eval/src/methods/compare.rs — lexicographic via compare_lists() (same logic)
    • Type Checker: ori_types/src/infer/expr/methods.rs — compare() returns Ordering for tuple
    • Ori Tests: tests/spec/traits/core/tuple_compare.ori — 6 tests (lexicographic ordering, field priority, tiebreakers)
    • LLVM Support: ori_llvm/src/codegen/lower_builtin_methods.rsemit_tuple_compare() lexicographic with phi-merge (2026-02-18)
    • AOT Tests: ori_llvm/tests/aot/traits.rstest_aot_tuple_compare (2026-02-18)
  • Implement: Comparable implementation for Option (2026-02-17)

    • Evaluator: ori_eval/src/methods/variants.rs — dispatch_option_method via compare_option_values() (None < Some)
    • Type Checker: ori_types/src/infer/expr/methods.rs — compare() returns Ordering for Option
    • Ori Tests: tests/spec/traits/core/comparable.ori — Option compare() tests (4 tests: None-None, None-Some, Some-Some)
    • LLVM Support: ori_llvm/src/codegen/lower_builtin_methods.rsemit_option_compare() with tag/payload branching (2026-02-18)
    • AOT Tests: ori_llvm/tests/aot/traits.rstest_aot_option_compare (2026-02-18)
  • Implement: Comparable implementation for Result<T, E> (2026-02-17)

    • Evaluator: ori_eval/src/methods/variants.rs — dispatch_result_method via compare_result_values() (Ok < Err)
    • Type Checker: ori_types/src/infer/expr/methods.rs — compare() returns Ordering for Result
    • Ori Tests: tests/spec/traits/core/comparable.ori — Result compare() tests (3 tests: Ok-Ok, Ok-Err, Err-Err)
    • LLVM Support: ori_llvm/src/codegen/lower_builtin_methods.rsemit_result_compare() with tag/payload branching (2026-02-18)
    • AOT Tests: ori_llvm/tests/aot/traits.rstest_aot_result_compare (2026-02-18)
  • Implement: Float IEEE 754 total ordering (NaN handling) (2026-02-17)

    • Evaluator: ori_eval/src/methods/numeric.rs — uses total_cmp() for IEEE 754 ordering
    • Ori Tests: tests/spec/traits/core/comparable.ori — float comparison tests
    • LLVM Support: Primitive float compare in LLVM (existing)
    • AOT Tests: ori_llvm/tests/aot/traits.rs — float compare tests
  • Implement: Comparable implementation for Ordering (2026-02-17)

    • Evaluator: ori_eval/src/methods/ordering.rs — dispatch_ordering_method with compare() (Less<Equal<Greater)
    • Type Checker: ori_types/src/infer/expr/methods.rs — compare() returns Ordering for Ordering
    • Ori Tests: tests/spec/traits/core/comparable.ori — Ordering compare() tests (3 tests)
    • LLVM Support: ori_llvm/src/codegen/lower_builtin_methods.rs — ordering compare via emit_icmp_ordering (2026-02-18)
    • AOT Tests: ori_llvm/tests/aot/traits.rstest_aot_ordering_compare (2026-02-18)
  • Implement: Comparison operator derivation (<, <=, >, >= via Ordering methods) (2026-02-15)

    • Completed as part of operator traits (3.21) — operators desugared to Comparable trait calls
    • Ori Tests: tests/spec/traits/core/comparable.ori — operator tests
    • LLVM Support: Operators compile via trait call desugaring
    • AOT Tests: ori_llvm/tests/aot/traits.rs — is_less/is_greater/etc.
  • Implement: Formal Hashable trait definition in type system (2026-02-17)

    • Trait defined in library/std/prelude.ori: pub trait Hashable: Eq { @hash (self) -> int }
    • DerivedTrait::Hashable variant in ori_ir/src/derives/mod.rs
    • Trait registered in ori_types/src/check/registration/mod.rs
    • Ori Tests: tests/spec/traits/core/compound_hash.ori — 17 tests covering all types + hash_combine
  • Implement: Hashable implementations for all primitives (int, float, bool, str, char, byte, Duration, Size) (2026-02-17)

    • Evaluator: ori_eval/src/methods/numeric.rs (int identity, float normalized), variants.rs (bool, char, byte), collections.rs (str), units.rs (Duration, Size), ordering.rs (Ordering)
    • Type Checker: ori_types/src/infer/expr/methods.rs — hash() returns int for all primitives
    • Ori Tests: tests/spec/traits/core/compound_hash.ori — primitive hash consistency tests
    • LLVM Support: ori_llvm/src/codegen/lower_builtin_methods.rs — bool/float/char/byte/ordering/str hash + ori_str_hash runtime (2026-02-18)
    • AOT Tests: ori_llvm/tests/aot/traits.rstest_aot_bool_hash, test_aot_float_hash, test_aot_char_hash, test_aot_str_hash (2026-02-18)
  • Implement: Hashable implementations for collections ([T], {K: V}, Set, tuples) (2026-02-17)

    • Evaluator: ori_eval/src/methods/collections.rs — list/map/set hash(); compare.rs — tuple hash via hash_value()
    • Type Checker: ori_types/src/infer/expr/methods.rs — hash() returns int for all collections
    • Ori Tests: tests/spec/traits/core/compound_hash.ori — collection hash tests (order-independent for map/set)
    • LLVM Support: List hash in lower_collection_methods.rsemit_list_hash() fold loop with hash_combine; tuple hash in lower_builtin_methods.rs (2026-02-18). Map/set hash pending AOT collection infrastructure.
    • AOT Tests: ori_llvm/tests/aot/traits.rstest_aot_list_hash, test_aot_list_hash_empty, test_aot_tuple_hash (2026-02-18). Map/set hash tests pending AOT collection infrastructure.
  • Implement: Hashable implementations for Option and Result<T, E> (2026-02-17)

    • Evaluator: ori_eval/src/methods/variants.rs — Option hash (None→0, Some→hash_combine(1,hash)); Result hash (Ok→hash_combine(2,hash), Err→hash_combine(3,hash))
    • Type Checker: ori_types/src/infer/expr/methods.rs — hash() returns int for Option/Result
    • Ori Tests: tests/spec/traits/core/compound_hash.ori — Option/Result hash tests
    • LLVM Support: ori_llvm/src/codegen/lower_builtin_methods.rsemit_option_hash(), emit_result_hash() with tag-based branching (2026-02-18)
    • AOT Tests: ori_llvm/tests/aot/traits.rstest_aot_option_hash, test_aot_result_hash (2026-02-18)
  • Implement: Float hashing consistency (+0.0 == -0.0, NaN == NaN for hash) (2026-02-17)

    • Evaluator: ori_eval/src/methods/compare.rshash_float() normalizes ±0.0 and NaN
    • Ori Tests: tests/spec/traits/core/compound_hash.ori — float hash consistency tests
    • LLVM Support: ori_llvm/src/codegen/lower_builtin_methods.rsnormalize_float_for_hash() (±0.0 → +0.0, NaN → canonical) (2026-02-18)
    • AOT Tests: ori_llvm/tests/aot/traits.rstest_aot_float_hash (2026-02-18)
  • Implement: hash_combine function in prelude (2026-02-17)

    • Evaluator: ori_eval/src/function_val.rsfunction_val_hash_combine() using boost hash combine algorithm
    • Registration: ori_eval/src/interpreter/mod.rs — registered in prelude via register_function_val()
    • Type Checker: ori_types/src/infer/expr/identifiers.rs — type signature (int, int) -> int
    • Ori Tests: tests/spec/traits/core/compound_hash.ori — hash_combine tests (3 tests)
    • LLVM Support: ori_llvm/src/codegen/lower_builtin_methods.rslower_builtin_hash_combine() + emit_hash_combine() (Boost algorithm) (2026-02-18)
    • AOT Tests: ori_llvm/tests/aot/traits.rstest_aot_hash_combine (2026-02-18)
  • Implement: #[derive(Comparable)] for user-defined types — evaluator only (2026-02-17)

    • Evaluator: ori_eval/src/interpreter/derived_methods.rseval_derived_compare() with lexicographic field comparison
    • IR: ori_ir/src/derives/mod.rsDerivedTrait::Comparable + method_name() returns “compare”
    • IR Tests: ori_ir/src/derives/tests.rs — from_name/method_name tests
    • Ori Tests: tests/spec/traits/derive/comparable.ori — 6 tests (basic, lexicographic, single-field)
    • LLVM Support: ori_llvm/src/codegen/derive_codegen/mod.rscompile_derived_compare() with lexicographic field comparison (2026-02-18)
    • AOT Tests: ori_llvm/tests/aot/derives.rstest_aot_derive_comparable_basic, comparable_first_field_wins, comparable_single_field, comparable_with_strings (2026-02-18)
  • Implement: #[derive(Hashable)] for user-defined types — all phases (2026-02-17)

    • Evaluator: ori_eval/src/interpreter/derived_methods.rseval_derived_hash() with field hash combination
    • IR: ori_ir/src/derives/mod.rsDerivedTrait::Hashable + method_name() returns “hash”
    • LLVM Support: ori_llvm/src/codegen/derive_codegen/mod.rs — FNV-1a hash in pure LLVM IR
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 2 tests (equal values, different values)
    • Ori Tests: tests/spec/traits/core/compound_hash.ori — hash consistency + struct hash tests
  • Implement: Error messages (E2029-E2031, remapped from E0940-E0942) (2026-02-18)

    • E2029: Cannot derive Hashable without Eq — validation in register_derived_impl(), compile-fail test, Rust unit tests
    • E2030: Hashable implementation violates hash invariant — infrastructure complete (error code, TypeErrorKind, diagnostics, docs); detection deferred until manual trait impls exist
    • E2031: Type cannot be used as map key (missing Hashable) — validation in check_map_key_hashable(), compile-fail test
    • Fixed 5 AOT derive hash tests that derived Hashable without Eq (now correctly caught by E2029)
  • Update Spec: 09-properties-of-types.md — Comparable and Hashable sections already present; updated E2029/E2031 error references (2026-02-18)

  • Update Spec: 12-modules.md — hash_combine already documented in prelude functions (2026-02-18)

  • Update: CLAUDE.md — added Comparable, Hashable, hash_combine, derive validation docs (2026-02-18)

  • Implement: equals() on compound types (Eq trait extension beyond primitives) (2026-02-17)

    • Evaluator: ori_eval/src/methods/collections.rs — list element-wise, map key-set+value, set element-wise equality
    • Evaluator: ori_eval/src/methods/variants.rs — Option tag+inner, Result tag+inner equality
    • Evaluator: ori_eval/src/methods/compare.rs — tuple element-wise via equals_values()
    • Type checker: ori_types/src/infer/expr/methods.rsequals registered for all compound types
    • Ori Tests: tests/spec/traits/core/compound_equals.ori — 12 tests (list, map, Option, Result, tuple)
    • LLVM codegen: List equals in lower_collection_methods.rsemit_list_equals() length check + element-wise loop; Option/Result/Tuple in lower_builtin_methods.rs (2026-02-18). Map/set equals pending AOT collection infrastructure.
    • AOT Tests: test_aot_list_equals, test_aot_list_equals_empty, test_aot_option_equals, test_aot_result_equals, test_aot_tuple_equals (2026-02-18). Map/set equals tests pending AOT collection infrastructure.

3.15 Derived Traits Formal Semantics

STATUS: Evaluator COMPLETE, LLVM PARTIAL (verified 2026-03-29 — 90+ evaluator tests across 12 files; LLVM gaps: sum type Eq, Debug, generic conditional, recursive derive)

Proposal: proposals/approved/derived-traits-proposal.md

Formalizes the #derive attribute semantics: derivable traits list, derivation rules, field constraints, generic type handling, and error messages.

Implementation

  • Implement: Eq derivation for structs — field-wise equality (2026-02-18)

    • Ori Tests: tests/spec/traits/derive/eq.ori — 22 struct tests
    • LLVM Support: LLVM codegen for Eq struct derivation (pre-existing)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 5 Eq struct AOT tests
  • Implement: Eq derivation for sum types — variant matching (2026-02-18)

    • Ori Tests: tests/spec/traits/derive/eq_sum.ori — 15 sum type tests
    • LLVM Support: LLVM codegen for Eq sum type derivation
    • AOT Tests: AOT tests for Eq sum type derive codegen
  • Implement: Hashable derivation — combined field hashes via hash_combine (2026-02-18)

    • Ori Tests: tests/spec/traits/derive/hashable.ori — 11 tests
    • LLVM Support: LLVM codegen for Hashable derivation (pre-existing)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 4 Hashable AOT tests
  • Implement: Comparable derivation — lexicographic field comparison (2026-02-18)

    • Ori Tests: tests/spec/traits/derive/comparable_sum.ori — 10 tests
    • LLVM Support: LLVM codegen for Comparable derivation (pre-existing)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 4 Comparable AOT tests
  • Implement: Clone derivation — field-wise clone (2026-02-18)

    • Ori Tests: tests/spec/traits/derive/clone.ori — 8 tests
    • LLVM Support: LLVM codegen for Clone derivation (pre-existing)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 6 Clone AOT tests
  • Implement: Default derivation for structs only (2026-02-18)

    • Ori Compile-Fail Tests: tests/compile-fail/default_sum_type.ori (pre-existing)
    • LLVM Support: LLVM codegen for Default derivation (pre-existing)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 5 Default AOT tests
  • Implement: Debug derivation — structural representation with type name (2026-02-18)

    • Ori Tests: tests/spec/traits/derive/debug.ori — 5 tests
    • LLVM Support: LLVM codegen for Debug derivation (deferred — evaluator-only)
    • AOT Tests: AOT tests for Debug derive codegen
  • Implement: Printable derivation — human-readable format TypeName(field1, field2) (2026-02-18)

    • Ori Tests: tests/spec/traits/derive/printable.ori — 6 tests
    • LLVM Support: LLVM codegen for Printable derivation (pre-existing)
    • AOT Tests: ori_llvm/tests/aot/derives.rs — 1 Printable AOT test
  • Implement: Generic type conditional derivation — bounded impls (2026-02-18)

    • Ori Tests: tests/spec/traits/derive/generic.ori — 5 tests (Eq + Clone on Pair)
    • LLVM Support: LLVM codegen for generic conditional derivation
    • AOT Tests: AOT tests for generic derive codegen
  • Implement: Recursive type derivation (2026-02-18)

    • Ori Tests: tests/spec/traits/derive/recursive.ori — 8 tests (Eq + Clone + Printable on Tree)
    • LLVM Support: LLVM codegen for recursive type derivation
    • AOT Tests: AOT tests for recursive derive codegen
  • Implement: Error messages for derive validation (2026-02-18)

    • E2032: Field type does not implement trait required by derive (was E0880)
    • E2033: Trait cannot be derived (was E0881)
    • E2028: Cannot derive Default for sum type (was E0882, pre-existing)
    • Compile-Fail Tests: tests/compile-fail/derive_field_missing_trait.ori, tests/compile-fail/derive_not_derivable.ori
  • W0100 superseded by E2029 — Hashable has supertrait Eq, making this a hard error (2026-02-18)

  • Update Spec: 06-types.md — Derive section already comprehensive (lines 775-837): derivable traits table, rules, generics, recursion, non-derivable [done] (verified 2026-02-18)

  • Update Spec: 09-properties-of-types.md — derive semantics covered via individual trait sections (Eq, Comparable, Hashable each reference derivation) [done] (verified 2026-02-18)

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

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

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

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

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


3.16 Formattable Trait

STATUS: COMPLETE (verified 2026-03-29 — 8 evaluator test files + 17 AOT tests; one documented GAP: user-defined Formattable::format() LLVM codegen blocked by general trait method call codegen)

Proposal: proposals/approved/formattable-trait-proposal.md

Formalizes the Formattable trait and format specification syntax for customized string formatting. Defines FormatSpec type structure, format spec syntax, and the relationship between Formattable and Printable via blanket implementation.

Implementation

  • Implement: Formattable trait definition in type system (2026-02-18)

    • Trait registered in ori_types/src/check/registration/mod.rs
    • Trait signature uses spec: FormatSpec per spec
    • Ori Tests: tests/spec/traits/formattable/definition.ori
  • Implement: FormatSpec type and related types (Alignment, Sign, FormatType) in prelude (2026-02-18)

    • Alignment enum (Left, Center, Right) registered in type system
    • Sign enum (Plus, Minus, Space) registered in type system
    • FormatType enum (Binary, Octal, Hex, HexUpper, Exp, ExpUpper, Fixed, Percent) registered
    • FormatSpec struct with 6 Option fields registered
    • Variant identifiers resolve in type checker (ori_types/src/infer/expr/identifiers.rs)
    • Variant globals registered in evaluator prelude (ori_eval/src/interpreter/mod.rs)
    • Type definitions in library/std/prelude.ori
    • Ori Tests: tests/spec/traits/formattable/format_spec_type.ori
  • Implement: Format spec parsing in template strings (pre-existing)

    • Parser in ori_ir/src/format_spec.rs — handles [[fill]align][sign][#][0][width][.precision][type]
    • Validation in type checker with E2034/E2035 errors
    • LLVM Support: LLVM codegen for FormatWith expressions (ori_llvm/src/codegen/lower_constructs.rs)
    • AOT Tests: ori_llvm/tests/aot/formattable.rs — 17 AOT tests (2026-02-18)
  • Implement: Blanket Formattable implementation for Printable types (2026-02-18)

    • Evaluator fallback via display_value() + alignment in ori_eval/src/interpreter/format.rs
    • Ori Tests: tests/spec/traits/formattable/blanket.ori
  • Implement: Formattable for int with binary, octal, hex format types (pre-existing, LLVM 2026-02-18)

    • Evaluator: ori_eval/src/interpreter/format.rs — full int formatting
    • Ori Tests: tests/spec/traits/formattable/int.ori
    • LLVM Support: ori_rt/src/format.rsori_format_int runtime function
    • AOT Tests: AOT tests cover hex, binary, octal, sign, zero-pad, width/align
  • Implement: Formattable for float with scientific, fixed, percentage format types (pre-existing, LLVM 2026-02-18)

    • Evaluator: ori_eval/src/interpreter/format.rs — full float formatting
    • Ori Tests: tests/spec/traits/formattable/float.ori
    • LLVM Support: ori_rt/src/format.rsori_format_float runtime function
    • AOT Tests: AOT tests cover fixed, precision, percent, sign
  • Implement: Formattable for str with width, alignment, precision (pre-existing, LLVM 2026-02-18)

    • Evaluator: ori_eval/src/interpreter/format.rs — full str formatting
    • Ori Tests: tests/spec/traits/formattable/definition.ori
    • LLVM Support: ori_rt/src/format.rsori_format_str runtime function
    • AOT Tests: AOT tests cover width, fill, precision
  • Implement: Sign specifiers (+, -, ) for numeric formatting (pre-existing)

    • Covered in int.ori and float.ori tests
  • Implement: Alternate form (#) for prefix formatting (0b, 0o, 0x) (pre-existing)

    • Covered in int.ori tests
  • Implement: Zero-pad shorthand (0) for numeric formatting (pre-existing)

    • Covered in int.ori tests
  • Implement: Custom fill characters (2026-02-18)

    • Ori Tests: tests/spec/traits/formattable/fill.ori
    • AOT test: test_aot_format_fill_center
  • Implement: User-defined Formattable with FormatSpec dispatch (2026-02-18)

    • Evaluator constructs Value::Struct(FormatSpec{...}) for user-type dispatch
    • Ori Tests: tests/spec/traits/formattable/user_impl.ori
    • GAP(formattable-aot): LLVM codegen for user Formattable::format() impls requires general trait method call codegen. Currently blocked with record_codegen_error() at lower_constructs.rs. Evaluator works correctly.
  • Implement: Edge cases (bool, char, empty spec, negative hex, zero precision) (2026-02-18)

    • Ori Tests: tests/spec/traits/formattable/edge_cases.ori
    • LLVM Support: ori_rt/src/format.rsori_format_bool, ori_format_char runtime functions
  • Implement: Error messages E2034-E2035 (pre-existing, renumbered from E0970-E0971)

    • E2034: Invalid format specification syntax
    • E2035: Format type not supported for this type
  • Update Spec: 09-properties-of-types.md — Formattable trait section present (pre-existing)

  • Update Spec: 12-modules.md — FormatSpec, Alignment, Sign, FormatType in prelude types (pre-existing)

  • LLVM str.concat() support: Added string concatenation method to LLVM backend (2026-02-18)

    • Required for template string desugaring (.concat() chains)
    • ori_llvm/src/codegen/lower_builtin_methods.rsemit_str_concat_call()

3.17 Into Trait

STATUS: Evaluator COMPLETE, LLVM PARTIAL (verified 2026-03-29 — int->float LLVM done; str->Error blocked by Error type LLVM repr; orphan rules blocked by module system)

Proposal: proposals/approved/into-trait-proposal.md

Formalizes the Into trait for semantic, lossless type conversions. Defines trait signature, standard implementations, relationship to as/as?, and rules for custom implementations.

Implementation

  • Implement: Into<T> trait definition in type system

    • Rust Tests: ori_types/src/infer/expr/tests.rsinto_not_on_named_types_via_builtins (trait dispatch path)
    • Ori Tests: tests/spec/traits/into/definition.ori
  • Implement: Into implementation for str→Error

    • Rust Tests: ori_types/src/infer/expr/tests.rsinto_str_resolves_to_error
    • Ori Tests: tests/spec/traits/into/str_to_error.ori
    • LLVM Support: LLVM codegen for str→Error conversion (blocked: Error type has no LLVM representation — TypeInfo::Error is a sentinel)
    • AOT Tests: ori_llvm/tests/aot/traits.rs — str→Error AOT
  • Implement: Into implementation for int→float (numeric widening)

    • Rust Tests: ori_types/src/infer/expr/tests.rsinto_int_resolves_to_float
    • Ori Tests: tests/spec/traits/into/int_to_float.ori
    • LLVM Support: LLVM codegen for int→float conversion (sitofp)
    • AOT Tests: ori_llvm/tests/aot/traits.rs — 3 AOT tests (basic, negative, zero)
  • Implement: Into implementation for Set→[T] (with T: Eq + Hashable constraint)

    • Rust Tests: ori_types/src/infer/expr/tests.rsinto_set_resolves_to_list, into_set_preserves_element_type
    • Ori Tests: tests/spec/traits/into/set_to_list.ori
    • LLVM Support: LLVM codegen for Set→List conversion (identity — same layout)
    • AOT Tests: ori_llvm/tests/aot/traits.rs — Set→List AOT
  • Implement: Custom Into implementations for user types

    • Rust Tests: ori_types/src/infer/expr/tests.rsinto_not_on_named_types_via_builtins (verifies trait registry dispatch path)
    • Ori Tests: tests/spec/traits/into/definition.ori (Celsius→str, Wrapper→int)
  • Implement: No blanket identity (no impl Into for T)

    • Ori Tests: tests/compile-fail/into_no_identity.ori
  • Implement: No automatic conversion chaining

    • Ori Tests: tests/compile-fail/into_no_chaining.ori
  • Implement: Orphan rule enforcement for Into implementations

    • Rust Tests: ori_types/src/check/tests.rs — orphan rule tests
    • Ori Compile-Fail Tests: tests/compile-fail/into_orphan_rule.ori
  • Implement: Error messages (E2036-E2037)

    • E2036: Type does not implement Into
    • E2037: Multiple Into implementations apply (ambiguous)
  • Update Spec: 09-properties-of-types.md — Into trait section (already present, fixed error codes E0960→E2036, E0961→E2037)

  • Update Spec: 12-modules.md — Into already in prelude traits list (verified)

  • Update: .claude/rules/ori-syntax.md — Into already documented in prelude traits (verified)

Note: str.into() returns Idx::ERROR directly (pre-interned primitive) rather than pool.named("Error"). The WellKnownNames.error_type field was removed as unused. If a future feature needs to resolve “Error” by name at type-check time, re-add it to well_known.rs. Error.message field access is implemented in both type checker (infer_field in structs.rs) and evaluator (eval_field_access in expr.rs) — if more Error fields are added (e.g. .source), update both.

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

3.18 Ordering Type

STATUS: COMPLETE (verified 2026-03-29 — 41 spec tests, all methods complete; only Ordering.default() deferred, blocked by static method support)

Proposal: proposals/approved/ordering-type-proposal.md

Formalizes the Ordering type that represents comparison results. Defines the three variants (Less, Equal, Greater), methods (is_less, is_equal, is_greater, is_less_or_equal, is_greater_or_equal, reverse, then, then_with), and trait implementations.

Implementation

  • Implement: Ordering type definition (already in spec as type Ordering = Less | Equal | Greater) [done] (2026-02-10)

    • Type checking via Type::Named("Ordering")
    • Runtime values via Value::Variant { type_name: "Ordering", ... }
    • Variants available as bare names: Less, Equal, Greater are registered as built-in enum variants
      • Type registry: register_builtin_types() in ori_types/src/check/registration/mod.rs
      • Evaluator: register_prelude() in ori_eval/src/interpreter/mod.rs
    • Ori Tests: tests/spec/types/ordering/methods.ori — 32 tests (all pass)
  • Implement: Ordering predicate methods (is_less, is_equal, is_greater, is_less_or_equal, is_greater_or_equal) [done] (2026-02-10)

    • Type checker: ori_types/src/infer/ordering.rs
    • Evaluator: ori_eval/src/methods.rsdispatch_ordering_method
    • Ori Tests: tests/spec/types/ordering/methods.ori — 15 predicate tests (all pass)
    • LLVM Support: i8 comparison/arithmetic in lower_calls.rs
  • Implement: reverse method for Ordering [done] (2026-02-10)

    • Type checker: Returns Type::Named("Ordering")
    • Evaluator: Swaps Less↔Greater, preserves Equal
    • Ori Tests: tests/spec/types/ordering/methods.ori — 4 reverse tests including involution
  • Implement: then method for lexicographic comparison chaining [done] (2026-02-15)

    • Keyword conflict resolved: keywords now valid as member names after . (grammar.ebnf § member_name)
    • Parser: expect_member_name() in cursor, used by postfix.rs
    • Type checker: resolve_ordering_method() — returns Idx::ORDERING
    • Evaluator: dispatch_ordering_method() — Equal chains, non-Equal keeps self
    • IR registry: builtin_methods.rsMethodDef with ParamSpec::SelfType
    • Eval registry: EVAL_BUILTIN_METHODS("Ordering", "then")
    • Ori Tests: tests/spec/types/ordering/methods.ori — 5 tests (equal chains, non-equal keeps self, chaining)
    • Rust Tests: ori_eval/src/tests/methods_tests.rsthen_equal_chains, then_non_equal_keeps_self
  • Implement: then_with method for lazy lexicographic chaining (2026-02-18)

    • Dispatched via CollectionMethodResolverOrderingThenWith (closure needs interpreter access)
    • Type checker: resolve_ordering_method() — returns Idx::ORDERING
    • Collection resolver: CollectionMethod::OrderingThenWith variant + resolution on Value::Ordering
    • Method dispatch: eval_ordering_then_with() — Equal calls closure, non-Equal returns self
    • Rust Tests: ori_types/src/infer/expr/tests.rsthen_with_ordering_resolves_to_ordering
    • Ori Tests: tests/spec/types/ordering/then_with.ori — 9 tests (equal/non-equal, laziness, chaining)
  • Implement: Trait methods for Ordering (Clone, Printable, Hashable) [done] (2026-02-10)

    • clone() → returns self — verified in ordering/methods.ori
    • to_str() → “Less”/“Equal”/“Greater” — verified in ordering/methods.ori
    • debug() → “Less”/“Equal”/“Greater” — implemented via generic Debug dispatch [done] (2026-02-18)
    • hash() → distinct values for each variant — verified in ordering/methods.ori
  • Implement: Default value is Equal (via associated function Ordering.default()) — NOT testable (static methods not supported)

  • Update Spec: 06-types.md — Ordering section already comprehensive (lines 571-615): variants, methods, then/then_with, trait impls, default [done] (verified 2026-02-18)

  • Update: CLAUDE.md — Ordering methods documented in .claude/rules/ori-syntax.md [done] (verified 2026-02-18)


3.19 Default Type Parameters on Traits

STATUS: COMPLETE (verified 2026-03-29 — WEAK TESTS: only 2 spec tests for this feature)

Proposal: proposals/approved/default-type-parameters-proposal.md

Allow type parameters on traits to have default values, enabling trait Add<Rhs = Self> where Rhs defaults to Self if not specified. Essential prerequisite for operator traits.

Implementation

  • Implement: Parse default type in type_param grammar rule (identifier [ ":" bounds ] [ "=" type ]) [done] (2026-02-10)

    • Rust Tests: ori_parse/src/grammar/item/generics.rsparse_generics() handles = Type after bounds
    • Ori Tests: tests/spec/traits/default_type_params.ori — 2 tests (all pass)
  • Implement: Store default types in trait definition AST [done] (2026-02-10)

    • Rust Tests: GenericParam in ori_ir/src/ast/items/traits.rs has default_type: Option<ParsedType>
    • Rust Tests: TraitEntry in ori_types/src/check/registration/ (trait types) has default_types: Vec<Option<ParsedType>>
  • Implement: Fill missing type arguments with defaults in impl checking [done] (2026-02-10)

    • Rust Tests: resolve_trait_type_args() in trait_registration.rs
    • Ori Tests: tests/spec/traits/default_type_params.oriimpl Point: Addable omits Rhs, uses Self default
  • Implement: Substitute Self with implementing type in defaults [done] (2026-02-10)

    • Rust Tests: resolve_parsed_type_with_self_substitution() in trait_registration.rs
    • Ori Tests: tests/spec/traits/default_type_params.oritest_add uses Self default
  • Implement: Ordering constraint enforcement (defaults must follow non-defaults) [done] (2026-02-10)

    • Rust Tests: validate_default_type_param_ordering() in trait_registration.rs
    • Error Code: E2015 (type parameter ordering violation)
  • Implement: Later parameters can reference earlier ones in defaults [done] (2026-02-10)

    • Design: Stored as ParsedType, resolved at impl time with substitution
    • Verified: trait Transform<Input = Self, Output = Input> in default_type_params.ori
  • Update Spec: grammar.ebnf § Generics — type_param = identifier [ ":" bounds ] [ "=" type ] . [done] (verified 2026-02-15, already present)

  • Update Spec: 08-declarations.md — Default Type Parameters section under Traits [done] (verified 2026-02-15, already present at line 230)

  • Update: CLAUDE.mdtrait N<T = Self> syntax documented [done] (verified 2026-02-15, already in ori-syntax.md)


3.20 Default Associated Types

STATUS: COMPLETE (verified 2026-03-29 — bounds checking on defaults deferred)

Proposal: proposals/approved/default-associated-types-proposal.md

Allow associated types in traits to have default values, enabling type Output = Self where implementors can omit the associated type if the default is acceptable. Works alongside default type parameters to enable operator traits.

Implementation

  • Implement: Parse default type in assoc_type grammar rule ("type" identifier [ ":" bounds ] [ "=" type ]) [done] (2026-02-10)

    • Rust Tests: ori_parse/src/grammar/item/trait_def.rs — default assoc type parsing
    • Ori Tests: tests/spec/traits/default_assoc_types.ori — 4 tests (all pass)
  • Implement: Store default types in trait definition AST for associated types [done] (2026-02-10)

    • Rust Tests: ori_ir/src/ast/items/traits.rsTraitAssocType.default_type: Option<ParsedType>
  • Implement: Fill missing associated types with defaults in impl checking [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/registration/ (trait registration)validate_associated_types() uses defaults
    • Ori Tests: tests/spec/traits/default_assoc_types.ori — Point impl omits Output, uses Self default
  • Implement: Substitute Self with implementing type in defaults [done] (2026-02-10)

    • Rust Tests: ori_types/src/check/ (trait registry)resolve_parsed_type_with_self_substitution()
    • Ori Tests: tests/spec/traits/default_assoc_types.ori — verified with Point (default Output=Self) and Number (overridden Output=int)
  • Implement: Defaults can reference type parameters and other associated types [done] (2026-02-10)

    • Note: Basic support implemented; complex cascading defaults deferred
  • Implement: Bounds checking — verify default satisfies any bounds after substitution

    • Note: Deferred to future enhancement; bounds on associated types not yet fully implemented
  • Update Spec: grammar.ebnf — update assoc_type production [done] (verified 2026-02-15, already present: assoc_type = "type" identifier [ ":" bounds ] [ "=" type ])

  • Update Spec: 08-declarations.md — add Default Associated Types section [done] (verified 2026-02-15, already present at line 272 with bounds section)

  • Update: CLAUDE.md — add default associated type syntax to Traits section [done] (verified 2026-02-15, already in ori-syntax.md: type Output = Self default)


3.21 Operator Traits

STATUS: COMPLETE (verified 2026-03-29 — type checker desugaring, evaluator dispatch, LLVM codegen, error messages all working; derive for newtypes optional/deferred; MatMul 3.21.1 not started)

Proposal: proposals/approved/operator-traits-proposal.md

Defines traits for arithmetic, bitwise, and unary operators that user-defined types can implement to support operator syntax. The compiler desugars operators to trait method calls. Enables Duration and Size types to move to stdlib.

Dependencies

  • Default Type Parameters on Traits (3.19) — for trait Add<Rhs = Self> [done] (2026-02-10)
  • Default Associated Types (3.20) — for type Output = Self [done] (2026-02-10)

Implementation

  • Implement: Define operator traits in prelude (via trait registry lookup) [done] (2026-02-15)

    • Add<Rhs = Self>, Sub<Rhs = Self>, Mul<Rhs = Self>, Div<Rhs = Self>, FloorDiv<Rhs = Self>, Rem<Rhs = Self>
    • Neg, Not, BitNot
    • BitAnd<Rhs = Self>, BitOr<Rhs = Self>, BitXor<Rhs = Self>, Shl<Rhs = int>, Shr<Rhs = int>
    • Files: library/std/prelude.ori — all operator traits defined with associated Output type
    • Ori Tests: tests/spec/traits/operators/user_defined.ori — 16 tests covering all operators
  • Implement: Operator desugaring in type checker [done] (2026-02-15)

    • a + ba.add(rhs: b) (etc. for all binary operators)
    • -aa.negate(), !aa.not(), ~aa.bit_not() (unary operators)
    • Files: ori_types/src/infer/expr/operators.rsresolve_binary_op_via_trait(), resolve_unary_op_via_trait()
    • Files: ori_types/src/infer/mod.rsintern_name() helper on InferEngine
  • Implement: Operator dispatch in evaluator via trait impls [done] (2026-02-15)

    • Files: ori_eval/src/interpreter/mod.rseval_binary(), binary_op_to_method()
    • Files: ori_eval/src/methods.rs — operator methods for primitives
    • Ori Tests: tests/spec/traits/operators/user_defined.ori — 16 tests (Add, Sub, Neg, Mul, Div, Rem, FloorDiv, BitAnd, BitOr, BitXor, Shl, Shr, BitNot, Not, chaining, double negation)
    • LLVM Support: LLVM codegen for operator trait dispatch — Tier 1 (lower_operators.rs) and Tier 2 (arc_emitter.rs) [done] (2026-02-15)
    • AOT Tests: ori_llvm/tests/aot/traits.rs — 7 AOT tests (add, sub, neg, mul_mixed, chained, bitwise, not) [done] (2026-02-15)
  • Implement: Built-in operator implementations for primitives (NOT trait-based, direct evaluator dispatch) [done] (2026-02-10)

    • int: Add, Sub, Mul, Div, FloorDiv, Rem, Neg, BitAnd, BitOr, BitXor, Shl, Shr, BitNot
    • float: Add, Sub, Mul, Div, Neg
    • bool: Not
    • str: Add (concatenation)
    • list: Add (concatenation)
    • Duration: Add, Sub, Mul (with int), Div (with int), Rem, Neg
    • Size: Add, Sub, Mul (with int), Div (with int), Rem
    • Files: ori_eval/src/methods.rsdispatch_int_method(), dispatch_float_method(), etc.
  • Implement: User-defined operator implementations [done] (2026-02-15)

    • Ori Tests: tests/spec/traits/operators/user_defined.ori — 16 tests all passing
    • Type checker desugars a + b to a.add(rhs: b) via TraitRegistry lookup
    • Evaluator dispatches to impl methods for non-primitive types
  • Implement: Mixed-type operations with explicit both-direction impls [done] (2026-02-10)

    • Example: Duration * int and int * Duration
    • Files: ori_eval/src/interpreter/mod.rsis_mixed_primitive_op()
  • Implement: Error messages for missing operator trait implementations [done] (2026-02-15)

    • E2020: Type does not implement operator trait (for user-defined types)
    • Primitives keep original error messages (e.g., “cannot apply - to str”)
    • Files: ori_types/src/type_error/check_error/mod.rsUnsupportedOperator variant
    • Files: ori_diagnostic/src/error_code/mod.rs — E2020 error code
    • Files: ori_diagnostic/src/errors/E2020.md — error documentation
    • Ori Compile-Fail Tests: tests/compile-fail/operator_trait_missing.ori — 5 tests (Add, Neg, Not, BitNot, BitAnd)
  • Implement: Derive support for operator traits on newtypes (OPTIONAL)

    • #derive(Add, Sub, Mul, Div) generates field-wise operations
    • Rust Tests: ori_types/src/check/ (derives) — operator derive tests
    • Ori Tests: tests/spec/traits/operators/derive.ori
  • Update Spec: 09-expressions.md — Operator Traits section [done] (verified 2026-02-15, already present at line 403 with full trait/method/desugaring tables)

  • Update: CLAUDE.md — operator traits in prelude and operators section [done] (verified 2026-02-15, already in ori-syntax.md lines 93 and 191)

3.21.1 MatMul Operator (@)

Proposal: proposals/approved/matmul-operator-proposal.md

Add @ as a binary operator for matrix multiplication at multiplicative precedence (level 3), desugaring to the MatMul trait method matrix_multiply(). Follows Python PEP 465 convention for ML/scientific computing adoption. The @ token is disambiguated by parser context (item position = function sigil, expression position = matmul operator, pattern position = binding).

Dependencies

  • Operator Traits (3.21) — trait dispatch infrastructure [done]

Implementation

  • Implement: Add MatMul variant to BinaryOp in IR

    • BinaryOp::MatMul + arms in as_symbol(), precedence(), trait_method_name(), trait_name()
    • Files: ori_ir/src/ast/operators.rs
    • Rust Tests: ori_ir/src/ast/operators/tests.rs
  • Implement: Parser — add TokenKind::At to multiplicative precedence level

    • Add entry to OPER_TABLE in grammar/expr/operators.rs
    • Files: ori_parse/src/grammar/expr/operators.rs
    • Rust Tests: ori_parse/src/grammar/expr/operators/tests.rs — matmul parsing
    • Ori Tests: tests/spec/operators/matmul.ori — precedence, associativity, disambiguation
  • Implement: Evaluator — add BinaryOp::MatMul error arms to primitive type handlers

    • ~17 match arms returning “type does not implement MatMul” for all primitive handlers
    • Files: ori_eval/src/operators.rs
  • Implement: Define MatMul trait in prelude

    • trait MatMul<Rhs = Self> { type Output = Self; @matrix_multiply (self, rhs: Rhs) -> Self.Output }
    • Files: library/std/prelude.ori
    • Ori Tests: tests/spec/traits/operators/matmul.ori — user-defined MatMul impl
  • Implement: LLVM codegen support

    • Falls through via trait dispatch — verify no special-casing needed
    • AOT Tests: ori_llvm/tests/aot/traits.rs — matmul codegen test
  • Update Spec: operator-rules.md — add @ to multiplicative group and trait dispatch table

  • Update Spec: grammar.ebnf — add "@" to mul_expr production

  • Update: .claude/rules/ori-syntax.md — document @ operator and MatMul trait

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

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

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

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

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


3.22 Bound Syntax — ELIMINATED (Capability Unification)

STATUS: ELIMINATED (verified 2026-03-29 — correctly eliminated per 2026-03-04 capability-unification decision)

Proposal: proposals/approved/capability-unification-generics-proposal.md — Phase 2 (eliminated)

Status: This section is no longer needed. The 2026-03-04 addendum to the capability-unification-generics-proposal decided to retain : for all bound positions (generic parameters, where clauses, supertrait declarations, impl block bounds). No parser changes, no test migration, no spec updates for bound syntax. Only the #derive: trait clause on type declarations is a new syntax change (tracked in Section 5).

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

3.23 Impl Colon Syntax

STATUS: NOT STARTED (verified 2026-03-29 — all items unchecked)

Proposal: proposals/approved/impl-colon-syntax-proposal.md

Replace impl Trait for Type with impl Type: Trait — subject-first ordering, completes : = “conforms to” unification across all five conformance positions.

Implementation

  • Implement: Parser change — impl Type: Trait replaces impl Trait for Type

    • Update ori_parse/src/grammar/item/impl_def/mod.rs — parse type first, then : + trait
    • Update parser tests in impl_def/tests.rs
    • Rust Tests: Parser unit tests for new syntax
    • Ori Tests: Migrate all .ori test files from impl Trait for Type to impl Type: Trait (~34 files, ~111 occurrences — deferred until parser supports new syntax)
  • Implement: Error recovery — detect old impl Trait for Type syntax and suggest fix

    • Rust Tests: Recovery test for old syntax
  • Migrate: Update all .ori test/spec files to new syntax

    • tests/spec/traits/ — 30 files
    • tests/compile-fail/ — 3 files
    • tests/fmt/declarations/impls/ — 1 file
  • Verify: All spec tests pass with new parser

    • cargo st — full spec test suite
    • cargo t — full Rust test suite
  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

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

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

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

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


3.24 Value Trait (ARC-Free Value Types)

STATUS: NOT STARTED (verified 2026-03-29 — all items unchecked across 5 phases)

Proposal: proposals/approved/value-trait-proposal.md

Marker trait guaranteeing inline storage, bitwise copy, no ARC, and no Drop. Supersedes the Copy trait slot and inline type keyword reservation.

Phase 1: Type Checker Validation

  • Implement: Register Value in prelude as marker trait (no methods) — ori_types/check/registration/

    • Supertrait: Clone + Eq
    • Cannot be manually implemented (like Sendable)
    • Rust Tests: Registration tests in ori_types/check/registration/tests.rs
  • Implement: Value validation pass — ori_types/check/

    • All fields recursively satisfy Value
    • No Drop impl registered for the type
    • No recursive type structure
    • Size within threshold (warning >256 bytes, error >512 bytes)
    • Value types automatically satisfy Sendable and Clone
    • Rust Tests: Validation tests in ori_types/check/
  • Implement: Error codes E2040-E2043, warning W2040

    • E2040: Field does not satisfy Value
    • E2041: Value type cannot implement Drop
    • E2042: Value type exceeds maximum size (512 bytes)
    • E2043: Type does not satisfy Value bound
    • W2040: Value type is large (>256 bytes)
    • Ori Tests: tests/compile-fail/traits/value/ — field violations, Drop conflict, size error
    • Ori Tests: tests/spec/traits/value/ — valid value types, generics, patterns
  • Implement: Primitive types implicitly satisfy Value

    • int, float, bool, char, byte, void, Duration, Size, Ordering, Never
    • str does NOT satisfy Value
    • Rust Tests: Primitive Value satisfaction tests

Phase 2: ARC Pipeline Fast Path

  • Implement: Fast path in ori_arc/src/classify/mod.rs — types with Value trait -> ArcClass::Scalar

    • Skip field traversal for Value types
    • Rust Tests: ori_arc/src/classify/tests.rs
  • Implement: Skip borrow inference for Value parameters — ori_arc/src/borrow/

    • Always cheap to copy, no borrow optimization needed
    • Rust Tests: Borrow inference tests
  • Implement: Skip RC insertion for Value-typed variables — ori_arc/src/rc_insert/

    • Rust Tests: RC insertion skip tests

Phase 3: Evaluator Support

  • Implement: Value trait recognition in evaluator — ori_eval/
    • Auto-satisfy Clone for Value types (bitwise copy)
    • Rust Tests: Evaluator Value type tests
    • Ori Tests: tests/spec/traits/value/ — runtime behavior

Phase 4: LLVM Codegen Optimization

  • Implement: memcpy for Value types — ori_llvm/
    • Value types passed by value (no indirection through pointers) when <=2 registers
    • No RC inc/dec emitted for Value types
    • LLVM SROA and constant folding work on Value types
    • LLVM Rust Tests: ori_llvm/tests/aot/value_types.rs
    • Ori Tests: AOT tests for Value type operations

Phase 5: Const Generic Integration (Future)

  • Implement: Value + Hashable types eligible as const generic parameters

    • Ori Tests: Const generic with Value types
  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

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

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

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

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


3.25 Structural Trait Defaults

Status: Not Started Goal: Formalize and complete structural trait defaults — Eq/Clone/Debug/Printable work without declaration on all types; eqequals method rename; LLVM codegen parity with evaluator for enum structural equality and structural Clone/Debug/Printable fallbacks.

Context: Ori is a pure value-type language. The evaluator has always performed structural equality for all types without requiring #derive(Eq). The type checker does not gate ==/!= on the Eq trait. The LLVM codegen has structural eq fallback for structs but not enums. This subsection formalizes this behavior per the approved structural-trait-defaults-proposal (2026-04-02) and closes the LLVM codegen gaps.

Proposal: docs/ori_lang/proposals/approved/structural-trait-defaults-proposal.md

Reference implementations:

  • Gleam compiler-core/src/type_/expression.rs: all types structurally comparable — no Eq trait requirement
  • Elm compiler/src/Type/Error.hs: structural equality built-in for all values
  • Roc crates/compiler/mono/src/ir.rs: structural equality as default for all types

Depends on: None (evaluator and type checker already implement this behavior).

Key design decisions:

  1. Two-tier model: Structural ==/!= works on all types without declaration. Declaring type T: Eq = {...} generates a named equals method for trait dispatch in generic T: Eq contexts.
  2. Comparable/Hashable/Default require explicit declaration — no structural default (field ordering is semantic, not structural).
  3. eqequals method rename — unifies a partial rename already in progress (evaluator and mangling use "equals", IR and codegen use "eq").
  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)
  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.
  • Subsection close-out (3.25) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-3.25 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 3.25: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.
  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.
  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.

3.25.1 eqequals Method Rename

File(s): ori_ir/src/derives/mod.rs, library/std/prelude.ori, ori_llvm/src/codegen/arc_emitter/builtins/compound_traits.rs, ori_llvm/src/codegen/arc_emitter/operators/mod.rs, ori_llvm/src/codegen/derive_codegen/field_ops/thunks.rs, ori_eval/src/derives/tests.rs, ori_ir/src/derives/tests.rs

The codebase has a partial inconsistency: the evaluator runtime (MethodNames.equals), mangling ($equals), type checker registration, and some test files already use "equals". The IR source of truth (DerivedTrait::Eq.method_name()) and LLVM codegen hardcode "eq". This subsection unifies to "equals" everywhere.

Rename targets (must change):

FileCurrentChange To
compiler/ori_ir/src/derives/mod.rs line 145"eq" in define_derived_traits! macro"equals"
library/std/prelude.ori line 20@eq (self, other: Self) -> bool@equals (self, other: Self) -> bool
compiler/ori_ir/src/derives/tests.rs line 29assert_eq!(DerivedTrait::Eq.method_name(), "eq")"equals"
compiler/ori_llvm/src/codegen/arc_emitter/operators/mod.rs lines 203-204"eq" in operator dispatch"equals"
compiler/ori_llvm/src/codegen/arc_emitter/builtins/compound_traits.rs line 216self.interner.intern("eq")self.interner.intern("equals")
compiler/ori_llvm/src/codegen/derive_codegen/field_ops/thunks.rsfc.intern("eq")fc.intern("equals")
compiler/ori_eval/src/derives/tests.rs (3 occurrences)interner.intern("eq")interner.intern("equals")

Already correct (no change needed):

  • Evaluator runtime MethodNames.equals — already uses "equals"

  • Mangling (_ori_int$$Eq$equals) — already uses "equals"

  • Type checker registration — already uses "equals"

  • BinaryOp::Eq enum variant — this is the operator, not the method name

  • LLVM IR builder labels (e.g., icmp_eq(a, b, "eq")) — these are IR instruction names, not method names

  • Write failing tests first: Add test in ori_ir/src/derives/tests.rs asserting DerivedTrait::Eq.method_name() == "equals"; verify it fails

  • Rename source of truth: Change "eq" to "equals" in ori_ir/src/derives/mod.rs line 145 (define_derived_traits! macro entry for Eq)

  • Update prelude: Change @eq to @equals in library/std/prelude.ori

  • Update LLVM codegen: Change all intern("eq") to intern("equals") in:

    • compound_traits.rsemit_derived_eq_call
    • operators/mod.rs — operator dispatch tuple
    • derive_codegen/field_ops/thunks.rs — derive thunk emit
  • Update evaluator tests: Change interner.intern("eq")interner.intern("equals") in ori_eval/src/derives/tests.rs (3 occurrences)

  • Update pattern tests: Change method_name() == "eq""equals" in ori_patterns/src/user_methods/tests.rs

  • Verify existing tests pass: timeout 150 cargo t — all existing tests must pass after rename (evaluator/mangling already use “equals”)

  • Semantic pin: Add Ori spec test tests/spec/traits/derive/eq_method_name.ori that calls .equals() directly on a derived Eq type — proves the method is accessible by the new name

Test matrix:

  • Types: struct (single-field, multi-field), newtype, enum (unit variants, payload variants)
  • Patterns: direct ==, direct !=, method call .equals(other:), use in generic T: Eq context
  • Backends: eval + LLVM (debug + release)

3.25.2 LLVM Enum Structural Equality

File(s): compiler/ori_llvm/src/codegen/arc_emitter/builtins/compound_traits.rs

Currently, when emit_element_equals encounters an enum type at line 205, it only tries emit_derived_eq_call — there is no structural fallback. Structs have this fallback (line 200-203: try derived, .or_else(|| self.emit_structural_eq(...))). This means enums without #derive(Eq) cannot be compared in LLVM codegen, even though the evaluator compares them structurally.

Pattern to follow: compiler/ori_llvm/src/codegen/derive_codegen/enum_bodies/enum_comparable.rs (lines 21-73) — emit_enum_lexicographic() shows the exact tag-extraction + payload-switch pattern for enum comparison in LLVM IR.

Algorithm for emit_structural_enum_eq:

  1. Extract discriminant (tag) from both lhs and rhs via extract_value(val, 0, ...)
  2. Compare tags with icmp_eq
  3. If tags differ → return false
  4. If tags match → switch on tag value, for each variant:
    • If unit variant (no payload) → contribute true
    • If payload variant → extract payload fields, recursively call emit_element_equals on each, accumulate with AND
  5. Return accumulated result via phi node
  • Write failing test first: Add AOT test compiler/ori_llvm/tests/aot/structural_eq.rs with enum type having no #derive(Eq), assert ==/!= work correctly
    • Unit-variant enum: type Color = Red | Green | Blue
    • Payload enum: type Shape = Circle(r: float) | Rect(w: float, h: float)
    • Verify test fails (LLVM can’t emit structural enum eq)
  • Implement emit_structural_enum_eq in compound_traits.rs:
    • Add function signature: fn emit_structural_enum_eq(&mut self, lhs: ValueId, rhs: ValueId, variants: &[...], ty: Idx) -> Option<ValueId>
    • Implement tag extraction and comparison
    • Implement variant-switch payload comparison (reuse emit_element_equals for recursion)
    • Handle edge cases: all-unit enum (no payload switch needed), single-variant enum
  • Wire into dispatch: Change line 205 from:
    TypeInfo::Enum { .. } => self.emit_derived_eq_call(lhs, rhs, elem_ty),
    to:
    TypeInfo::Enum { variants, .. } => {
        let variants = variants.clone();
        self.emit_derived_eq_call(lhs, rhs, elem_ty)
            .or_else(|| self.emit_structural_enum_eq(lhs, rhs, &variants, elem_ty))
    }
  • Verify tests pass: All new AOT tests pass in debug and release
  • Dual-execution parity: Run diagnostics/dual-exec-verify.sh on test programs — evaluator and LLVM must produce identical results
  • Semantic pin: Test that verifies enum structural eq works WITHOUT #derive(Eq) — would fail if fallback is removed
  • Negative pin: Test that verifies a type with custom impl T: Eq uses the custom method, not structural default

Test matrix:

  • Types: unit enum, payload enum (single field, multi-field), nested enum (enum containing enum), enum with struct payload, Option-like enum, Result-like enum
  • Patterns: == same variant, == different variant, !=, nested comparison
  • Backends: LLVM debug + release (FastISel divergence check)

3.25.3 LLVM Structural Clone/Debug/Printable Fallbacks

File(s): compiler/ori_llvm/src/codegen/arc_emitter/builtins/compound_traits.rs, compiler/ori_llvm/src/codegen/arc_emitter/builtins/debug_helpers.rs

Currently:

  • Clone: No structural fallback. Types without #derive(Clone) cannot be cloned in LLVM codegen (evaluator clones all types structurally).
  • Debug: Falls back to "<?>" literal when no derived debug method exists (line 189-190 of debug_helpers.rs). Should produce TypeName { field: value, ... } structurally.
  • Printable: Same as Debug — falls back to "<?>". Should produce the same structural format as Debug default.

Implementation order: Clone first (simplest — no string building), then Debug (requires string concatenation), then Printable (identical to Debug structural default).

Phase A: Structural Clone

  • Write failing test: AOT test with struct/enum without #derive(Clone), call .clone() structurally
  • Implement emit_structural_clone in compound_traits.rs:
    • For structs: extract each field, recursively clone, rebuild struct via insert_value
    • For enums: extract tag + payload, switch on tag, clone payload fields per variant, rebuild
    • Wire into clone dispatch with .or_else(|| self.emit_structural_clone(...))
  • Verify: Tests pass, dual-exec parity

Phase B: Structural Debug

  • Write failing test: AOT test with struct/enum without #derive(Debug), call .debug(), verify output format
  • Implement emit_structural_debug in debug_helpers.rs:
    • Build string: TypeName { field1: <debug(f1)>, field2: <debug(f2)>, ... }
    • Use emit_literal_ori_str for type/field names, emit_element_debug for field values
    • Concatenate via emit_str_concat (runtime call ori_str_concat)
    • Handle enums: VariantName (unit) or VariantName(field1: <debug>, ...)
    • Handle Sret return convention (debug returns str = 24 bytes)
  • Wire into dispatch: Replace "<?>" fallback at line 189-190 with structural debug
  • Verify: Tests pass, dual-exec parity, output matches evaluator format

Phase C: Structural Printable (to_str)

  • Write failing test: AOT test with struct/enum without #derive(Printable), call .to_str() or use in string interpolation
  • Implement emit_structural_to_str: Identical to structural debug (same format per proposal)
  • Wire into dispatch in the to_str emission path
  • Verify: Tests pass, dual-exec parity

Test matrix (all three phases):

  • Types: empty struct, single-field struct, multi-field struct, newtype, unit enum, payload enum, nested types (struct containing enum), generic types
  • Patterns: direct method call (.clone(), .debug(), .to_str()), use in string interpolation (Printable), use in dbg() (Debug)
  • Backends: eval + LLVM (debug + release)
  • Format verification: structural output matches TypeName { field: value } format exactly

3.25.4 Spec and Documentation Updates

File(s): docs/ori_lang/v2026/spec/operator-rules.md, docs/ori_lang/v2026/spec/09-properties-of-types.md, .claude/rules/ori-syntax.md

  • Update operator-rules.md: Remove T : Eq precondition from EQ type rule (Annex B, Comparison section)
    • Change from: e1 : T e2 : T T : Eq → e1 ==|!= e2 : bool
    • Change to: e1 : T e2 : T → e1 ==|!= e2 : bool
    • Add NOTE: structural equality is the default; declaring Eq enables trait dispatch
    • ORD rule (Comparable) remains unchanged
  • Update 09-properties-of-types.md: Redefine Eq as “custom equality override” rather than “enables equality”
    • Document structural defaults for Eq, Clone, Debug, Printable
    • Document that Comparable/Hashable/Default require explicit declaration
    • Document the two-tier model
    • Rename @eq to @equals in trait definition
  • Update 08-types.md Newtype section: Document that newtypes inherit structural comparison from inner type
  • Update .claude/rules/ori-syntax.md:
    • Update Eq trait description to reflect structural defaults
    • Update method name from eq to equals
    • Add note about two-tier model (structural vs declared)
  • Update design doc: Remove Eq requirement from binary operations diagram in docs/compiler/design/05-type-system/index.md (line ~250: T == T → bool (where T: Eq))
  • Update LLVM codegen comment: Remove stale comment in ori_llvm/src/codegen/arc_emitter/operators/mod.rs line 201 referencing old “eq” method name
  • Verify spec consistency: No contradictions between operator-rules.md, 09-properties-of-types.md, and ori-syntax.md

3.25.R Third Party Review Findings

  • None.

3.25.N Completion Checklist

  • eqequals rename complete across all crates (ori_ir, ori_llvm, prelude.ori, all tests)
  • Enum structural equality works in LLVM codegen without #derive(Eq)
  • Structural Clone fallback works in LLVM codegen without #derive(Clone)
  • Structural Debug fallback works in LLVM codegen without #derive(Debug) (produces TypeName { field: value } format)
  • Structural Printable fallback works in LLVM codegen without #derive(Printable)
  • Spec updated: EQ rule no longer requires T : Eq
  • 09-properties-of-types.md documents structural defaults and two-tier model
  • .claude/rules/ori-syntax.md updated with equals method name
  • All AOT tests pass in both debug and release: timeout 150 cargo b && timeout 150 cargo b --release && timeout 150 ./test-all.sh
  • Dual-execution parity verified for all new test programs
  • ORI_CHECK_LEAKS=1 reports zero leaks on all new test programs
  • Plan annotation cleanup: no stale plan annotations in .rs files
  • /tpr-review passed
  • /impl-hygiene-review passed
  • /improve-tooling retrospective completed — MANDATORY at section close, after both reviews are clean. Reflect on the section’s debugging journey (which diagnostics/ scripts you ran, which command sequences you repeated, where you added ad-hoc dbg!/tracing calls, where output was hard to interpret) and identify any tool/log/diagnostic improvement that would have made this section materially easier OR that would help the next section touching this area. Implement every accepted improvement NOW (zero deferral) and commit each via SEPARATE /commit-push. The retrospective is mandatory even when nothing felt painful — that is exactly when blind spots accumulate. See .claude/skills/improve-tooling/SKILL.md “Retrospective Mode” for the full protocol.

Exit Criteria: All types (structs, enums, newtypes) support ==/!=, .clone(), .debug(), and .to_str() structurally in both evaluator and LLVM codegen without requiring #derive(...). The equals method name is consistent across all compiler crates. Spec reflects structural defaults. Zero regressions in ./test-all.sh (debug and release). Dual-execution parity confirmed for all new test programs.