Section 03: Remove Workarounds & Simplify
Status: Complete Goal: With elem_dec_fn stored in the RC header, the ordering workarounds in the ARC lowering are no longer needed. Remove them to simplify the code.
Depends on: Section 02 (codegen must use header-based cleanup first).
Ordering within this section: Steps 03.1, 03.1.5, and 03.2 remove the for-loop workarounds and MUST be done together (they share state: for_coll_counter, ForYieldContext::coll_param, and __for_coll_N bindings). Step 03.2.5 (removing elem_dec_fn from the iterator API) is an independent change that can be done before or after the workaround removal, but doing it last is recommended to keep the removal steps focused and testable as a single unit.
03.1 Remove Phantom Binding from lower_for
File: compiler/ori_arc/src/lower/control_flow/loops.rs
The phantom __for_coll_N mutable binding was added to thread the collection through the loop header, forcing AIMS to add RcInc. With the header storing elem_dec_fn, the ordering no longer matters — whoever reaches zero reads the function from the header.
Note: The source code comment at loops.rs:169-176 says the phantom is needed for “List, Set, Map”, but the actual match expression at line 177 only handles List | Set — Map is excluded. This is a pre-existing documentation bug in the source code.
- Remove the
needs_phantomcheck andscope.bind_mutable(coll_name, iter_val)block (lines 177-184 inloops.rs) (2026-03-21) - Remove the comments explaining the workaround (lines 169-176) (2026-03-21)
- Verify: the
__for_collname is not referenced anywhere else in the compiler (grep -r "__for_coll" compiler/→ 0 results) (2026-03-21) - [BUG FIX] Set.iter() was using
emit_list_iterdirectly, treating the hash table as a contiguous array — exposed by phantom removal. Fixed:emit_set_iternow converts viaori_set_to_list+ explicit set bufferori_set_buffer_rc_dec(2026-03-21)
Cleanup (03.1)
- [WASTE]
compiler/ori_arc/src/lower/control_flow/loops.rs:169-184— Removed phantom binding code and stale comment. ALL__for_collreferences updated:-
loops.rs:177-184— phantom binding creation code removed (2026-03-21) -
for_iterator.rs:192-207— dummy reference afterori_iter_dropremoved (Section 03.2) (2026-03-21) -
for_yield.rs:60-62—prepare_iterator()doc comment updated (2026-03-21) -
for_yield.rs:86-96—prepare_iterator()colllogic removed (Section 03.1.5) (2026-03-21) -
expr/mod.rs:108-112—for_coll_counterfield removed. Initialization sites atlower/mod.rs:168andlower/calls/lambda.rs:126also removed (2026-03-21) -
borrowed_defs.rs:208-209— doc comment updated to describe generic mechanism without referencing removed phantom (2026-03-21) -
walk_dec.rs:79— comment updated (2026-03-21) -
list_builtins.rs:143-147— comment updated to reference header-based approach (2026-03-21)
-
03.1.5 Remove For-Yield Collection Threading
Files: compiler/ori_arc/src/lower/control_flow/for_yield.rs, compiler/ori_arc/src/lower/expr/mod.rs, compiler/ori_arc/src/lower/control_flow/mod.rs
The for-yield path has its own independent collection-phantom mechanism parallel to the for-do __for_coll_N binding. prepare_iterator() returns coll_var = Some(iter_val) for List/Set, which lower_for_yield_iterator() threads through header/exit blocks as coll_param/exit_coll_param block parameters, and emits a dummy let after ori_iter_drop. ForYieldContext::coll_param is used by lower_break/lower_continue to prepend the phantom to jump args. With the header storing elem_dec_fn, all of this is unnecessary.
- In
for_yield.rsprepare_iterator(): simplified return type to(ArcVarId, Idx), removedcollvariable logic (2026-03-21) - In
for_yield.rslower_for_yield_iterator(): removedcoll_varparameter and allcoll_param/exit_coll_paramblock parameter threading (2026-03-21) - In
for_yield.rsexit block: removed dummy reference toexit_coll_paramafterori_iter_drop(2026-03-21) - In
for_yield.rslower_for_yield_iterator()doc comment: updated block diagram — removedcoll_paramfrom header and exit_prep jump args (2026-03-21) - In
for_yield.rslower_for_yield_iterator(): removed#[expect(clippy::too_many_arguments)](2026-03-21) - In
for_yield.rsForYieldContextconstruction: removedcoll_paramfield initialization (2026-03-21) - In
expr/mod.rsForYieldContext: removedcoll_paramfield (2026-03-21) - In
for_yield_option.rs:158: removedcoll_param: Noneand updated comment at line 88 (2026-03-21) - In
control_flow/mod.rslower_break(): removedcoll_paramfrom for-yield break path (2026-03-21) - In
control_flow/mod.rslower_continue(): removedcoll_paramfrom for-yield continue path (2026-03-21) - [NOTE]
control_flow/mod.rsshrunk from 494 to ~475 lines aftercoll_paramremoval. Safe margin restored. (2026-03-21) - In
for_yield.rslower_for_yield()call site: updated destructuring from 3-tuple to 2-tuple (2026-03-21)
Cleanup (03.1.5)
- [WASTE]
for_yield.rs—lower_for_yield_iteratorshrunk ~40 lines.#[expect(clippy::too_many_arguments)]removed.#[expect(clippy::too_many_lines)]retained (function still > 50 lines but well under 100). (2026-03-21) - [NOTE]
for_yield.rsshrunk from 390 to ~345 lines. No split needed. (2026-03-21)
03.2 Remove Dummy Reference from lower_for_iterator
File: compiler/ori_arc/src/lower/control_flow/for_loops/for_iterator.rs
The dummy Let after ori_iter_drop was added to keep the collection alive past the iterator drop. No longer needed.
- Remove the
__for_coll_Nlookup andemit_let(coll_ty, ArcValue::Var(exit_param))block (lines ~192-207 infor_iterator.rs) (2026-03-21) - Remove the comments explaining the ordering guarantee (2026-03-21)
03.2.5 Remove Dead elem_dec_fn Parameter from Iterator API
Files: compiler/ori_rt/src/iterator/sources.rs, compiler/ori_rt/src/iterator/state.rs, compiler/ori_llvm/src/codegen/arc_emitter/builtins/collections/list_builtins.rs, compiler/ori_llvm/src/codegen/runtime_decl/runtime_functions.rs, compiler/ori_llvm/src/evaluator/runtime_mappings.rs
With the header storing elem_dec_fn, the parameter in ori_iter_from_list and the field in IterState::List are redundant (the header provides the function). Section 02.2 chose Option A (keep parameter for defense-in-depth while the header approach was unproven). Now that the header approach is proven stable by Sections 02-04, the redundant parameter is removed.
WARNING — ABI sync point: This step changes the ori_iter_from_list signature from 5 to 4 parameters. All 4 locations MUST be updated in a single commit: (1) ori_rt/src/iterator/sources.rs (runtime impl), (2) runtime_functions.rs (LLVM IR declaration), (3) list_builtins.rs (codegen call site), (4) runtime_mappings.rs (JIT symbol). Partial updates cause linker errors or silent memory corruption.
- Remove
elem_dec_fnparameter fromori_iter_from_listfunction signature insources.rs(currently at line 32). Also: (2026-03-22)- Remove
elem_dec_fn,from theIterState::List { ... }construction at line 41 (field must be removed from both the struct definition AND this construction site). (2026-03-22) - Update the function doc comment (lines 20-25) — remove the reference to
elem_dec_fn = Nonefor test data. The doc should explain that element cleanup is entirely header-based (V5 RC header). (2026-03-22)
- Remove
- Remove
elem_dec_fnfield fromIterState::Listinstate.rs(field at line 62;Listvariant starts at line 56). Also update the variant doc comment at lines 43-55 — remove the paragraph explainingelem_dec_fndefense-in-depth (lines 51-55), since the field will no longer exist. The doc should explain that element cleanup is entirely header-based. (2026-03-22) - Update
IterState::ListDrop (state.rs:162-178): thedrop()match arm currently destructureselem_dec_fn(line 168) and passes*elem_dec_fntoori_buffer_rc_dec(line 176). With the field removed, passNoneinstead —ori_buffer_rc_decreads the function from the V5 RC header viaload_elem_dec_fnat cleanup time. The destructuring pattern at lines 163-169 must also remove theelem_dec_fnfield. Safety: passingNoneis safe because the header was populated at construction time (Section 02.1) andori_buffer_rc_decalways reads from the header in its drop path (drop_elements_and_freecallsload_elem_dec_fn). (2026-03-22) - Update
emit_list_iterinlist_builtins.rs: remove theelem_dec_fnargument from the call toori_iter_from_list(currently passes real function at line 148, call at line 152 — this becomes unnecessary when header provides it). Also: (2026-03-22)- Update the function doc comment (lines 115-129): remove the “real
elem_dec_fn” explanation and the “Defense-in-depth” paragraph. Replace with a note that element cleanup is entirely header-based (V5 RC header). (2026-03-22) - Remove the comment block at lines 143-147 explaining why
elem_dec_fnis passed and referencing__for_coll. (2026-03-22) - Remove
let elem_dec_fn = self.get_or_generate_elem_dec_fn(elem_ty);at line 148. (2026-03-22) - Update the
emit_rt_callargs from&[data_ptr, len, cap, elem_size_val, elem_dec_fn]to&[data_ptr, len, cap, elem_size_val]. (2026-03-22)
- Update the function doc comment (lines 115-129): remove the “real
- Update
ori_iter_from_listdeclaration inruntime_functions.rs(line 1305): remove the 5th parameter (Ty::Ptrforelem_dec_fn) and update the inline comment at line 1307. Note:runtime_functions.rsis 1528 lines — self-documenting exemption from the 500-line limit (pure static data table), but verify no logic has crept in. (2026-03-22) - Update Rust unit tests in
compiler/ori_rt/src/iterator/tests.rsthat callori_iter_from_listwith 5 args — update to 4 args. There are 30+ call sites across all iterator tests (next, map, filter, take, skip, enumerate, zip, chain, flatten, flat_map, cycle, collect, for_each, fold, slice drop). Each passesNoneas the 5th arg — remove that argument from every call. (2026-03-22) - Update
ori_iter_from_listJIT symbol mapping incompiler/ori_llvm/src/evaluator/runtime_mappings.rs(line 204) to match the new 4-parameter signature — no change needed: JIT mapping is a function pointer cast, parameter count derived from runtime_functions.rs declaration (already updated). (2026-03-22) - Run
timeout 150 cargo test -p ori_rtandtimeout 150 cargo test -p ori_llvm --test aotto verify — 350 + 1876 tests pass (2026-03-22)
Cleanup (03.2.5)
- [STYLE]
compiler/ori_rt/src/iterator/mod.rs:43,60— Remove 2 decorative banners (// ── Extern C API — Core ──...,// ── Extern C API — Cleanup ──...). Replace with plain section comments. (2026-03-22) - [STYLE]
compiler/ori_rt/src/iterator/tests.rs— Remove 20 decorative banners across test file (e.g.,// ── List iterator ───,// ── Range iterator ──, etc.). Replace with plain section comments. Since this file has 30+ori_iter_from_listcalls being modified, clean banners in the same commit. (2026-03-22)
03.3 Verify No Regressions
- Run
timeout 150 cargo test -p ori_llvm --test aot— 1876 passed, 0 failed, 17 ignored (2026-03-22) - Run
timeout 150 ./test-all.sh— 13,551 passed, 0 failed (2026-03-22) - Run
./clippy-all.sh— zero warnings (2026-03-22) - Run
./fmt-all.sh— clean (2026-03-22) - Verify ARC IR for
[str]iteration is cleaner (no phantom__for_coll_Nparam in loop header, nocoll_paramin for-yield loop header) — verified withORI_DUMP_AFTER_ARC=1, no matches for__for_collorcoll_param(2026-03-22) - Verify
ori_iter_from_listtakes 4 parameters (not 5) in the LLVM IR output — confirmed:declare ptr @ori_iter_from_list(ptr, i64, i64, i64)(2026-03-22)
03.R Third Party Review Findings
-
[TPR-03-002][low]plans/rc-header-elem-dec/section-03-remove-workarounds.md:4— Section 03 status metadata contradicts the document body and index. Resolved: Aligned frontmatter (status: complete,third_party_review.status: resolved), body status text (**Status:** Complete), and index entry on 2026-03-22. -
[TPR-03-003][low]compiler/ori_llvm/src/codegen/arc_emitter/builtins/collections/list_builtins.rs:118—emit_list_iter’s doc comment still claims the function explicitly emitsori_list_rc_inc, but the implementation no longer does that. Resolved: Updated doc comment on 2026-03-22 to describe the actual ownership path — caller is responsible for RC inc (via ARC arg-ownership oremit_slice_aware_rc_incinemit_auto_iter). -
[TPR-03-001][high]compiler/ori_llvm/src/codegen/arc_emitter/builtins/mod.rs:397— Auto-iterator promotion still routesSetreceivers throughemit_list_iter, so methods likeSet.fold()still iterate the hash-table buffer as if it were a contiguous list. Resolved: Validated and fixed on 2026-03-22. SplitTypeInfo::List | TypeInfo::Setmatch arm inemit_auto_iter()soSetroutes throughemit_set_iter(). Added 5 semantic pin tests:set_auto_fold,set_auto_count,set_auto_any,set_auto_all,set_str_auto_fold.
03.N Completion Checklist
Workaround Removal (03.1, 03.1.5, 03.2)
- No references to
__for_collin compiler code (verified:grep -rn "__for_coll" compiler/→ 0 results) (2026-03-22) - No references to
coll_paramin for-yield collection-threading context (verified:grep -rn "coll_param" compiler/ori_arc/src/lower/→ 0 results) (2026-03-22) - No dummy reference after
ori_iter_dropin exit block (both for-do and for-yield paths) — exit blocks only callori_iter_drop+ scope restore (2026-03-22) -
lower_foris simpler (no phantom binding logic) (2026-03-22) -
lower_for_iteratoris simpler (no exit-block dummy reference) (2026-03-22) -
lower_for_yield_iteratoris simpler (nocoll_var/coll_paramthreading, no exit-block dummy reference) (2026-03-22) -
ForYieldContext::coll_paramfield removed fromexpr/mod.rs— only 3 fields:list_ptr,elem_size,list_push_name(2026-03-22) -
lower_breakandlower_continueincontrol_flow/mod.rsno longer prependcoll_paramto jump args (2026-03-22) -
prepare_iteratorinfor_yield.rsno longer returns collection variable for phantom threading — returns(ArcVarId, Idx)(2026-03-22) -
for_coll_counterfield removed fromArcLowererinexpr/mod.rs(2026-03-22) -
for_coll_counter: 0initialization removed fromlower/mod.rsandlower/calls/lambda.rs(2026-03-22) -
propagate_borrowed_closureinborrowed_defs.rsupdated (no stale__for_collreferences) (2026-03-22) -
for_yield_option.rsupdated (nocoll_param: NoneinForYieldContextconstruction) (2026-03-22) -
for_yield_option.rscomment updated (no reference tocoll_param) (2026-03-22) -
lower_for_yield_iteratordoc comment block diagram updated (nocoll_paramin jump args) (2026-03-22) -
lower_for_yield_iterator#[expect(clippy::too_many_arguments)]removed (onlytoo_many_linesremains with justification) (2026-03-22)
Iterator API Cleanup (03.2.5)
-
ori_iter_from_listtakes 4 parameters (deadelem_dec_fnremoved) (2026-03-22) -
ori_iter_from_listdoc comment updated to reflect header-based cleanup (noelem_dec_fnparameter) (2026-03-22) -
ori_iter_from_listJIT symbol mapping inevaluator/runtime_mappings.rs— no change needed (function pointer cast) (2026-03-22) -
IterState::Listhas noelem_dec_fnfield (2026-03-22) -
IterState::Listdoc comment updated: header-based cleanup, no defense-in-depth reference (2026-03-22) -
IterState::ListDrop match arm destructuring pattern updated (noelem_dec_fnfield) (2026-03-22) - 30+
ori_iter_from_listcalls initerator/tests.rsupdated from 5 args to 4 args (2026-03-22) -
emit_list_iterinlist_builtins.rsdoc comment and code updated — no reference toelem_dec_fnparameter or__for_collphantom (2026-03-22) - Decorative banners in
iterator/mod.rsanditerator/tests.rsreplaced with plain section comments (2026-03-22)
Verification
- All tests pass (
timeout 150 ./test-all.sh) — 13,551 passed, 0 failed (2026-03-22) - All tests pass in release build (
cargo b --release && timeout 150 cargo test -p ori_llvm --test aot --release) — 1876 passed (2026-03-22) -
./clippy-all.sh— zero warnings (2026-03-22) -
lower_for_yield_iteratorfunction length: 211 lines (exceeds 100-line target but justified with#[expect(clippy::too_many_lines)]— inherently sequential SSA merge logic) (2026-03-22) -
control_flow/mod.rsfile length: 494 lines (under 500-line limit) (2026-03-22)