Section 01: IndexSet Trait + updated Method + ARC COW
Goal
- See frontmatter. Proposal Phase 1.
- The
updatedmethod is the desugar target for index assignment (list[i] = x → list = list.updated(key: i, value: x)); it ships before the section-03 desugar consumes it.
Implementation Sketch
IndexSet<Key, Value>is a prelude trait (companion to read-onlyIndex).- The
updatedmethod is publicly callable (functional style:list.updated(key: 0, value: x)) independent of the assignment sugar. - The contract is value-semantic:
updatedreturns a NEW collection, observably distinct from the receiver. - Built-in impls are compiler-provided intrinsics; for all three types (
[T]/[T, max N]/{K:V}) the existing ARC copy-on-write mutates the backing buffer in place at refcount==1 (provable uniqueness) and allocates-then-rebinds otherwise — observably identical to the always-copy path (Swift Array/Dictionary COW under ARC). - Map in-place COW is live in the runtime:
ori_rt/src/map/cow.rscow_insert_existing/cow_insert_newcarry a unique-fast-path (ori_rc_is_unique) that overwrites in place at refcount==1 — maps are NOT always-allocate. strdeliberately omitsIndexSet(codepoint replacement may change byte length).
01.1 IndexSet Trait + updated Method + ARC COW Implementation
- TDD-first: failing test matrix BEFORE implementation —
updatedon[int]/[str]/{str:int}/[int, max N]× {in-bounds, out-of-bounds, refcount==1 in-place, refcount>1 copy} × {interpreter, LLVM}. OOB semantics per type:[T].updatedpanics,[T, max N].updatedpanics (key>= length),{K:V}.updatedinserts. Negative pin:str.updateddirect-resolution failure (str implementsIndex, notIndexSet).[T, max N].updatedOOB cell (parallels[T]): positive pin —[1, 2, 3].to_fixed<3>().updated(key: 1, value: 9)yields[1, 9, 3]in both backends; negative pin —assert_panics(() -> fixed.updated(key: 5, value: 0))forkey >= length(in-bounds-of-capacity but out-of-bounds-of-length still panics, matching[T]index semantics, NOT the fixed-listtry_pushoverflow path).- Ori Tests:
tests/spec/traits/index_set/fixed_oob.ori
- Ori Tests:
- Define
IndexSet<Key, Value>trait incompiler_repo/library/std/prelude.oriwith@updated (self, key: Key, value: Value) -> Self.- Ori Tests:
tests/spec/traits/index_set/basic.ori
- Ori Tests:
- Register
IndexSettrait definition + built-in derived/impl signatures inori_types/src/check/registration/(mirror howIndexis registered).- Rust Tests:
ori_types/src/check/registration/tests.rs
- Rust Tests:
- Register
updatedas a built-in method on[T]+{K: V}inori_evalmethod dispatch +ori_registry(per.claude/rules/registry.md— methods on builtin types live in the registry). Map registration carries theK: Eq + Hashablebound (mirrorsIndex/ map-key constraints).[T, max N]is NOT a separate registration surface: it erases toTypeTag::Listat registration/resolution, so the[T](List-tag) registration inori_registry/src/defs/list/mod.rs(registered undertag: TypeTag::List) covers fixed-lists — registeringupdatedon[T, max N]separately would be redundant.- Rust Tests:
ori_types/src/infer/expr/methods/tests.rs(companion toresolve_builtin_methodatori_types/src/infer/expr/methods/mod.rs; the resolver lives inori_types, NOTori_eval/src/method_dispatch/) — registry resolution ofupdatedsucceeds for each type:[int].updated→IndexSet<int, int>,{str: int}.updated→IndexSet<str, int>,[int, max 4].updated→IndexSet<int, int>resolves via the List tag (assertresolve_builtin_methodreturns the registered impl + correct key/value types per type). - Rust Tests:
ori_types/src/check/registration/tests.rs— non-hashable map-key negative pin: a{K: V}whereKdoes not satisfyEq + Hashablerejectsupdatedresolution (paralleling E2031 non-hashable map-key handling); positive pin: hashableKresolves. - Ori Tests:
tests/spec/traits/index_set/updated_method.ori
- Rust Tests:
- Implement
updatedARC copy-on-write inori_patterns/ori_evalvalue model: for[T]/[T, max N]AND{K:V}refcount==1 → mutate backing buffer in place (list:ori_rt/src/list/cow.rs; map:ori_rt/src/map/cow.rsunique-fast-path), refcount>1 → clone-then-mutate + rebind. List/fixed-list out-of-bounds panics; map inserts-or-replaces.- Rust Tests:
ori_patterns/src/value/tests.rs— COW behavior matrix (positive: in-place fires at rc==1 for list/fixed-list AND map; negative: aliased list/map forces copy, alias unchanged) - Ori Tests:
tests/spec/traits/index_set/cow_behavior.ori
- Rust Tests:
- Register
updatedAIMS builtin ownership contract inori_arcso AIMS can prove the value-flow rather than emit RC ops on the inserted value. Addupdated’s param/return ownership + borrow contract toBuiltinOwnershipSets/seed_builtin_contracts(ori_arc/src/aims/builtins/mod.rs) and the borrow-builtin surface:selfis consumed-and-returned (the return aliases or replaces the receiver’s storage),valueis moved into the collection (ownership transferred — its RC must NOT be dropped after insert). Without the interprocedural contract AIMS may emit an erroneous RC dec on the inserted value (leak at rc==1 in-place; double-free at rc>1 copy).- 3-param contract constructor required:
updatedis 3-param (self, key, value); the existingcow_receiver_only_contract(ori_arc/src/aims/builtins/mod.rs) marks ONLY the receiver and cannot express thevalue-param ownership-transfer —seed_builtin_contractsMUST NOT defaultupdatedinto it (param-length mismatch). Add a new 3-param parameterized contract constructor (or specialized memory contract) that modelsselfconsumed-returned +valuemoved-in +keyborrowed. - Uniform COW contract across all three types:
[T]/[T, max N]AND{K:V}share one value-flow shape — in-place-at-rc==1 / clone-at-rc>1, the return aliases-or-replaces receiver storage (no list-vs-map asymmetry; the runtime map unique-fast-path atori_rt/src/map/cow.rs:106is the in-place path). The seeded contract models the single COW value-flow (selfconsumed-returned,valuemoved-in) so AIMS proves all three without parallel emission paths. - Rust Tests:
ori_arc/src/aims/builtins/tests.rs— contract seeded forupdatedon[T]/[T, max N]/{K:V}; value-param ownership-transfer asserted (no RC dec on the movedvalue). - Ori Tests:
tests/spec/traits/index_set/arc_insert.ori— insert an ARC-managed element ([str]/{str: [int]}) underupdated;ORI_CHECK_LEAKS=1reports zero leaks debug + release, interpreter == AOT.
- 3-param contract constructor required:
- LLVM
updatedcodegen for the three built-in types; verify interpreter == AOT (dual-execution parity);ORI_CHECK_LEAKS=1zero leaks debug + release. - Verify: matrix green debug + release, both backends;
cargo st tests/spec/traits/index_set/.
Intelligence Reconnaissance
2026-06-01 — feature-mode scaffold; approved proposal index-assignment-proposal.md is the research artifact.
scripts/intel-query.sh symbols "Index" --repo ori --kind trait— mirror the read-side trait registration[ori:ori_types/src/check/registration/]forIndexSet.scripts/intel-query.sh file-symbols "ori_eval/src/method_dispatch" --repo ori— built-in method routing surface[ori:ori_eval/src/method_dispatch/].scripts/intel-query.sh similar "updated" --repo swift,rust --limit 5— Array/Dictionary copy-on-write prior art.
Spec References
compiler_repo/docs/ori_lang/v2026/spec/13-variables.md§13.6.2 (index assignment) — the AUTHORITATIVE SSOT definingx = x.updated(key: i, value: v)as the index-assignment desugar contract; spec is SSOT over the proposal. The §13.6 NOTE establishes that in-place mutation under refcount==1 is an optimization observably identical to the always-copy value-semantic path.- Proposal
index-assignment-proposal.md§The IndexSet Trait, §Standard Implementations (research artifact; subordinate to the spec). index-trait-proposal.md(the read-sideIndexpair).- Semantic contract:
t.updated(key:k, value:v).index(key:k) == v(not compiler-enforced).
Tests
tests/spec/traits/index_set/{basic,updated_method,cow_behavior}.ori + Rust unit tests in ori_types / ori_eval / ori_patterns / ori_llvm per items above.