; Iter 18g tidy follow-up RED-test fixture: a let-binder whose ; value is a Term::Var referencing a non-Own fn-param must ; inherit the param's mode for codegen's drop-emission gates. ; ; The carve-out documented in 18d.4's Iter A fix: the gate ; checks `scrutinee_is_owned` against `current_param_modes`, ; but only fn-params are recorded there. A let-binder aliasing ; an Implicit-mode fn-param passes the gate (its lookup ; misses, default = owned), so the arm-close drop fires on ; memory the caller still references. ; ; Pattern: `pin_aliased` takes `t` as Implicit-mode (default, ; no annotation); aliases it via `(let a t ...)`; matches `a`. ; In the TNode arm the pattern-bindings `l` / `r` would be ; dec'd at arm close because `a` looks owned to the gate — ; corrupting the caller's tree. ; ; Pre-fix under --alloc=rc: refcount underflow at the second ; iteration of `loop`, where the recursive call into ; `pin_aliased(t)` re-loads cells the previous iteration ; freed. ; Post-fix: clean exit, output `0`. Stats are not the focus ; here (the caller's tree leaks under the Implicit-mode ; back-compat lane); the test asserts only correctness. (module rc_let_alias_implicit_param (data Tree (ctor TLeaf) (ctor TNode (con Int) (con Tree) (con Tree))) (fn build (type (fn-type (params (con Int)) (ret (own (con Tree))))) (params d) (body (if (app eq d 0) (term-ctor Tree TLeaf) (term-ctor Tree TNode 1 (app build (app - d 1)) (app build (app - d 1)))))) ; Pin via let-alias: the alias `a` is a Var-binding on the ; Implicit-mode (default) param `t`. Codegen's gate must ; recognise that `a` inherits `t`'s mode and skip the arm- ; close drop that would otherwise fragment the caller's ; tree. (fn pin_aliased (type (fn-type (params (con Tree)) (ret (con Int)))) (params t) (body (let a t (match a (case (pat-ctor TLeaf) 0) (case (pat-ctor TNode v l r) 1))))) (fn loop (type (fn-type (params (con Int) (con Tree)) (ret (con Int)))) (params n t) (body (if (app eq n 0) 0 (let _v (app pin_aliased t) (app loop (app - n 1) t))))) (fn main (type (fn-type (params) (ret (con Unit)) (effects IO))) (params) (body (let t (app build 2) (app print (app loop 3 t))))))