Skip to content

Commit c1c753e

Browse files
proof(L2 Phase 2 / Phase D slice 2): T_Lam_L1_*_Eff rules + cascade (#204)
## Summary - Adds `T_Lam_L1_Linear_Eff` + `T_Lam_L1_Affine_Eff` to `TypingL1.v` typing effect-typed lambda values formed via `TFunEff T1 T2 R_in R_out` (slice 1, PR #200). - Side condition `forall r, In r R -> In r R_in` bridges outer/inner envs, making `subst_typing_gen_l1_m` and `region_shrink_preserves_typing_l1_gen_m` close. - 3 inductive lemma cascades extended (~35 lines). ## Design (per formal/PHASE-D-REDESIGN.md + 2026-05-28 refinement) R_in ⊇ R reading: body has access to at least formation regions, possibly more. Balances: - Substitution: Hregv : In rv R → In rv R_in via side condition. - Env-shrinkage: TFunEff contains R_in (not outer R), preserved under outer R shrinkage. ## Not in this PR - T_App_L1_Eff + TFunEff_count_monotone → slice 3 - preservation_l1 lambda-rigidity closure → slice 4 - Phase B + Phase C re-attempts → slice 5 ## Test plan - [x] coqc 8.18.0 10/10 .v rebuild clean - [x] Admit budget preserved (7 + 1 legacy = baseline) - [x] Zero new Axiom; GPG-signed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a159c36 commit c1c753e

2 files changed

Lines changed: 81 additions & 0 deletions

File tree

formal/Semantics_L1.v

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,15 @@ Proof.
473473
apply T_Lam_L1_Linear. eapply IHHt; auto.
474474
- (* T_Lam_L1_Affine *)
475475
eapply T_Lam_L1_Affine. eapply IHHt; auto.
476+
- (* T_Lam_L1_Linear_Eff — body's R_in is separate from outer R, but
477+
the side condition [forall r, In r R -> In r R_in] survives
478+
outer shrinkage (smaller outer R ⊆ original R ⊆ R_in). The body
479+
typing at R_in is unchanged. *)
480+
eapply T_Lam_L1_Linear_Eff; [|eassumption].
481+
intros r0 Hin0. apply H. eapply remove_first_subset. exact Hin0.
482+
- (* T_Lam_L1_Affine_Eff — same pattern. *)
483+
eapply T_Lam_L1_Affine_Eff; [|eassumption].
484+
intros r0 Hin0. apply H. eapply remove_first_subset. exact Hin0.
476485
- (* T_App_L1 *)
477486
destruct Hfree as [Hf1 Hf2].
478487
eapply T_App_L1; [eapply IHHt1; auto | eapply IHHt2; auto].
@@ -1002,6 +1011,13 @@ Proof.
10021011
(* T_Lam_L1_Affine *)
10031012
- assert (IH := IHHtype (S k) T_new ltac:(simpl; lia)).
10041013
simpl in IH. eapply T_Lam_L1_Affine. exact IH.
1014+
(* T_Lam_L1_Linear_Eff — side condition + body via IH on (S k) shift.
1015+
The side condition is shift-invariant. *)
1016+
- assert (IH := IHHtype (S k) T_new ltac:(simpl; lia)).
1017+
simpl in IH. eapply T_Lam_L1_Linear_Eff; [exact H | exact IH].
1018+
(* T_Lam_L1_Affine_Eff — same. *)
1019+
- assert (IH := IHHtype (S k) T_new ltac:(simpl; lia)).
1020+
simpl in IH. eapply T_Lam_L1_Affine_Eff; [exact H | exact IH].
10051021
(* T_App_L1 *)
10061022
- eapply T_App_L1; [apply IHHtype1; assumption|].
10071023
apply IHHtype2. assert (Hlen := typing_preserves_length_l1 _ _ _ _ _ _ _ Htype1). lia.
@@ -1459,6 +1475,25 @@ Proof.
14591475
simpl; try eassumption; try reflexivity.
14601476
apply loc_retype_at_R_l1_m. exact Hregv.
14611477

1478+
(* T_Lam_L1_Linear_Eff — body's R = R_in (separate from outer R), but
1479+
the side condition [H : forall r, In r R -> In r R_in] gives
1480+
In rv R_in from Hregv : In rv R. The body then types the
1481+
substituted location at R_in. *)
1482+
- assert (u_out = u_in) by congruence; subst.
1483+
eapply T_Lam_L1_Linear_Eff; [exact H |].
1484+
destruct (linear_value_is_loc_l1 _ _ _ _ Hv_type Hval Hlin) as [lv [rv [-> [-> Hregv]]]].
1485+
eapply (IHHtype (S k0) (TString rv) (ELoc lv rv) u_in);
1486+
simpl; try eassumption; try reflexivity.
1487+
apply loc_retype_at_R_l1_m. apply H. exact Hregv.
1488+
1489+
(* T_Lam_L1_Affine_Eff — same. *)
1490+
- assert (u_out = u_in) by congruence; subst.
1491+
eapply T_Lam_L1_Affine_Eff; [exact H |].
1492+
destruct (linear_value_is_loc_l1 _ _ _ _ Hv_type Hval Hlin) as [lv [rv [-> [-> Hregv]]]].
1493+
eapply (IHHtype (S k0) (TString rv) (ELoc lv rv) u_in);
1494+
simpl; try eassumption; try reflexivity.
1495+
apply loc_retype_at_R_l1_m. apply H. exact Hregv.
1496+
14621497
(* T_App_L1 *)
14631498
- destruct (output_shape_at_l1 _ _ _ _ _ _ _ _ _ _ Htype1 Hk_in) as [u_mid Hu_mid].
14641499
eapply T_App_L1.

formal/TypingL1.v

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,52 @@ Inductive has_type_l1
182182
R ; ctx_extend G T1 |=L1[Affine] e : T2 -| R ; (T1, u) :: G ->
183183
R ; G |=L1[Affine] ELam T1 e : TFun T1 T2 -| R ; G
184184

185+
(** ===== Phase D slice 2 — Effect-typed lambda rules =====
186+
187+
[T_Lam_L1_Linear_Eff] / [T_Lam_L1_Affine_Eff] parallel
188+
[T_Lam_L1_Linear] / [T_Lam_L1_Affine] but record the body's
189+
R-flow into the function type via [TFunEff T1 T2 R_in R_out]
190+
(slice 1, PR #200; refined per [formal/PHASE-D-REDESIGN.md]).
191+
192+
**Design choice (2026-05-28 final):** the rule carries a
193+
side condition [forall r, In r R -> In r R_in], i.e., the
194+
body's input env [R_in] is a SUPERSET of the formation env
195+
[R]. This makes:
196+
197+
* Substitution: any value at outer R has its region rv ∈ R;
198+
side condition gives rv ∈ R_in, which is what the body
199+
needs after substitution.
200+
* Env-shrinkage lemmas: the type T = TFunEff T1 T2 R_in R_out
201+
contains R_in (not the outer R). Shrinking outer R from R
202+
to remove_first rr R preserves the side condition (smaller
203+
R is still a subset of R_in).
204+
205+
Why not R_in = R (tighter)? That ties the type to the
206+
formation env, breaking env-shrinkage lemmas (the type
207+
changes when env shrinks). Why not R_in unconstrained? That
208+
breaks substitution (the substituted value's region might
209+
not be in R_in).
210+
211+
The R_in ⊇ R reading: "the body has access to AT LEAST the
212+
formation regions, possibly more (declared up front)." Natural
213+
and compositional. An explicit weakening for use at different
214+
call-site Rs ships in slice 3 (T_App_L1_Eff).
215+
216+
Per the L3 wiring playbook (parallel-rule strategy): existing
217+
[TFun]-typed programs continue to type via [T_Lam_L1_Linear] /
218+
[T_Lam_L1_Affine] unchanged. New code uses these [_Eff] rules
219+
to opt into effect-typed lambdas. *)
220+
221+
| T_Lam_L1_Linear_Eff : forall R G T1 T2 e R_in R_out,
222+
(forall r, In r R -> In r R_in) ->
223+
R_in ; ctx_extend G T1 |=L1[Linear] e : T2 -| R_out ; (T1, true) :: G ->
224+
R ; G |=L1[Linear] ELam T1 e : TFunEff T1 T2 R_in R_out -| R ; G
225+
226+
| T_Lam_L1_Affine_Eff : forall R G T1 T2 e u R_in R_out,
227+
(forall r, In r R -> In r R_in) ->
228+
R_in ; ctx_extend G T1 |=L1[Affine] e : T2 -| R_out ; (T1, u) :: G ->
229+
R ; G |=L1[Affine] ELam T1 e : TFunEff T1 T2 R_in R_out -| R ; G
230+
185231
| T_App_L1 : forall m R R1 R2 G G' G'' e1 e2 T1 T2,
186232
R ; G |=L1[m] e1 : TFun T1 T2 -| R1 ; G' ->
187233
R1 ; G' |=L1[m] e2 : T1 -| R2 ; G'' ->

0 commit comments

Comments
 (0)