check: mode-strict-because suppression (iter 19b)
Closes the 19a/19a.1/19b arc. Corpus signal from 19a.1 (5/65
fixtures fire over-strict-mode, all deliberate RC codegen-test
fixtures) justified shipping the suppress mechanism end-to-end.
Schema: Suppress { code, because } on FnDef. Pre-19b hashes
bit-identical via skip_serializing_if. Typechecker drops matching
diagnostics; empty 'because' is Error severity; wrong codes are
silent no-ops (open-set registry).
Form-A: (suppress (code "...") (because "...")) clause, parser
+ printer round-trip clean. Form-B: '// @suppress <code>: <reason>'
above the doc string, lossless contract metadata.
5 RC fixtures migrated (.ail.json + .ailx + .prose.txt). Corpus
signal: 5/65 -> 0/65. Lint still fires on any future fn that's
accidentally over-strict without an authored reason.
Test counts: ailang-check 55->61, ailang-core 26->28, ailang-surface
21->26, ailang-prose 49->52, e2e 70 unchanged.
Known debt: .ailx comment headers lost on regen (ail render's
contract excludes comments); parse_suppress_attr accepts
duplicate code/because attrs without diagnose (bounded by canonical
print order).
This commit is contained in:
@@ -1 +1 @@
|
||||
{"defs":[{"ctors":[{"fields":[{"k":"con","name":"Int"}],"name":"MkWrap"}],"kind":"type","name":"Wrap"},{"ctors":[{"fields":[{"k":"con","name":"Wrap"},{"k":"con","name":"Wrap"}],"name":"MkCell"}],"kind":"type","name":"Cell"},{"ctors":[{"fields":[{"k":"con","name":"Cell"},{"k":"con","name":"Cell"}],"name":"MkPair"}],"kind":"type","name":"Pair"},{"body":{"args":[{"args":[{"args":[{"name":"n","t":"var"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":2},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"},{"args":[{"args":[{"lit":{"kind":"int","value":3},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":4},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"}],"ctor":"MkPair","t":"ctor","type":"Pair"},"kind":"fn","name":"build_pair","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Pair"},"ret_mode":"own"}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":1},"t":"lit"},"pat":{"ctor":"MkCell","fields":[{"name":"w1","p":"var"},{"name":"w2","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"c","t":"var"},"t":"match"},"kind":"fn","name":"use_cell","params":["c"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"Cell"}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"args":[{"arms":[{"body":{"args":[{"name":"a","t":"var"}],"fn":{"name":"use_cell","t":"var"},"t":"app"},"pat":{"ctor":"MkPair","fields":[{"name":"a","p":"var"},{"p":"wild"}],"p":"ctor"}}],"scrutinee":{"name":"p","t":"var"},"t":"match"}],"op":"io/print_int","t":"do"},"name":"p","t":"let","value":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"build_pair","t":"var"},"t":"app"}},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_app_let_partial_drop_leak","schema":"ailang/v0"}
|
||||
{"defs":[{"ctors":[{"fields":[{"k":"con","name":"Int"}],"name":"MkWrap"}],"kind":"type","name":"Wrap"},{"ctors":[{"fields":[{"k":"con","name":"Wrap"},{"k":"con","name":"Wrap"}],"name":"MkCell"}],"kind":"type","name":"Cell"},{"ctors":[{"fields":[{"k":"con","name":"Cell"},{"k":"con","name":"Cell"}],"name":"MkPair"}],"kind":"type","name":"Pair"},{"body":{"args":[{"args":[{"args":[{"name":"n","t":"var"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":2},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"},{"args":[{"args":[{"lit":{"kind":"int","value":3},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":4},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"}],"ctor":"MkPair","t":"ctor","type":"Pair"},"kind":"fn","name":"build_pair","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Pair"},"ret_mode":"own"}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":1},"t":"lit"},"pat":{"ctor":"MkCell","fields":[{"name":"w1","p":"var"},{"name":"w2","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"c","t":"var"},"t":"match"},"kind":"fn","name":"use_cell","params":["c"],"suppress":[{"because":"RC codegen test: shape used to feed App-bound let-close partial-drop into use_cell","code":"over-strict-mode"}],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"Cell"}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"args":[{"arms":[{"body":{"args":[{"name":"a","t":"var"}],"fn":{"name":"use_cell","t":"var"},"t":"app"},"pat":{"ctor":"MkPair","fields":[{"name":"a","p":"var"},{"p":"wild"}],"p":"ctor"}}],"scrutinee":{"name":"p","t":"var"},"t":"match"}],"op":"io/print_int","t":"do"},"name":"p","t":"let","value":{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"build_pair","t":"var"},"t":"app"}},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_app_let_partial_drop_leak","schema":"ailang/v0"}
|
||||
|
||||
@@ -1,69 +1,22 @@
|
||||
; 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)))))
|
||||
(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)))))
|
||||
|
||||
(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))))
|
||||
(suppress (code "over-strict-mode") (because "RC codegen test: shape used to feed App-bound let-close partial-drop into use_cell"))
|
||||
(type (fn-type (params (own (con Cell))) (ret (con Int))))
|
||||
(params c)
|
||||
(body
|
||||
(match c
|
||||
(case (pat-ctor MkCell w1 w2) 1))))
|
||||
|
||||
(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))))))))
|
||||
(body (let p (app build_pair 1) (do io/print_int (match p
|
||||
(case (pat-ctor MkPair a _) (app use_cell a))))))))
|
||||
|
||||
@@ -10,6 +10,7 @@ fn build_pair(n: Int) -> own Pair {
|
||||
MkPair(MkCell(MkWrap(n), MkWrap(2)), MkCell(MkWrap(3), MkWrap(4)))
|
||||
}
|
||||
|
||||
// @suppress over-strict-mode: RC codegen test: shape used to feed App-bound let-close partial-drop into use_cell
|
||||
fn use_cell(c: own Cell) -> Int {
|
||||
match c {
|
||||
MkCell(w1, w2) => 1
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"defs":[{"ctors":[{"fields":[],"name":"INil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"name":"ICons"}],"drop-iterative":true,"kind":"type","name":"IntList"},{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"name":"n","t":"var"},{"name":"acc","t":"var"}],"ctor":"ICons","t":"ctor","type":"IntList"}],"fn":{"name":"cons_n_acc","t":"var"},"t":"app","tail":true},"t":"if","then":{"name":"acc","t":"var"}},"doc":"Tail-recursive list builder. acc-prepended.","kind":"fn","name":"cons_n_acc","params":["n","acc"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"IntList"}}},{"body":{"args":[{"name":"n","t":"var"},{"args":[],"ctor":"INil","t":"ctor","type":"IntList"}],"fn":{"name":"cons_n_acc","t":"var"},"t":"app"},"doc":"Build [1, 2, ..., n] :: IntList. Order is reverse of build but immaterial for head/sum.","kind":"fn","name":"cons_n","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"IntList"}}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"INil","fields":[],"p":"ctor"}},{"body":{"name":"h","t":"var"},"pat":{"ctor":"ICons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Take ownership of an IntList; return its head if ICons, else 0. The (own ...) signature signals 18d.4 to emit an Own-param drop at fn return — which under the (drop-iterative) annotation is the iterative-worklist body, freeing the entire chain via the heap-allocated worklist instead of recursive cascade.","kind":"fn","name":"head_or_zero","params":["xs"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":1000000},"t":"lit"}],"fn":{"name":"cons_n","t":"var"},"t":"app"}],"fn":{"name":"head_or_zero","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_drop_iterative_long_list","schema":"ailang/v0"}
|
||||
{"defs":[{"ctors":[{"fields":[],"name":"INil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"name":"ICons"}],"drop-iterative":true,"kind":"type","name":"IntList"},{"body":{"cond":{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"args":[{"name":"n","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"},{"args":[{"name":"n","t":"var"},{"name":"acc","t":"var"}],"ctor":"ICons","t":"ctor","type":"IntList"}],"fn":{"name":"cons_n_acc","t":"var"},"t":"app","tail":true},"t":"if","then":{"name":"acc","t":"var"}},"doc":"Tail-recursive list builder. acc-prepended.","kind":"fn","name":"cons_n_acc","params":["n","acc"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"IntList"}}},{"body":{"args":[{"name":"n","t":"var"},{"args":[],"ctor":"INil","t":"ctor","type":"IntList"}],"fn":{"name":"cons_n_acc","t":"var"},"t":"app"},"doc":"Build [1, 2, ..., n] :: IntList. Order is reverse of build but immaterial for head/sum.","kind":"fn","name":"cons_n","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"IntList"}}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"INil","fields":[],"p":"ctor"}},{"body":{"name":"h","t":"var"},"pat":{"ctor":"ICons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Take ownership of an IntList; return its head if ICons, else 0. The (own ...) signature signals 18d.4 to emit an Own-param drop at fn return — which under the (drop-iterative) annotation is the iterative-worklist body, freeing the entire chain via the heap-allocated worklist instead of recursive cascade.","kind":"fn","name":"head_or_zero","params":["xs"],"suppress":[{"because":"Iter 18e test: forces (drop-iterative) cascade via Own-param drop at fn return","code":"over-strict-mode"}],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":1000000},"t":"lit"}],"fn":{"name":"cons_n","t":"var"},"t":"app"}],"fn":{"name":"head_or_zero","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_drop_iterative_long_list","schema":"ailang/v0"}
|
||||
|
||||
@@ -1,93 +1,27 @@
|
||||
; Iter 18e fixture: `(drop-iterative)` opt-in annotation drives the
|
||||
; codegen to emit `drop_<m>_IntList` with a worklist body in place
|
||||
; of the recursive cascade. Without the annotation, freeing a long
|
||||
; list overflows Linux's default 8MB stack at ~1M cells (one frame
|
||||
; per recursive `drop_<m>_IntList(tail)` call). With it, the chain
|
||||
; pops through the heap-allocated worklist in O(N) time and O(1)
|
||||
; stack.
|
||||
;
|
||||
; The fixture builds a 100,000-cell IntList tail-recursively, sums
|
||||
; it into 4_999_950_000 (= N*(N-1)/2 for N=100_000), then `main`
|
||||
; returns. At process exit the build's `xs` binder is consumed by
|
||||
; sum_acc (via tail-call), so the iterative drop fires inside
|
||||
; sum_acc's `Cons` arm — specifically, on every recursive step the
|
||||
; tail t is bound, then t is consumed by the next iteration's
|
||||
; tail-app sum_acc, leaving no live cells at termination.
|
||||
;
|
||||
; Wait — under the actual emission shape: sum_acc's xs param is
|
||||
; (own (con IntList)); 18d.4 emits an Own-param drop at fn return.
|
||||
; On the inductive Cons arm, the fn returns via tail-call into the
|
||||
; next iteration (musttail), and the Own-param dec on xs at the
|
||||
; outer fn would normally fire — but tail-call elision means the
|
||||
; outer frame is gone before any post-tail-call code can run. The
|
||||
; canonical case for the iterative-drop test is therefore the
|
||||
; let-close-drop on `xs` in `main` (or the outer-let's drop after
|
||||
; sum's tail returns). For 18e the load-bearing property is "long
|
||||
; chains drop without overflowing the stack"; that fires whenever
|
||||
; ANY drop call against the head IntList runs end-to-end.
|
||||
;
|
||||
; To force the issue: `main` builds the list, sums it, prints the
|
||||
; sum, AND then `let xs = build n in let _ = sum xs in xs` does NOT
|
||||
; exist as a pattern in AILang. We instead route the list through a
|
||||
; `head` fn that takes (own IntList) and returns the head Int —
|
||||
; which transfers ownership and forces the Own-param drop on xs at
|
||||
; head's return. Because head's body (a match returning Int) cannot
|
||||
; be tail-called, the drop is emitted in head's epilogue and runs
|
||||
; in full before head returns to main.
|
||||
;
|
||||
; Expected stdout: `1` (the head of [1, 2, ..., 1_000_000]).
|
||||
; Why 1M and not 100K: at 100K the recursive cascade fits in the 8MB
|
||||
; default Linux stack (~64B/frame ≈ 6.4MB at 100K), so the test would
|
||||
; "pass" even without the iterative drop — false-negative on the
|
||||
; whole point of 18e. At 1M it overflows clean (SIGSEGV in the
|
||||
; recursive variant; clean exit-0 in the iterative variant).
|
||||
|
||||
(module rc_drop_iterative_long_list
|
||||
|
||||
(data IntList
|
||||
(ctor INil)
|
||||
(ctor ICons (con Int) (con IntList))
|
||||
(drop-iterative))
|
||||
|
||||
(fn cons_n_acc
|
||||
(doc "Tail-recursive list builder. acc-prepended.")
|
||||
(type
|
||||
(fn-type
|
||||
(params (con Int) (con IntList))
|
||||
(ret (con IntList))))
|
||||
(type (fn-type (params (con Int) (con IntList)) (ret (con IntList))))
|
||||
(params n acc)
|
||||
(body
|
||||
(if (app == n 0)
|
||||
acc
|
||||
(tail-app cons_n_acc
|
||||
(app - n 1)
|
||||
(term-ctor IntList ICons n acc)))))
|
||||
|
||||
(body (if (app == n 0) acc (tail-app cons_n_acc (app - n 1) (term-ctor IntList ICons n acc)))))
|
||||
(fn cons_n
|
||||
(doc "Build [1, 2, ..., n] :: IntList. Order is reverse of build but immaterial for head/sum.")
|
||||
(type
|
||||
(fn-type
|
||||
(params (con Int))
|
||||
(ret (con IntList))))
|
||||
(type (fn-type (params (con Int)) (ret (con IntList))))
|
||||
(params n)
|
||||
(body
|
||||
(app cons_n_acc n (term-ctor IntList INil))))
|
||||
|
||||
(body (app cons_n_acc n (term-ctor IntList INil))))
|
||||
(fn head_or_zero
|
||||
(doc "Take ownership of an IntList; return its head if ICons, else 0. The (own ...) signature signals 18d.4 to emit an Own-param drop at fn return — which under the (drop-iterative) annotation is the iterative-worklist body, freeing the entire chain via the heap-allocated worklist instead of recursive cascade.")
|
||||
(type
|
||||
(fn-type
|
||||
(params (own (con IntList)))
|
||||
(ret (con Int))))
|
||||
(suppress (code "over-strict-mode") (because "Iter 18e test: forces (drop-iterative) cascade via Own-param drop at fn return"))
|
||||
(type (fn-type (params (own (con IntList))) (ret (con Int))))
|
||||
(params xs)
|
||||
(body
|
||||
(match xs
|
||||
(case (pat-ctor INil) 0)
|
||||
(case (pat-ctor ICons h t) h))))
|
||||
|
||||
(body (match xs
|
||||
(case (pat-ctor INil) 0)
|
||||
(case (pat-ctor ICons h t) h))))
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(do io/print_int
|
||||
(app head_or_zero (app cons_n 1000000))))))
|
||||
(body (do io/print_int (app head_or_zero (app cons_n 1000000))))))
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"defs":[{"ctors":[{"fields":[{"k":"con","name":"Int"}],"name":"MkWrap"}],"kind":"type","name":"Wrap"},{"ctors":[{"fields":[{"k":"con","name":"Wrap"},{"k":"con","name":"Wrap"}],"name":"MkCell"}],"kind":"type","name":"Cell"},{"ctors":[{"fields":[{"k":"con","name":"Cell"},{"k":"con","name":"Cell"}],"name":"MkPair"}],"kind":"type","name":"Pair"},{"body":{"args":[{"args":[{"args":[{"name":"n","t":"var"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":2},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"},{"args":[{"args":[{"lit":{"kind":"int","value":3},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":4},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"}],"ctor":"MkPair","t":"ctor","type":"Pair"},"kind":"fn","name":"build_pair","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Pair"},"ret_mode":"own"}},{"body":{"arms":[{"body":{"arms":[{"body":{"lit":{"kind":"int","value":1},"t":"lit"},"pat":{"ctor":"MkCell","fields":[{"name":"w1","p":"var"},{"p":"wild"}],"p":"ctor"}}],"scrutinee":{"name":"a","t":"var"},"t":"match"},"pat":{"ctor":"MkPair","fields":[{"name":"a","p":"var"},{"name":"b","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"p","t":"var"},"t":"match"},"kind":"fn","name":"use_first","params":["p"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"Pair"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"build_pair","t":"var"},"t":"app"}],"fn":{"name":"use_first","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_match_arm_partial_drop_leak","schema":"ailang/v0"}
|
||||
{"defs":[{"ctors":[{"fields":[{"k":"con","name":"Int"}],"name":"MkWrap"}],"kind":"type","name":"Wrap"},{"ctors":[{"fields":[{"k":"con","name":"Wrap"},{"k":"con","name":"Wrap"}],"name":"MkCell"}],"kind":"type","name":"Cell"},{"ctors":[{"fields":[{"k":"con","name":"Cell"},{"k":"con","name":"Cell"}],"name":"MkPair"}],"kind":"type","name":"Pair"},{"body":{"args":[{"args":[{"args":[{"name":"n","t":"var"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":2},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"},{"args":[{"args":[{"lit":{"kind":"int","value":3},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":4},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"}],"ctor":"MkPair","t":"ctor","type":"Pair"},"kind":"fn","name":"build_pair","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Pair"},"ret_mode":"own"}},{"body":{"arms":[{"body":{"arms":[{"body":{"lit":{"kind":"int","value":1},"t":"lit"},"pat":{"ctor":"MkCell","fields":[{"name":"w1","p":"var"},{"p":"wild"}],"p":"ctor"}}],"scrutinee":{"name":"a","t":"var"},"t":"match"},"pat":{"ctor":"MkPair","fields":[{"name":"a","p":"var"},{"name":"b","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"p","t":"var"},"t":"match"},"kind":"fn","name":"use_first","params":["p"],"suppress":[{"because":"RC codegen test: exercises Iter A outer-arm-close partial-drop","code":"over-strict-mode"}],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"Pair"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"build_pair","t":"var"},"t":"app"}],"fn":{"name":"use_first","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_match_arm_partial_drop_leak","schema":"ailang/v0"}
|
||||
|
||||
@@ -1,71 +1,22 @@
|
||||
; Iter 18g.tidy.fu2 RED-test fixture 2/3: dynamic-tag partial-drop
|
||||
; carve-out at outer-arm-close pattern-binder dec
|
||||
; (Iter A / match_lower.rs:839).
|
||||
;
|
||||
; Shape:
|
||||
; - `Pair` carries two `Cell` fields; `Cell` carries two `Wrap`
|
||||
; fields. (Same types as fixture 1.)
|
||||
; - `use_first` takes `(own Pair)` and the OUTER match binds both
|
||||
; slots: `MkPair a b`.
|
||||
; - The arm body INNER-matches `a` as `MkCell w1 _` — slot 0 of
|
||||
; a is bound, slot 1 is wildcarded.
|
||||
; - Inner arm-close drops `w1` properly via `drop_<m>_Wrap`.
|
||||
; Inner match adds slot 0 to `moved_slots[a]`.
|
||||
; - Outer arm-close drops `a` and `b`. `a` has `moves={0}`
|
||||
; (non-empty) and `consume_count==0` (only Borrow use as
|
||||
; scrutinee of inner match) → Iter A's dynamic-tag carve-out
|
||||
; fires: shallow `ailang_rc_dec(a)`. a's outer Cell is freed,
|
||||
; but slot 1 (the unbound MkWrap(2) cell) leaks.
|
||||
; - `b` has `moves={}` and `consume_count==0` → routes through
|
||||
; `drop_<m>_Cell(b)` which cascades through both Wraps. No
|
||||
; leak from b.
|
||||
; - At fn return, `p`'s `moves={0,1}` (both slots bound) → Iter
|
||||
; B carve-out fires too, but with all slots moved, the shallow
|
||||
; dec is correct (no additional leak from p).
|
||||
;
|
||||
; Pre-fix: live = 1 (the unbound MkWrap(2) cell in slot 1 of a).
|
||||
; Post-fix: live = 0.
|
||||
|
||||
(module rc_match_arm_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)))))
|
||||
(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)))))
|
||||
|
||||
(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_first
|
||||
(type
|
||||
(fn-type
|
||||
(params (own (con Pair)))
|
||||
(ret (con Int))))
|
||||
(suppress (code "over-strict-mode") (because "RC codegen test: exercises Iter A outer-arm-close partial-drop"))
|
||||
(type (fn-type (params (own (con Pair))) (ret (con Int))))
|
||||
(params p)
|
||||
(body
|
||||
(match p
|
||||
(case (pat-ctor MkPair a b)
|
||||
(match a
|
||||
(case (pat-ctor MkCell w1 _) 1))))))
|
||||
|
||||
(body (match p
|
||||
(case (pat-ctor MkPair a b) (match a
|
||||
(case (pat-ctor MkCell w1 _) 1))))))
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(do io/print_int (app use_first (app build_pair 1))))))
|
||||
(body (do io/print_int (app use_first (app build_pair 1))))))
|
||||
|
||||
@@ -10,6 +10,7 @@ fn build_pair(n: Int) -> own Pair {
|
||||
MkPair(MkCell(MkWrap(n), MkWrap(2)), MkCell(MkWrap(3), MkWrap(4)))
|
||||
}
|
||||
|
||||
// @suppress over-strict-mode: RC codegen test: exercises Iter A outer-arm-close partial-drop
|
||||
fn use_first(p: own Pair) -> Int {
|
||||
match p {
|
||||
MkPair(a, b) => match a {
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"defs":[{"ctors":[{"fields":[],"name":"Nil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"name":"Cons"}],"doc":"Recursive Int list — boxed.","kind":"type","name":"IntList"},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"Nil","fields":[],"p":"ctor"}},{"body":{"name":"h","t":"var"},"pat":{"ctor":"Cons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Take ownership of an IntList; return its head if Cons, else 0. The tail is loaded as a pattern binder but never consumed — iter A dec's it at arm close. The outer cell is dec'd at fn return via iter B's Own-param emission.","kind":"fn","name":"head_or_zero","params":["xs"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"args":[{"args":[{"name":"xs","t":"var"}],"fn":{"name":"head_or_zero","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"name":"xs","t":"let","value":{"args":[{"lit":{"kind":"int","value":11},"t":"lit"},{"args":[{"lit":{"kind":"int","value":22},"t":"lit"},{"args":[{"lit":{"kind":"int","value":33},"t":"lit"},{"args":[{"lit":{"kind":"int","value":44},"t":"lit"},{"args":[{"lit":{"kind":"int","value":55},"t":"lit"},{"args":[],"ctor":"Nil","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}},"doc":"Build a 5-element IntList; pass to head_or_zero (transferring ownership); print the result.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_own_param_drop","schema":"ailang/v0"}
|
||||
{"defs":[{"ctors":[{"fields":[],"name":"Nil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"name":"Cons"}],"doc":"Recursive Int list — boxed.","kind":"type","name":"IntList"},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":0},"t":"lit"},"pat":{"ctor":"Nil","fields":[],"p":"ctor"}},{"body":{"name":"h","t":"var"},"pat":{"ctor":"Cons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Take ownership of an IntList; return its head if Cons, else 0. The tail is loaded as a pattern binder but never consumed — iter A dec's it at arm close. The outer cell is dec'd at fn return via iter B's Own-param emission.","kind":"fn","name":"head_or_zero","params":["xs"],"suppress":[{"because":"RC codegen test: exercises Iter B Own-param dec at fn return","code":"over-strict-mode"}],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"Int"}}},{"body":{"body":{"args":[{"args":[{"name":"xs","t":"var"}],"fn":{"name":"head_or_zero","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"name":"xs","t":"let","value":{"args":[{"lit":{"kind":"int","value":11},"t":"lit"},{"args":[{"lit":{"kind":"int","value":22},"t":"lit"},{"args":[{"lit":{"kind":"int","value":33},"t":"lit"},{"args":[{"lit":{"kind":"int","value":44},"t":"lit"},{"args":[{"lit":{"kind":"int","value":55},"t":"lit"},{"args":[],"ctor":"Nil","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}},"doc":"Build a 5-element IntList; pass to head_or_zero (transferring ownership); print the result.","kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_own_param_drop","schema":"ailang/v0"}
|
||||
|
||||
@@ -1,62 +1,18 @@
|
||||
; Iter 18d.4 — Own-param dec at fn return.
|
||||
;
|
||||
; Companion fixture to `alloc_rc_borrow_only_recursive_list_drop`.
|
||||
; Here the static "caller handed off ownership" signal is the
|
||||
; explicit `(own (con IntList))` parameter mode on `head_or_zero`.
|
||||
; Under --alloc=rc, codegen now emits a drop call against the
|
||||
; param SSA (`%arg_xs`) before the fn's `ret`, closing the
|
||||
; symmetric debt 18c.3/18c.4 carried.
|
||||
;
|
||||
; Fixture shape:
|
||||
; - `head_or_zero` takes `(own (con IntList))` and returns Int.
|
||||
; Body destructures via match, returns the head in the Cons
|
||||
; arm (ignoring the tail) and 0 in the Nil arm.
|
||||
; - `xs` (the param) has consume_count == 0 (only borrow at
|
||||
; match scrutinee). Iter B fires: param drop at fn return.
|
||||
; - `t` (Cons-arm pattern binder) has consume_count == 0 (the
|
||||
; arm body just returns `h` — `t` is unused). Iter A fires:
|
||||
; drop_<m>_IntList(t) at arm close, freeing the tail chain
|
||||
; before the fn returns.
|
||||
; - At fn return, moved_slots[xs] = {1} (Cons.t was moved into
|
||||
; the arm-bound `t` and dec'd by iter A). Iter B falls back
|
||||
; to shallow `ailang_rc_dec(%arg_xs)` — the dynamic-tag
|
||||
; partial-drop case is debt; for the canonical Cons-or-Nil
|
||||
; dispatch here, dec'ing the outer cell only is correct
|
||||
; because the active ctor's only ptr field (Cons.tail) is
|
||||
; already freed by iter A, and Nil has no ptr fields.
|
||||
;
|
||||
; Expected stdout under --alloc=rc / --alloc=gc: 11 (head of the
|
||||
; 5-element list).
|
||||
|
||||
(module rc_own_param_drop
|
||||
|
||||
(data IntList
|
||||
(doc "Recursive Int list — boxed.")
|
||||
(ctor Nil)
|
||||
(ctor Cons (con Int) (con IntList)))
|
||||
|
||||
(fn head_or_zero
|
||||
(doc "Take ownership of an IntList; return its head if Cons, else 0. The tail is loaded as a pattern binder but never consumed — iter A dec's it at arm close. The outer cell is dec'd at fn return via iter B's Own-param emission.")
|
||||
(type
|
||||
(fn-type
|
||||
(params (own (con IntList)))
|
||||
(ret (con Int))))
|
||||
(suppress (code "over-strict-mode") (because "RC codegen test: exercises Iter B Own-param dec at fn return"))
|
||||
(type (fn-type (params (own (con IntList))) (ret (con Int))))
|
||||
(params xs)
|
||||
(body
|
||||
(match xs
|
||||
(case (pat-ctor Nil) 0)
|
||||
(case (pat-ctor Cons h t) h))))
|
||||
|
||||
(body (match xs
|
||||
(case (pat-ctor Nil) 0)
|
||||
(case (pat-ctor Cons h t) h))))
|
||||
(fn main
|
||||
(doc "Build a 5-element IntList; pass to head_or_zero (transferring ownership); print the result.")
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(let xs
|
||||
(term-ctor IntList Cons 11
|
||||
(term-ctor IntList Cons 22
|
||||
(term-ctor IntList Cons 33
|
||||
(term-ctor IntList Cons 44
|
||||
(term-ctor IntList Cons 55
|
||||
(term-ctor IntList Nil))))))
|
||||
(do io/print_int (app head_or_zero xs))))))
|
||||
(body (let xs (term-ctor IntList Cons 11 (term-ctor IntList Cons 22 (term-ctor IntList Cons 33 (term-ctor IntList Cons 44 (term-ctor IntList Cons 55 (term-ctor IntList Nil)))))) (do io/print_int (app head_or_zero xs))))))
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/// Recursive Int list — boxed.
|
||||
data IntList = Nil | Cons(Int, IntList)
|
||||
|
||||
// @suppress over-strict-mode: RC codegen test: exercises Iter B Own-param dec at fn return
|
||||
/// Take ownership of an IntList; return its head if Cons, else 0. The tail is
|
||||
/// loaded as a pattern binder but never consumed — iter A dec's it at arm
|
||||
/// close. The outer cell is dec'd at fn return via iter B's Own-param emission.
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"defs":[{"ctors":[{"fields":[{"k":"con","name":"Int"}],"name":"MkWrap"}],"kind":"type","name":"Wrap"},{"ctors":[{"fields":[{"k":"con","name":"Wrap"},{"k":"con","name":"Wrap"}],"name":"MkCell"}],"kind":"type","name":"Cell"},{"ctors":[{"fields":[{"k":"con","name":"Cell"},{"k":"con","name":"Cell"}],"name":"MkPair"}],"kind":"type","name":"Pair"},{"body":{"args":[{"args":[{"args":[{"name":"n","t":"var"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":2},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"},{"args":[{"args":[{"lit":{"kind":"int","value":3},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":4},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"}],"ctor":"MkPair","t":"ctor","type":"Pair"},"kind":"fn","name":"build_pair","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Pair"},"ret_mode":"own"}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":1},"t":"lit"},"pat":{"ctor":"MkPair","fields":[{"name":"a","p":"var"},{"p":"wild"}],"p":"ctor"}}],"scrutinee":{"name":"p","t":"var"},"t":"match"},"kind":"fn","name":"use_first","params":["p"],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"Pair"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"build_pair","t":"var"},"t":"app"}],"fn":{"name":"use_first","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_own_param_partial_drop_leak","schema":"ailang/v0"}
|
||||
{"defs":[{"ctors":[{"fields":[{"k":"con","name":"Int"}],"name":"MkWrap"}],"kind":"type","name":"Wrap"},{"ctors":[{"fields":[{"k":"con","name":"Wrap"},{"k":"con","name":"Wrap"}],"name":"MkCell"}],"kind":"type","name":"Cell"},{"ctors":[{"fields":[{"k":"con","name":"Cell"},{"k":"con","name":"Cell"}],"name":"MkPair"}],"kind":"type","name":"Pair"},{"body":{"args":[{"args":[{"args":[{"name":"n","t":"var"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":2},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"},{"args":[{"args":[{"lit":{"kind":"int","value":3},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"},{"args":[{"lit":{"kind":"int","value":4},"t":"lit"}],"ctor":"MkWrap","t":"ctor","type":"Wrap"}],"ctor":"MkCell","t":"ctor","type":"Cell"}],"ctor":"MkPair","t":"ctor","type":"Pair"},"kind":"fn","name":"build_pair","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Pair"},"ret_mode":"own"}},{"body":{"arms":[{"body":{"lit":{"kind":"int","value":1},"t":"lit"},"pat":{"ctor":"MkPair","fields":[{"name":"a","p":"var"},{"p":"wild"}],"p":"ctor"}}],"scrutinee":{"name":"p","t":"var"},"t":"match"},"kind":"fn","name":"use_first","params":["p"],"suppress":[{"because":"RC codegen test: exercises Iter B fn-return dynamic-tag partial-drop","code":"over-strict-mode"}],"type":{"effects":[],"k":"fn","param_modes":["own"],"params":[{"k":"con","name":"Pair"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"build_pair","t":"var"},"t":"app"}],"fn":{"name":"use_first","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"rc_own_param_partial_drop_leak","schema":"ailang/v0"}
|
||||
|
||||
@@ -1,65 +1,21 @@
|
||||
; Iter 18g.tidy.fu2 RED-test fixture 1/3: dynamic-tag partial-drop
|
||||
; carve-out at fn-return (Iter B / lib.rs:1093).
|
||||
;
|
||||
; Shape:
|
||||
; - `Pair` carries two `Cell` fields (both pointer-typed).
|
||||
; - `Cell` carries two `Wrap` fields (both pointer-typed).
|
||||
; - `use_first` takes `(own Pair)` and pattern-binds the first
|
||||
; slot only, wildcarding the second.
|
||||
; - The bound slot's `Cell` is dec'd via `drop_<m>_Cell` at the
|
||||
; outer arm-close (moves[a] empty → field_drop_call routes
|
||||
; correctly).
|
||||
; - At fn return, `p`'s `consume_count == 0`, mode = Own, and
|
||||
; `moved_slots[p] = {0}`. Iter B's drop (lib.rs:1093) hits the
|
||||
; dynamic-tag carve-out: moves non-empty → shallow
|
||||
; `ailang_rc_dec(p)`. p's outer cell is freed; slot 1 (the
|
||||
; wildcarded second Cell + its two MkWrap children = 3 cells)
|
||||
; leaks.
|
||||
;
|
||||
; Pre-fix: live = 3 (one Cell + two MkWrap children).
|
||||
; Post-fix: live = 0.
|
||||
;
|
||||
; This fixture is the cleanest of the three because no inner match
|
||||
; is involved: the leak surfaces from Iter B alone.
|
||||
|
||||
(module rc_own_param_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)))))
|
||||
(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)))))
|
||||
|
||||
(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_first
|
||||
(type
|
||||
(fn-type
|
||||
(params (own (con Pair)))
|
||||
(ret (con Int))))
|
||||
(suppress (code "over-strict-mode") (because "RC codegen test: exercises Iter B fn-return dynamic-tag partial-drop"))
|
||||
(type (fn-type (params (own (con Pair))) (ret (con Int))))
|
||||
(params p)
|
||||
(body
|
||||
(match p
|
||||
(case (pat-ctor MkPair a _) 1))))
|
||||
|
||||
(body (match p
|
||||
(case (pat-ctor MkPair a _) 1))))
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(do io/print_int (app use_first (app build_pair 1))))))
|
||||
(body (do io/print_int (app use_first (app build_pair 1))))))
|
||||
|
||||
Reference in New Issue
Block a user