fix(examples): destructure partition_eithers result once (#57, 0064 iter 4)
Final iteration of spec 0064 (the #55-cutover hardening, #57). Closes class 4, the one genuine corpus bug among the four (not a false positive): std_either_list.partition_eithers projected both (app Pair.fst rest) and (app Pair.snd rest) from one owned `rest`. Pair.fst/snd are own-param projections that move a field out, so each consumes `rest` -> a genuine double-consume that universal linearity activation (#55) would correctly reject. The fix is a body rewrite (destructure `rest` once via (match rest (case (pat-ctor MkPair ls rs) …)) then dispatch on the head), NOT a check change -- the check is right. Latent until activation: partition_eithers' param is a bare (Implicit) slot today, so the check is skipped on it -- no RED->GREEN flip on the real fixture. The rewrite is a pre-emptive corpus fix. Its correctness rests on the unchanged 2 3 2 3 E2E output (std_either_list_demo, a semantically-identical partition) and on the new c4_double_consume must-stay-RED fixture, which -- with explicit modes, so the check is active today -- demonstrates the double-projection shape IS rejected. - examples/std_either_list.ail: partition_eithers Cons arm rewritten; doc updated (destructure-once, no longer "projections"). - examples/c4_double_consume.ail: must-stay-RED pin (the rejected shape), folded into a generalised harden_ownership_heap_double_consume_still_errors loop over {real_consume, c4_double_consume}. - examples/c4_rewrite.ail: stays-clean pin (the accepted destructure-once shape), added to harden_ownership_false_positives_are_clean. No hash-pin on std_either_list (verified); the e2e 2 3 2 3 output pin is the content pin and is preserved. No check/schema/codegen change. Verified: std_either_list checks clean; demo 2 3 2 3; both harden assertions green; cargo test --workspace green; bench/check.py 34/34, compile_check.py 24/24 stable. This is the last of the four #57 hardening classes. Spec 0064 is now code-complete: classes 1 (local fn-param modes), 2 (let-alias redirect), 3 (value-typed let-binder), and 4 (this) all shipped. The cycle is ready for audit; the #55 cutover precondition is met. refs #57
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
(module c4_double_consume
|
||||
(data Pair
|
||||
(doc "boxed pair of ints")
|
||||
(ctor MkPair (con Int) (con Int)))
|
||||
(fn fst (type (fn-type (params (own (con Pair))) (ret (own (con Int))))) (params p)
|
||||
(body (match p (case (pat-ctor MkPair a b) a))))
|
||||
(fn snd (type (fn-type (params (own (con Pair))) (ret (own (con Int))))) (params p)
|
||||
(body (match p (case (pat-ctor MkPair a b) b))))
|
||||
(fn both
|
||||
(doc "MUST STAY RED: rest projected by fst AND snd = consumed twice")
|
||||
(type (fn-type (params (own (con Pair))) (ret (own (con Pair)))))
|
||||
(params rest)
|
||||
(body (term-ctor Pair MkPair (app fst rest) (app snd rest)))))
|
||||
@@ -0,0 +1,9 @@
|
||||
(module c4_rewrite
|
||||
(data Pair
|
||||
(doc "boxed pair of ints")
|
||||
(ctor MkPair (con Int) (con Int)))
|
||||
(fn both
|
||||
(doc "rewrite: destructure rest once via match")
|
||||
(type (fn-type (params (own (con Pair))) (ret (own (con Pair)))))
|
||||
(params rest)
|
||||
(body (match rest (case (pat-ctor MkPair a b) (term-ctor Pair MkPair a b))))))
|
||||
@@ -45,7 +45,7 @@
|
||||
(case _ (term-ctor List Nil)))))
|
||||
|
||||
(fn partition_eithers
|
||||
(doc "Partition a list of Eithers into a Pair<List<e>, List<a>>: lefts on the left, rights on the right. Single pass via direct recursion; head dispatch is a flat match on the recursive result's projections.")
|
||||
(doc "Partition a list of Eithers into a Pair<List<e>, List<a>>: lefts on the left, rights on the right. Single pass via direct recursion; the recursive result is destructured once and the head dispatches into the matching side.")
|
||||
(type
|
||||
(forall (vars e a)
|
||||
(fn-type
|
||||
@@ -60,12 +60,14 @@
|
||||
(term-ctor List Nil)))
|
||||
(case (pat-ctor Cons h t)
|
||||
(let rest (app partition_eithers t)
|
||||
(match h
|
||||
(case (pat-ctor Left l)
|
||||
(term-ctor Pair MkPair
|
||||
(term-ctor List Cons l (app Pair.fst rest))
|
||||
(app Pair.snd rest)))
|
||||
(case (pat-ctor Right r)
|
||||
(term-ctor Pair MkPair
|
||||
(app Pair.fst rest)
|
||||
(term-ctor List Cons r (app Pair.snd rest)))))))))))
|
||||
(match rest
|
||||
(case (pat-ctor MkPair ls rs)
|
||||
(match h
|
||||
(case (pat-ctor Left l)
|
||||
(term-ctor Pair MkPair
|
||||
(term-ctor List Cons l ls)
|
||||
rs))
|
||||
(case (pat-ctor Right r)
|
||||
(term-ctor Pair MkPair
|
||||
ls
|
||||
(term-ctor List Cons r rs))))))))))))
|
||||
|
||||
Reference in New Issue
Block a user