caefcf996a
Three sibling sites previously fell back to shallow `ailang_rc_dec` when a binder had non-empty `moved_slots` and a dynamic runtime ctor tag: Iter B Own-param dec at fn-return (lib.rs), Iter A arm-close pattern-binder dec (match_lower.rs), and emit_inlined_partial_drop's non-Ctor branch (drop.rs). Shallow freed the outer cell but did not walk the unmoved ptr fields — silent leak. Adds `emit_partial_drop_fn_for_type`: a per-ADT helper structurally parallel to `emit_drop_fn_for_type` but taking an i64 moved-slots bitmask. Each ptr-field's dec is gated on the corresponding mask bit; the outer box is dec'd at join. Emitted alongside the per-type drop fn for every ADT under --alloc=rc. Three call sites rewritten to resolve the partial_drop symbol from the binder's static type and build the mask from `moved_slots`. Three RED-then-GREEN fixtures (rc_own_param_/rc_match_arm_/ rc_app_let_partial_drop_leak) pin the carve-outs in regression coverage; live cell counts go from 3/1/3 (pre-fix) to 0/0/0. e2e count: 66 → 69. The pre-existing `alloc_rc_own_param_dec_at_fn_return` IR-shape assertion is widened to accept `partial_drop_<m>_<T>(%arg_xs, i64 mask)` as a third valid drop shape (the canonical fu2 case). Closes the JOURNAL queue's only remaining iter; the "wait for organic fixture" stance from the 18g tidy is retracted — known leaks are bugs, CLAUDE.md's TDD rule covers them autonomously.
70 lines
2.0 KiB
Plaintext
70 lines
2.0 KiB
Plaintext
; Iter 18g.tidy.fu2 RED-test fixture 3/3: dynamic-tag partial-drop
|
|
; carve-out at let-close for an App-bound binder
|
|
; (drop.rs:580 fallback in `emit_inlined_partial_drop`).
|
|
;
|
|
; Shape:
|
|
; - Same `Pair`/`Cell`/`Wrap` types as fixtures 1 and 2.
|
|
; - `main` let-binds `p = (app build_pair)` — value is
|
|
; `Term::App` (Own-returning), `is_rc_heap_allocated` returns
|
|
; true → trackable.
|
|
; - Body matches `p` as `MkPair a _` — slot 0 bound, slot 1 wild.
|
|
; `moved_slots[p] = {0}`.
|
|
; - `a` is consumed by `use_cell` (Own param) → `consume_count[a]
|
|
; == 1`, arm-close drop skipped. `use_cell`'s body fully
|
|
; destructures `a` and returns Int.
|
|
; - At p's let-close: `consume_count[p] == 0`, `moves[p] = {0}`
|
|
; non-empty, `value` is `Term::App` (not `Term::Ctor`) →
|
|
; `emit_inlined_partial_drop` falls into the non-Ctor branch
|
|
; (drop.rs:580) → shallow `ailang_rc_dec(p)`. p's outer cell
|
|
; is freed; slot 1 (the second MkCell + its two MkWraps =
|
|
; 3 cells) leaks.
|
|
;
|
|
; Pre-fix: live = 3 (one MkCell + two MkWrap children in slot 1).
|
|
; Post-fix: live = 0.
|
|
|
|
(module rc_app_let_partial_drop_leak
|
|
|
|
(data Wrap
|
|
(ctor MkWrap (con Int)))
|
|
|
|
(data Cell
|
|
(ctor MkCell (con Wrap) (con Wrap)))
|
|
|
|
(data Pair
|
|
(ctor MkPair (con Cell) (con Cell)))
|
|
|
|
(fn build_pair
|
|
(type
|
|
(fn-type
|
|
(params (con Int))
|
|
(ret (own (con Pair)))))
|
|
(params n)
|
|
(body
|
|
(term-ctor Pair MkPair
|
|
(term-ctor Cell MkCell
|
|
(term-ctor Wrap MkWrap n)
|
|
(term-ctor Wrap MkWrap 2))
|
|
(term-ctor Cell MkCell
|
|
(term-ctor Wrap MkWrap 3)
|
|
(term-ctor Wrap MkWrap 4)))))
|
|
|
|
(fn use_cell
|
|
(type
|
|
(fn-type
|
|
(params (own (con Cell)))
|
|
(ret (con Int))))
|
|
(params c)
|
|
(body
|
|
(match c
|
|
(case (pat-ctor MkCell w1 w2) 1))))
|
|
|
|
(fn main
|
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
|
(params)
|
|
(body
|
|
(let p (app build_pair 1)
|
|
(do io/print_int
|
|
(match p
|
|
(case (pat-ctor MkPair a _)
|
|
(app use_cell a))))))))
|