aboutsummaryrefslogtreecommitdiff
path: root/src/UnderLetsProofs.v
diff options
context:
space:
mode:
Diffstat (limited to 'src/UnderLetsProofs.v')
-rw-r--r--src/UnderLetsProofs.v1025
1 files changed, 1025 insertions, 0 deletions
diff --git a/src/UnderLetsProofs.v b/src/UnderLetsProofs.v
new file mode 100644
index 000000000..787fdb7c4
--- /dev/null
+++ b/src/UnderLetsProofs.v
@@ -0,0 +1,1025 @@
+Require Import Coq.Lists.List.
+Require Import Coq.Classes.Morphisms.
+Require Import Coq.Lists.SetoidList.
+Require Import Crypto.Language.
+Require Import Crypto.LanguageInversion.
+Require Import Crypto.LanguageWf.
+Require Import Crypto.UnderLets.
+Require Import Crypto.Util.Prod.
+Require Import Crypto.Util.Sigma.
+Require Import Crypto.Util.Option.
+Require Import Crypto.Util.Tactics.BreakMatch.
+Require Import Crypto.Util.Tactics.DestructHead.
+Require Import Crypto.Util.Tactics.SpecializeAllWays.
+Require Import Crypto.Util.Tactics.SpecializeBy.
+Import ListNotations. Local Open Scope list_scope.
+
+Import EqNotations.
+Module Compilers.
+ Import Language.Compilers.
+ Import LanguageInversion.Compilers.
+ Import LanguageWf.Compilers.
+ Import UnderLets.Compilers.
+ Import ident.Notations.
+ Import expr.Notations.
+ Import invert_expr.
+
+ Module SubstVarLike.
+ Section with_ident.
+ Context {base_type : Type}.
+ Local Notation type := (type.type base_type).
+ Context {ident : type -> Type}.
+ Local Notation expr := (@expr.expr base_type ident).
+ Section with_var.
+ Context {var1 var2 : type -> Type}.
+ Local Notation expr1 := (@expr.expr base_type ident var1).
+ Local Notation expr2 := (@expr.expr base_type ident var2).
+ Section with_var_like.
+ Context (is_var_like1 : forall t, @expr var1 t -> bool)
+ (is_var_like2 : forall t, @expr var2 t -> bool).
+ Local Notation subst_var_like1 := (@SubstVarLike.subst_var_like base_type ident var1 is_var_like1).
+ Local Notation subst_var_like2 := (@SubstVarLike.subst_var_like base_type ident var2 is_var_like2).
+ Definition is_var_like_wfT := forall G t e1 e2, expr.wf G (t:=t) e1 e2 -> is_var_like1 t e1 = is_var_like2 t e2.
+ Context (is_var_like_good : is_var_like_wfT).
+
+ Lemma wf_subst_var_like G1 G2 t e1 e2
+ (HG1G2 : forall t v1 v2, List.In (existT _ t (v1, v2)) G1 -> expr.wf G2 v1 v2)
+ : expr.wf G1 (t:=t) e1 e2 -> expr.wf G2 (subst_var_like1 e1) (subst_var_like2 e2).
+ Proof.
+ cbv [is_var_like_wfT] in *.
+ intro Hwf; revert dependent G2; induction Hwf;
+ cbn [SubstVarLike.subst_var_like];
+ repeat first [ match goal with
+ | [ H : is_var_like1 _ ?x = _, H' : is_var_like2 _ ?y = _ |- _ ]
+ => assert (is_var_like1 _ x = is_var_like2 _ y) by eauto; congruence
+ end
+ | progress wf_safe_t
+ | progress break_innermost_match
+ | solve [ wf_t ] ].
+ Qed.
+ End with_var_like.
+
+ Section with_ident_like.
+ Context (ident_is_good : forall t, ident t -> bool).
+
+ Lemma wfT_is_recursively_var_or_ident
+ : is_var_like_wfT (fun t => SubstVarLike.is_recursively_var_or_ident ident_is_good)
+ (fun t => SubstVarLike.is_recursively_var_or_ident ident_is_good).
+ Proof.
+ intros G t e1 e2 Hwf; induction Hwf; cbn [SubstVarLike.is_recursively_var_or_ident];
+ congruence.
+ Qed.
+ End with_ident_like.
+
+ Lemma wfT_is_var
+ : is_var_like_wfT (fun _ e => match invert_Var e with Some _ => true | None => false end)
+ (fun _ e => match invert_Var e with Some _ => true | None => false end).
+ Proof. intros G t e1 e2 Hwf; destruct Hwf; cbn [invert_Var]; reflexivity. Qed.
+ End with_var.
+
+ Local Notation SubstVarLike := (@SubstVarLike.SubstVarLike base_type ident).
+ Local Notation SubstVar := (@SubstVarLike.SubstVar base_type ident).
+ Local Notation SubstVarOrIdent := (@SubstVarLike.SubstVarOrIdent base_type ident).
+
+ Lemma Wf_SubstVarLike (is_var_like : forall var t, @expr var t -> bool)
+ (is_var_like_good : forall var1 var2, is_var_like_wfT (is_var_like var1) (is_var_like var2))
+ {t} (e : expr.Expr t)
+ : expr.Wf e -> expr.Wf (SubstVarLike is_var_like e).
+ Proof.
+ intros Hwf var1 var2; eapply wf_subst_var_like; eauto with nocore; cbn [In]; tauto.
+ Qed.
+
+ Lemma Wf_SubstVar {t} (e : expr.Expr t)
+ : expr.Wf e -> expr.Wf (SubstVar e).
+ Proof.
+ intros Hwf var1 var2; eapply wf_subst_var_like; eauto using wfT_is_var with nocore; cbn [In]; tauto.
+ Qed.
+
+ Lemma Wf_SubstVarOrIdent (should_subst_ident : forall t, ident t -> bool)
+ {t} (e : expr.Expr t)
+ : expr.Wf e -> expr.Wf (SubstVarOrIdent should_subst_ident e).
+ Proof.
+ intros Hwf var1 var2; eapply wf_subst_var_like; eauto using wfT_is_recursively_var_or_ident with nocore; cbn [In]; tauto.
+ Qed.
+
+ Section interp.
+ Context {base_interp : base_type -> Type}
+ {interp_ident : forall t, ident t -> type.interp base_interp t}
+ {interp_ident_Proper : forall t, Proper (eq ==> type.eqv) (interp_ident t)}.
+ Section with_is_var_like.
+ Context (is_var_like : forall t, @expr (type.interp base_interp) t -> bool).
+
+ Lemma interp_subst_var_like_gen G t (e1 e2 : expr t)
+ (HG : forall t v1 v2, List.In (existT _ t (v1, v2)) G -> expr.interp interp_ident v1 == v2)
+ (Hwf : expr.wf G e1 e2)
+ : expr.interp interp_ident (SubstVarLike.subst_var_like is_var_like e1) == expr.interp interp_ident e2.
+ Proof.
+ induction Hwf; cbn [SubstVarLike.subst_var_like]; cbv [Proper respectful] in *;
+ interp_safe_t; break_innermost_match; interp_safe_t.
+ Qed.
+
+ Lemma interp_subst_var_like_gen_nil t (e1 e2 : expr t)
+ (Hwf : expr.wf nil e1 e2)
+ : expr.interp interp_ident (SubstVarLike.subst_var_like is_var_like e1) == expr.interp interp_ident e2.
+ Proof. apply interp_subst_var_like_gen with (G:=nil); cbn [In]; eauto with nocore; tauto. Qed.
+ End with_is_var_like.
+
+ Lemma Interp_SubstVarLike (is_var_like : forall var t, @expr var t -> bool)
+ {t} (e : expr.Expr t) (Hwf : expr.Wf e)
+ : expr.Interp interp_ident (SubstVarLike is_var_like e) == expr.Interp interp_ident e.
+ Proof. apply interp_subst_var_like_gen_nil, Hwf. Qed.
+
+ Lemma Interp_SubstVar {t} (e : expr.Expr t) (Hwf : expr.Wf e)
+ : expr.Interp interp_ident (SubstVar e) == expr.Interp interp_ident e.
+ Proof. apply interp_subst_var_like_gen_nil, Hwf. Qed.
+
+ Lemma Interp_SubstVarOrIdent (should_subst_ident : forall t, ident t -> bool)
+ {t} (e : expr.Expr t) (Hwf : expr.Wf e)
+ : expr.Interp interp_ident (SubstVarOrIdent should_subst_ident e) == expr.Interp interp_ident e.
+ Proof. apply interp_subst_var_like_gen_nil, Hwf. Qed.
+ End interp.
+ End with_ident.
+
+ Lemma Wf_SubstVarFstSndPairOppCast {t} (e : expr.Expr t)
+ : expr.Wf e -> expr.Wf (SubstVarLike.SubstVarFstSndPairOppCast e).
+ Proof. apply Wf_SubstVarOrIdent. Qed.
+
+ Section with_cast.
+ Context {cast_outside_of_range : ZRange.zrange -> BinInt.Z -> BinInt.Z}.
+ Local Notation ident_interp := (@ident.gen_interp cast_outside_of_range).
+ Local Notation interp := (@expr.interp _ _ _ (@ident_interp)).
+ Local Notation Interp := (@expr.Interp _ _ _ (@ident_interp)).
+
+ Lemma Interp_SubstVarFstSndPairOppCast {t} (e : expr.Expr t) (Hwf : expr.Wf e)
+ : Interp (SubstVarLike.SubstVarFstSndPairOppCast e) == Interp e.
+ Proof. apply Interp_SubstVarOrIdent, Hwf. Qed.
+ End with_cast.
+ End SubstVarLike.
+
+ Hint Resolve SubstVarLike.Wf_SubstVar SubstVarLike.Wf_SubstVarFstSndPairOppCast SubstVarLike.Wf_SubstVarLike SubstVarLike.Wf_SubstVarOrIdent : wf.
+ Hint Rewrite @SubstVarLike.Interp_SubstVar @SubstVarLike.Interp_SubstVarFstSndPairOppCast @SubstVarLike.Interp_SubstVarLike @SubstVarLike.Interp_SubstVarOrIdent : interp.
+
+ Module UnderLets.
+ Import UnderLets.Compilers.UnderLets.
+ Section with_ident.
+ Context {base_type : Type}.
+ Local Notation type := (type.type base_type).
+ Context {ident : type -> Type}.
+ Local Notation expr := (@expr.expr base_type ident).
+ Local Notation UnderLets := (@UnderLets base_type ident).
+
+ Section with_var.
+ Context {var1 var2 : type -> Type}.
+
+ Inductive wf {T1 T2} {P : list { t : type & var1 t * var2 t }%type -> T1 -> T2 -> Prop}
+ : list { t : type & var1 t * var2 t }%type -> @UnderLets var1 T1 -> @UnderLets var2 T2 -> Prop :=
+ | Wf_Base G e1 e2 : P G e1 e2 -> wf G (Base e1) (Base e2)
+ | Wf_UnderLet G A x1 x2 f1 f2
+ : expr.wf G x1 x2
+ -> (forall v1 v2, wf (existT _ A (v1, v2) :: G) (f1 v1) (f2 v2))
+ -> wf G (UnderLet x1 f1) (UnderLet x2 f2).
+ Global Arguments wf {T1 T2} P _ _ _.
+
+ Lemma wf_Proper_list_impl {T1 T2}
+ (P1 P2 : list { t : type & var1 t * var2 t }%type -> T1 -> T2 -> Prop)
+ G1 G2
+ (HP : forall seg v1 v2, P1 (seg ++ G1) v1 v2 -> P2 (seg ++ G2) v1 v2)
+ (HG1G2 : forall t v1 v2, List.In (existT _ t (v1, v2)) G1 -> List.In (existT _ t (v1, v2)) G2)
+ e1 e2
+ (Hwf : @wf T1 T2 P1 G1 e1 e2)
+ : @wf T1 T2 P2 G2 e1 e2.
+ Proof.
+ revert dependent G2; induction Hwf; constructor;
+ repeat first [ progress cbn in *
+ | progress intros
+ | solve [ eauto ]
+ | progress subst
+ | progress destruct_head'_or
+ | progress inversion_sigma
+ | progress inversion_prod
+ | match goal with H : _ |- _ => apply H; clear H end
+ | wf_unsafe_t_step
+ | eapply (HP nil)
+ | rewrite ListUtil.app_cons_app_app in * ].
+ Qed.
+
+ Lemma wf_Proper_list {T1 T2}
+ {P : list { t : type & var1 t * var2 t }%type -> T1 -> T2 -> Prop}
+ (HP : forall G1 G2,
+ (forall t v1 v2, List.In (existT _ t (v1, v2)) G1 -> List.In (existT _ t (v1, v2)) G2)
+ -> forall v1 v2, P G1 v1 v2 -> P G2 v1 v2)
+ G1 G2
+ (HG1G2 : forall t v1 v2, List.In (existT _ t (v1, v2)) G1 -> List.In (existT _ t (v1, v2)) G2)
+ e1 e2
+ (Hwf : @wf T1 T2 P G1 e1 e2)
+ : @wf T1 T2 P G2 e1 e2.
+ Proof.
+ eapply wf_Proper_list_impl; [ intros | | eassumption ]; eauto.
+ eapply HP; [ | eassumption ]; intros *.
+ rewrite !in_app_iff; intuition eauto.
+ Qed.
+
+ Lemma wf_to_expr {t} (x : @UnderLets var1 (@expr var1 t)) (y : @UnderLets var2 (@expr var2 t))
+ G
+ : wf (fun G => expr.wf G) G x y -> expr.wf G (to_expr x) (to_expr y).
+ Proof.
+ intro Hwf; induction Hwf; cbn [to_expr]; [ assumption | constructor; auto ].
+ Qed.
+
+ Lemma wf_splice {A1 B1 A2 B2}
+ {P : list { t : type & var1 t * var2 t }%type -> A1 -> A2 -> Prop}
+ {Q : list { t : type & var1 t * var2 t }%type -> B1 -> B2 -> Prop}
+ G
+ (x1 : @UnderLets var1 A1) (x2 : @UnderLets var2 A2) (Hx : @wf _ _ P G x1 x2)
+ (e1 : A1 -> @UnderLets var1 B1) (e2 : A2 -> @UnderLets var2 B2)
+ (He : forall G' a1 a2, (exists seg, G' = seg ++ G) -> P G' a1 a2 -> @wf _ _ Q G' (e1 a1) (e2 a2))
+ : @wf _ _ Q G (splice x1 e1) (splice x2 e2).
+ Proof.
+ induction Hx; cbn [splice]; [ | constructor ];
+ eauto using (ex_intro _ nil); intros.
+ match goal with H : _ |- _ => eapply H end;
+ intros; destruct_head'_ex; subst.
+ rewrite ListUtil.app_cons_app_app in *.
+ eauto using (ex_intro _ nil).
+ Qed.
+
+ Lemma wf_splice_list {A1 B1 A2 B2}
+ {P_parts : nat -> list { t : type & var1 t * var2 t }%type -> A1 -> A2 -> Prop}
+ {P : list { t : type & var1 t * var2 t }%type -> list A1 -> list A2 -> Prop}
+ {Q : list { t : type & var1 t * var2 t }%type -> B1 -> B2 -> Prop}
+ G
+ (x1 : list (@UnderLets var1 A1)) (x2 : list (@UnderLets var2 A2))
+ (P_parts_Proper_list : forall n G1 G2 a1 a2,
+ (forall t v1 v2, List.In (existT _ t (v1, v2)) G1 -> List.In (existT _ t (v1, v2)) G2)
+ -> P_parts n G1 a1 a2 -> P_parts n G2 a1 a2)
+ (HP : forall G' l1 l2,
+ (exists seg, G' = seg ++ G) -> length l1 = length x1 -> length l2 = length x2
+ -> (forall n v1 v2, nth_error l1 n = Some v1 -> nth_error l2 n = Some v2 -> P_parts n G' v1 v2)
+ -> P G' l1 l2)
+ (Hx_len : length x1 = length x2)
+ (Hx : forall n v1 v2, nth_error x1 n = Some v1 -> nth_error x2 n = Some v2 ->@wf _ _ (P_parts n) G v1 v2)
+ (e1 : list A1 -> @UnderLets var1 B1) (e2 : list A2 -> @UnderLets var2 B2)
+ (He : forall G' a1 a2, (exists seg, G' = seg ++ G) -> P G' a1 a2 -> @wf _ _ Q G' (e1 a1) (e2 a2))
+ : @wf _ _ Q G (splice_list x1 e1) (splice_list x2 e2).
+ Proof.
+ revert dependent P; revert dependent P_parts; revert dependent G; revert dependent e1; revert dependent e2; revert dependent x2;
+ induction x1 as [|x1 xs1 IHx1], x2 as [|x2 xs2];
+ cbn [splice_list length nth_error]; intros; try congruence.
+ { eapply He; [ exists nil; reflexivity | eapply HP; eauto using (ex_intro _ nil) ].
+ intros []; cbn [nth_error]; intros; congruence. }
+ { inversion Hx_len; clear Hx_len.
+ pose proof (fun n => Hx (S n)) as Hxs.
+ specialize (Hx O).
+ cbn [nth_error] in *.
+ eapply wf_splice; [ eapply Hx; reflexivity | wf_safe_t ].
+ destruct_head'_ex; subst.
+ lazymatch goal with
+ | [ |- wf _ _ (splice_list _ (fun _ => ?e1 (?a1 :: _))) (splice_list _ (fun _ => ?e2 (?a2 :: _))) ]
+ => eapply IHx1 with (P_parts:=fun n => P_parts (S n)) (P:=fun G' l1 l2 => P G' (a1::l1) (a2::l2))
+ end; wf_safe_t; destruct_head'_ex; wf_safe_t.
+ { eapply wf_Proper_list; [ | | eapply Hxs ]; wf_t. }
+ { eapply HP; cbn [length]; rewrite ?app_assoc; eauto; [].
+ intros []; cbn [nth_error]; wf_safe_t; inversion_option; wf_safe_t.
+ { eapply P_parts_Proper_list; [ | eauto ]; wf_t. }
+ { eapply P_parts_Proper_list; [ | eauto ]; wf_t. } }
+ { eapply He; eauto; rewrite ?app_assoc; eauto. } }
+ Qed.
+
+ Lemma wf_splice_list_no_order {A1 B1 A2 B2}
+ {P : list { t : type & var1 t * var2 t }%type -> A1 -> A2 -> Prop}
+ {Q : list { t : type & var1 t * var2 t }%type -> B1 -> B2 -> Prop}
+ G
+ (x1 : list (@UnderLets var1 A1)) (x2 : list (@UnderLets var2 A2))
+ (P_Proper_list : forall G1 G2 a1 a2,
+ (forall t v1 v2, List.In (existT _ t (v1, v2)) G1 -> List.In (existT _ t (v1, v2)) G2)
+ -> P G1 a1 a2 -> P G2 a1 a2)
+ (Hx_len : length x1 = length x2)
+ (Hx : forall n v1 v2, nth_error x1 n = Some v1 -> nth_error x2 n = Some v2 ->@wf _ _ P G v1 v2)
+ (e1 : list A1 -> @UnderLets var1 B1) (e2 : list A2 -> @UnderLets var2 B2)
+ (He : forall G' a1 a2, (exists seg, G' = seg ++ G)
+ -> length a1 = length x1
+ -> length a2 = length x2
+ -> (forall v1 v2, List.In (v1, v2) (combine a1 a2) -> P G' v1 v2)
+ -> @wf _ _ Q G' (e1 a1) (e2 a2))
+ : @wf _ _ Q G (splice_list x1 e1) (splice_list x2 e2).
+ Proof.
+ apply @wf_splice_list
+ with (P_parts := fun _ => P)
+ (P:=fun G' l1 l2 => length l1 = length x1 /\ length l2 = length x2
+ /\ forall v1 v2, List.In (v1, v2) (combine l1 l2) -> P G' v1 v2);
+ repeat first [ progress wf_safe_t
+ | apply conj
+ | progress inversion_option
+ | progress destruct_head'_ex
+ | progress break_innermost_match_hyps
+ | match goal with
+ | [ H : In _ (combine _ _) |- _ ] => apply ListUtil.In_nth_error_value in H
+ | [ H : context[nth_error (combine _ _) _] |- _ ]
+ => rewrite ListUtil.nth_error_combine in H
+ end ].
+ Qed.
+ End with_var.
+
+ Section for_interp.
+ Context {base_interp : base_type -> Type}
+ (ident_interp : forall t, ident t -> type.interp base_interp t).
+
+ Local Notation UnderLets := (@UnderLets (type.interp base_interp)).
+
+ Fixpoint interp {T} (v : UnderLets T) : T
+ := match v with
+ | Base v => v
+ | UnderLet A x f => let xv := expr.interp ident_interp x in
+ @interp _ (f xv)
+ end.
+
+ Fixpoint interp_related {T1 T2} (R : T1 -> T2 -> Prop) (e : UnderLets T1) (v2 : T2) : Prop
+ := match e with
+ | Base v1 => R v1 v2
+ | UnderLet t e f (* combine the App rule with the Abs rule *)
+ => exists fv ev,
+ expr.interp_related ident_interp e ev
+ /\ (forall x1 x2,
+ x1 == x2
+ -> @interp_related T1 T2 R (f x1) (fv x2))
+ /\ fv ev = v2
+ end.
+
+ Lemma interp_splice {A B} (x : UnderLets A) (e : A -> UnderLets B)
+ : interp (splice x e) = interp (e (interp x)).
+ Proof. induction x; cbn [splice interp]; eauto. Qed.
+
+ Lemma interp_splice_list {A B} (x : list (UnderLets A)) (e : list A -> UnderLets B)
+ : interp (splice_list x e)
+ = interp (e (map interp x)).
+ Proof.
+ revert e; induction x as [|x xs IHx]; intros; cbn [splice_list interp map]; [ reflexivity | ].
+ rewrite interp_splice, IHx; reflexivity.
+ Qed.
+
+ Lemma interp_to_expr {t} (x : UnderLets (expr t))
+ : expr.interp ident_interp (to_expr x) = expr.interp ident_interp (interp x).
+ Proof. induction x; cbn [expr.interp interp to_expr]; cbv [LetIn.Let_In]; eauto. Qed.
+
+ Lemma interp_of_expr {t} (x : expr t)
+ : expr.interp ident_interp (interp (of_expr x)) = expr.interp ident_interp x.
+ Proof. induction x; cbn [expr.interp interp of_expr]; cbv [LetIn.Let_In]; eauto. Qed.
+
+ Lemma to_expr_interp_related_iff {t e v}
+ : interp_related (expr.interp_related ident_interp (t:=t)) e v
+ <-> expr.interp_related ident_interp (UnderLets.to_expr e) v.
+ Proof using Type.
+ revert v; induction e; cbn [UnderLets.to_expr interp_related expr.interp_related]; try reflexivity.
+ setoid_rewrite H.
+ reflexivity.
+ Qed.
+
+ Global Instance interp_related_Proper_iff {T1 T2}
+ : Proper (pointwise_relation _ (pointwise_relation _ iff) ==> eq ==> eq ==> iff) (@interp_related T1 T2) | 10.
+ Proof using Type.
+ cbv [pointwise_relation respectful Proper].
+ intros R1 R2 HR x y ? x' y' H'; subst y y'.
+ revert x'; induction x; [ apply HR | ]; cbn [interp_related].
+ setoid_rewrite H; reflexivity.
+ Qed.
+
+ Lemma splice_interp_related_iff {A B T R x e} {v : T}
+ : interp_related R (@UnderLets.splice _ ident _ A B x e) v
+ <-> interp_related
+ (fun xv => interp_related R (e xv))
+ x v.
+ Proof using Type.
+ revert v; induction x; cbn [UnderLets.splice interp_related]; [ reflexivity | ].
+ match goal with H : _ |- _ => setoid_rewrite H end.
+ reflexivity.
+ Qed.
+
+ Lemma splice_list_interp_related_iff_gen {A B T R x e1 e2 base} {v : T}
+ (He1e2 : forall ls', e1 ls' = e2 (base ++ ls'))
+ : interp_related R (@UnderLets.splice_list _ ident _ A B x e1) v
+ <-> list_rect
+ (fun _ => list _ -> _ -> Prop)
+ (fun ls v => interp_related R (e2 ls) v)
+ (fun x xs recP ls v
+ => interp_related
+ (fun x' v => recP (ls ++ [x']) v)
+ x
+ v)
+ x
+ base
+ v.
+ Proof using Type.
+ revert base v e1 e2 He1e2; induction x as [|? ? IHx]; cbn [UnderLets.splice_list interp_related list_rect]; intros.
+ { intros; rewrite He1e2, ?app_nil_r; reflexivity. }
+ { setoid_rewrite splice_interp_related_iff.
+ apply interp_related_Proper_iff; [ | reflexivity.. ]; cbv [pointwise_relation]; intros.
+ specialize (fun v => IHx (base ++ [v])).
+ setoid_rewrite IHx; [ reflexivity | ].
+ intros; rewrite He1e2, <- ?app_assoc; reflexivity. }
+ Qed.
+
+ Lemma splice_list_interp_related_iff {A B T R x e} {v : T}
+ : interp_related R (@UnderLets.splice_list _ ident _ A B x e) v
+ <-> list_rect
+ (fun _ => list _ -> _ -> Prop)
+ (fun ls v => interp_related R (e ls) v)
+ (fun x xs recP ls v
+ => interp_related
+ (fun x' v => recP (ls ++ [x']) v)
+ x
+ v)
+ x
+ nil
+ v.
+ Proof using Type.
+ apply splice_list_interp_related_iff_gen; reflexivity.
+ Qed.
+
+ Lemma splice_interp_related_of_ex {A B T T' RA RB x e} {v : T}
+ : (exists ev (xv : T'),
+ interp_related RA x xv
+ /\ (forall x1 x2,
+ RA x1 x2
+ -> interp_related RB (e x1) (ev x2))
+ /\ ev xv = v)
+ -> interp_related RB (@UnderLets.splice _ ident _ A B x e) v.
+ Proof using Type.
+ revert e v; induction x; cbn [interp_related UnderLets.splice]; intros.
+ all: repeat first [ progress destruct_head'_ex
+ | progress destruct_head'_and
+ | progress subst
+ | reflexivity
+ | match goal with
+ | [ H : _ |- _ ] => apply H; clear H
+ end ].
+ do 2 eexists; repeat apply conj; [ eassumption | | ]; intros.
+ { match goal with H : _ |- _ => apply H; clear H end.
+ do 2 eexists; repeat apply conj; now eauto. }
+ { reflexivity. }
+ Qed.
+
+ Lemma splice_list_interp_related_of_ex {A B T T' RA RB x e} {v : T}
+ : (exists ev (xv : list T'),
+ List.Forall2 (interp_related RA) x xv
+ /\ (forall x1 x2,
+ List.length x2 = List.length xv
+ -> List.Forall2 RA x1 x2
+ -> interp_related RB (e x1) (ev x2))
+ /\ ev xv = v)
+ -> interp_related RB (@UnderLets.splice_list _ ident _ A B x e) v.
+ Proof using Type.
+ revert e v; induction x as [|x xs IHxs]; cbn [interp_related UnderLets.splice_list]; intros.
+ all: repeat first [ progress destruct_head'_ex
+ | progress destruct_head'_and
+ | progress cbn [List.length] in *
+ | progress subst
+ | reflexivity
+ | match goal with
+ | [ H : List.Forall2 _ nil ?x |- _ ] => is_var x; inversion H; clear H
+ | [ H : List.Forall2 _ (cons _ _) ?x |- _ ] => is_var x; inversion H; clear H
+ | [ |- List.Forall2 _ _ _ ] => constructor
+ | [ H : _ |- _ ] => apply H; clear H
+ end ].
+ lazymatch goal with
+ | [ H : forall l1 l2, length l2 = S (length _) -> Forall2 _ l1 l2 -> _ |- _ ]
+ => specialize (fun l ls l' ls' (pf0 : length _ = _) pf1 pf2 => H (cons l ls) (cons l' ls') (f_equal S pf0) (Forall2_cons _ _ pf1 pf2))
+ end.
+ eapply splice_interp_related_of_ex; do 2 eexists; repeat apply conj;
+ intros; [ eassumption | | ].
+ { eapply IHxs.
+ do 2 eexists; repeat apply conj; intros;
+ [ eassumption | | ].
+ { match goal with H : _ |- _ => eapply H; clear H end; eassumption. }
+ { reflexivity. } }
+ { reflexivity. }
+ Qed.
+
+ Lemma list_rect_interp_related {A B Pnil Pcons ls B' Pnil' Pcons' ls' R}
+ (Hnil : interp_related R Pnil Pnil')
+ (Hcons : forall x x',
+ expr.interp_related ident_interp x x'
+ -> forall l l',
+ List.Forall2 (expr.interp_related ident_interp) l l'
+ -> forall rec rec',
+ interp_related R rec rec'
+ -> interp_related R (Pcons x l rec) (Pcons' x' l' rec'))
+ (Hls : List.Forall2 (expr.interp_related ident_interp (t:=A)) ls ls')
+ : interp_related
+ R
+ (list_rect
+ (fun _ : list _ => UnderLets B)
+ Pnil
+ Pcons
+ ls)
+ (list_rect
+ (fun _ : list _ => B')
+ Pnil'
+ Pcons'
+ ls').
+ Proof using Type. induction Hls; cbn [list_rect] in *; auto. Qed.
+
+ Lemma nat_rect_interp_related {A PO PS n A' PO' PS' n' R}
+ (Hnil : interp_related R PO PO')
+ (Hcons : forall n rec rec',
+ interp_related R rec rec'
+ -> interp_related R (PS n rec) (PS' n rec'))
+ (Hn : n = n')
+ : interp_related
+ R
+ (nat_rect (fun _ => UnderLets A) PO PS n)
+ (nat_rect (fun _ => A') PO' PS' n').
+ Proof using Type. subst n'; induction n; cbn [nat_rect] in *; auto. Qed.
+
+ Lemma nat_rect_arrow_interp_related {A B PO PS n x A' B' PO' PS' n' x' R}
+ {R' : A -> A' -> Prop}
+ (Hnil : forall x x', R' x x' -> interp_related R (PO x) (PO' x'))
+ (Hcons : forall n rec rec',
+ (forall x x', R' x x' -> interp_related R (rec x) (rec' x'))
+ -> forall x x',
+ R' x x'
+ -> interp_related R (PS n rec x) (PS' n rec' x'))
+ (Hn : n = n')
+ (Hx : R' x x')
+ : interp_related
+ R
+ (nat_rect (fun _ => A -> UnderLets B) PO PS n x)
+ (nat_rect (fun _ => A' -> B') PO' PS' n' x').
+ Proof using Type. subst n'; revert x x' Hx; induction n; cbn [nat_rect] in *; auto. Qed.
+
+ Lemma interp_related_Proper_impl_same_UnderLets {A B B' R1 R2 e v f}
+ (HR : forall e v, (R1 e v : Prop) -> (R2 e (f v) : Prop))
+ : @interp_related A B R1 e v
+ -> @interp_related A B' R2 e (f v).
+ Proof using Type.
+ revert f v HR; induction e; cbn [interp_related]; [ now eauto | ]; intros F v HR H'.
+ destruct H' as [fv H']; exists (fun ev => F (fv ev)).
+ repeat first [ let x := fresh "x" in destruct H' as [x H']; exists x
+ | let x := fresh "x" in intro x; specialize (H' x)
+ | let H := fresh "H" in destruct H' as [H H']; split; [ exact H || now subst | ]
+ | let H := fresh "H" in destruct H' as [H' H]; split; [ | exact H || now subst ] ].
+ auto.
+ Qed.
+ End for_interp.
+
+ Section for_interp2.
+ Context {base_interp1 base_interp2 : base_type -> Type}
+ {ident_interp1 : forall t, ident t -> type.interp base_interp1 t}
+ {ident_interp2 : forall t, ident t -> type.interp base_interp2 t}.
+
+ Lemma wf_interp_Proper {T1 T2}
+ {P : list { t : type & type.interp base_interp1 t * type.interp base_interp2 t }%type -> T1 -> T2 -> Prop}
+ {G v1 v2}
+ (Hwf : @wf _ _ T1 T2 P G v1 v2)
+ : exists seg, P (seg ++ G) (interp ident_interp1 v1) (interp ident_interp2 v2).
+ Proof using Type.
+ induction Hwf; [ exists nil; cbn [List.app]; assumption | ].
+ let H := match goal with H : forall v1 v2, ex _ |- _ => H end in
+ edestruct H as [seg ?]; eexists (seg ++ [_]).
+ rewrite <- List.app_assoc; cbn [List.app].
+ eassumption.
+ Qed.
+ End for_interp2.
+ End with_ident.
+
+ Section reify.
+ Local Notation type := (type.type base.type).
+ Local Notation expr := (@expr.expr base.type ident).
+ Local Notation UnderLets := (@UnderLets.UnderLets base.type ident).
+
+ Section with_var.
+ Context {var1 var2 : type -> Type}.
+ Local Notation expr1 := (@expr.expr base.type ident var1).
+ Local Notation expr2 := (@expr.expr base.type ident var2).
+ Local Notation UnderLets1 := (@UnderLets.UnderLets base.type ident var1).
+ Local Notation UnderLets2 := (@UnderLets.UnderLets base.type ident var2).
+
+ Local Ltac wf_reify_and_let_binds_base_cps_t Hk :=
+ repeat first [ lazymatch goal with
+ | [ H : expr.wf _ ?e1 ?e2, H' : reflect_list ?e1 = Some _, H'' : reflect_list ?e2 = None |- _ ]
+ => apply expr.wf_reflect_list in H; rewrite H', H'' in H; exfalso; clear -H; intuition congruence
+ | [ H : expr.wf _ ?e1 ?e2, H' : reflect_list ?e2 = Some _, H'' : reflect_list ?e1 = None |- _ ]
+ => apply expr.wf_reflect_list in H; rewrite H', H'' in H; exfalso; clear -H; intuition congruence
+ | [ H : expr.wf _ (reify_list _) (reify_list _) |- _ ] => apply expr.wf_reify_list in H
+ end
+ | progress subst
+ | progress destruct_head' False
+ | progress expr.inversion_wf_constr
+ | progress expr.inversion_expr
+ | progress expr.invert_subst
+ | progress destruct_head'_sig
+ | progress destruct_head'_ex
+ | progress destruct_head'_and
+ | progress type.inversion_type
+ | progress base.type.inversion_type
+ | progress cbn [invert_Var invert_Literal ident.invert_Literal eq_rect f_equal f_equal2 type.decode fst snd projT1 projT2 invert_pair Option.bind combine list_rect length] in *
+ | progress cbv [type.try_transport type.try_transport_cps CPSNotations.cps_option_bind CPSNotations.cpsreturn CPSNotations.cpsbind CPSNotations.cpscall type.try_make_transport_cps id] in *
+ | rewrite base.try_make_transport_cps_correct in *
+ | progress type_beq_to_eq
+ | discriminate
+ | congruence
+ | apply Hk
+ | exists nil; reflexivity
+ | eexists (cons _ nil); reflexivity
+ | rewrite app_assoc; eexists; reflexivity
+ | progress wf_safe_t
+ | match goal with
+ | [ H : _ = _ :> ident _ |- _ ] => inversion H; clear H
+ end
+ | progress inversion_option
+ | progress break_innermost_match_hyps
+ | progress expr.inversion_wf_one_constr
+ | progress expr.invert_match_step
+ | match goal with |- wf _ _ _ _ => constructor end
+ | match goal with
+ | [ H : context[wf _ _ _ _] |- wf _ _ _ _ ] => apply H; eauto with nocore
+ end
+ | progress wf_unsafe_t_step
+ | match goal with
+ | [ H : context[match Compilers.reify_list ?ls with _ => _ end] |- _ ]
+ => is_var ls; destruct ls; rewrite ?expr.reify_list_cons, ?expr.reify_list_nil in H
+ | [ H : SubstVarLike.is_recursively_var_or_ident _ _ = _ |- _ ] => clear H
+ | [ H : forall x y, @?A x y \/ @?B x y -> @?C x y |- _ ]
+ => pose proof (fun x y pf => H x y (or_introl pf));
+ pose proof (fun x y pf => H x y (or_intror pf));
+ clear H
+ end ].
+
+ Lemma wf_reify_and_let_binds_base_cps {t : base.type} {T1 T2} (e1 : expr1 (type.base t)) (e2 : expr2 (type.base t))
+ (k1 : expr1 (type.base t) -> UnderLets1 T1) (k2 : expr2 (type.base t) -> UnderLets2 T2)
+ (P : _ -> _ -> _ -> Prop) G
+ (Hwf : expr.wf G e1 e2)
+ (Hk : forall G' e1 e2, (exists seg, G' = seg ++ G) -> expr.wf G' e1 e2 -> wf P G' (k1 e1) (k2 e2))
+ : wf P G (reify_and_let_binds_base_cps e1 T1 k1) (reify_and_let_binds_base_cps e2 T2 k2).
+ Proof.
+ revert dependent G; induction t; cbn [reify_and_let_binds_base_cps]; intros;
+ try (cbv [SubstVarLike.is_var_fst_snd_pair_opp_cast] in *; erewrite !SubstVarLike.wfT_is_recursively_var_or_ident by eassumption);
+ break_innermost_match; wf_reify_and_let_binds_base_cps_t Hk.
+ all: repeat match goal with H : list (sigT _) |- _ => revert dependent H end.
+ all: revert dependent k1; revert dependent k2.
+ all: lazymatch goal with
+ | [ H : length ?l1 = length ?l2 |- _ ]
+ => is_var l1; is_var l2; revert dependent l2; induction l1; intro l2; destruct l2; intros
+ end;
+ wf_reify_and_let_binds_base_cps_t Hk.
+ Qed.
+
+ Lemma wf_let_bind_return {t} (e1 : expr1 t) (e2 : expr2 t)
+ G
+ (Hwf : expr.wf G e1 e2)
+ : expr.wf G (let_bind_return e1) (let_bind_return e2).
+ Proof.
+ revert dependent G; induction t; intros; cbn [let_bind_return]; cbv [invert_Abs];
+ wf_safe_t;
+ expr.invert_match; expr.inversion_wf; try solve [ wf_t ].
+ { apply wf_to_expr.
+ pose (P := fun t => { e1e2 : expr1 t * expr2 t | expr.wf G (fst e1e2) (snd e1e2) }).
+ pose ((exist _ (e1, e2) Hwf) : P _) as pkg.
+ change e1 with (fst (proj1_sig pkg)).
+ change e2 with (snd (proj1_sig pkg)).
+ clearbody pkg; clear Hwf e1 e2.
+ type.generalize_one_eq_var pkg; subst P; destruct pkg as [ [e1 e2] Hwf ].
+ cbn [fst snd proj1_sig proj2_sig] in *.
+ repeat match goal with
+ | [ |- context[proj1_sig (rew [fun t => @sig (@?A t) (@?P t)] ?pf in exist ?P0 ?x ?p)] ]
+ => progress replace (proj1_sig (rew pf in exist P0 x p)) with (rew [A] pf in x) by (case pf; reflexivity)
+ | [ |- context[fst (rew [fun t => @prod (@?A t) (@?B t)] ?pf in pair ?x ?y)] ]
+ => progress replace (fst (rew pf in pair x y)) with (rew [A] pf in x) by (case pf; reflexivity)
+ | [ |- context[snd (rew [fun t => @prod (@?A t) (@?B t)] ?pf in pair ?x ?y)] ]
+ => progress replace (fst (rew pf in pair x y)) with (rew [B] pf in y) by (case pf; reflexivity)
+ end.
+ assert (H' : t = match t' with type.base t' => t' | _ => t end) by (subst; reflexivity).
+ revert pf.
+ rewrite H'; clear H'.
+ induction Hwf; break_innermost_match; break_innermost_match_hyps;
+ repeat first [ progress intros
+ | progress type.inversion_type
+ | progress base.type.inversion_type
+ | progress wf_safe_t
+ | progress cbn [of_expr fst snd splice eq_rect type.decode f_equal] in *
+ | match goal with
+ | [ H : forall pf : ?x = ?x, _ |- _ ] => specialize (H eq_refl)
+ | [ H : forall x y (pf : ?a = ?a), _ |- _ ] => specialize (fun x y => H x y eq_refl)
+ | [ |- wf _ _ _ _ ] => constructor
+ end
+ | solve [ eauto ]
+ | apply wf_reify_and_let_binds_base_cps ]. }
+ Qed.
+ End with_var.
+
+ Section with_cast.
+ Context (cast_outside_of_range : ZRange.zrange -> BinInt.Z -> BinInt.Z).
+ Local Notation ident_interp := (@ident.gen_interp cast_outside_of_range).
+ Local Notation interp := (@expr.interp _ _ _ (@ident_interp)).
+ Local Notation Interp := (@expr.Interp _ _ _ (@ident_interp)).
+
+ Lemma interp_reify_and_let_binds_base_cps
+ {t e T k}
+ (P : T -> Prop)
+ (Hk : forall e', interp e' = interp e -> P (UnderLets.interp (@ident_interp) (k e')))
+ : P (UnderLets.interp (@ident_interp) (@reify_and_let_binds_base_cps _ t e T k)).
+ Proof.
+ revert T k P Hk; induction t; cbn [reify_and_let_binds_base_cps]; intros;
+ break_innermost_match;
+ expr.invert_subst; cbn [type.related UnderLets.interp fst snd expr.interp ident_interp] in *; subst; eauto;
+ repeat first [ progress intros
+ | reflexivity
+ | progress cbn [expr.interp ident_interp List.map]
+ | apply (f_equal2 (@pair _ _))
+ | apply (f_equal2 (@cons _))
+ | match goal with
+ | [ H : _ |- _ ] => apply H; clear H
+ | [ H : SubstVarLike.is_var_fst_snd_pair_opp_cast (reify_list _) = _ |- _ ] => clear H
+ | [ H : context[interp (reify_list _)] |- _ ]
+ => rewrite expr.interp_reify_list in H
+ | [ |- ?Q (UnderLets.interp _ (list_rect ?P ?X ?Y ?ls ?k)) ]
+ => is_var ls; is_var k;
+ revert dependent k; induction ls; cbn [list_rect];
+ [ | generalize dependent (list_rect P X Y) ]; intros
+ end ].
+ Qed.
+
+ Lemma interp_reify_and_let_binds_base
+ {t e}
+ : interp (UnderLets.interp (@ident_interp) (@reify_and_let_binds_base_cps _ t e _ UnderLets.Base))
+ = interp e.
+ Proof.
+ eapply interp_reify_and_let_binds_base_cps; cbn [UnderLets.interp].
+ trivial.
+ Qed.
+
+ Local Ltac interp_to_expr_reify_and_let_binds_base_cps_t Hk :=
+ repeat first [ progress subst
+ | progress destruct_head' False
+ | progress destruct_head'_and
+ | progress destruct_head' iff
+ | progress specialize_by_assumption
+ | progress expr.inversion_wf_constr
+ | progress expr.inversion_expr
+ | progress expr.invert_subst
+ | progress destruct_head'_sig
+ | progress destruct_head'_ex
+ | progress destruct_head'_and
+ | progress type.inversion_type
+ | progress base.type.inversion_type
+ | progress cbn [invert_Var invert_Literal ident.invert_Literal eq_rect f_equal f_equal2 type.decode fst snd projT1 projT2 invert_pair Option.bind to_expr expr.interp ident.interp ident.gen_interp type.eqv length list_rect combine In] in *
+ | progress cbv [type.try_transport type.try_transport_cps CPSNotations.cps_option_bind CPSNotations.cpsreturn CPSNotations.cpsbind CPSNotations.cpscall type.try_make_transport_cps id] in *
+ | rewrite base.try_make_transport_cps_correct in *
+ | progress type_beq_to_eq
+ | discriminate
+ | congruence
+ | apply Hk
+ | exists nil; reflexivity
+ | eexists (cons _ nil); reflexivity
+ | rewrite app_assoc; eexists; reflexivity
+ | rewrite expr.reify_list_cons
+ | rewrite expr.reify_list_nil
+ | progress interp_safe_t
+ | match goal with
+ | [ H : _ = _ :> ident _ |- _ ] => inversion H; clear H
+ | [ H : forall t v1 v2, In _ _ -> _ == _, H' : In _ _ |- _ ] => apply H in H'
+ end
+ | progress inversion_option
+ | progress break_innermost_match_hyps
+ | progress expr.inversion_wf_one_constr
+ | progress expr.invert_match_step
+ | match goal with
+ | [ |- ?R (expr.interp _ ?e1) (expr.interp _ ?e2) ]
+ => solve [ eapply (@expr.wf_interp_Proper _ _ _ e1 e2); eauto ]
+ | [ H : context[reflect_list (reify_list _)] |- _ ] => rewrite expr.reflect_reify_list in H
+ | [ H : forall x y, @?A x y \/ @?B x y -> @?C x y |- _ ]
+ => pose proof (fun x y pf => H x y (or_introl pf));
+ pose proof (fun x y pf => H x y (or_intror pf));
+ clear H
+ end
+ | progress interp_unsafe_t_step
+ | match goal with
+ | [ H : expr.wf _ (reify_list _) ?e |- _ ]
+ => is_var e; destruct (reflect_list e) eqn:?; expr.invert_subst;
+ [ rewrite expr.wf_reify_list in H | apply expr.wf_reflect_list in H ]
+ | [ H : SubstVarLike.is_recursively_var_or_ident _ _ = _ |- _ ] => clear H
+ | [ H : context[expr.interp _ _ = _] |- expr.interp _ (to_expr _) = ?k2 _ ]
+ => erewrite H; clear H;
+ [ match goal with
+ | [ |- ?k (expr.interp ?ii ?e) = ?k' ?v ]
+ => has_evar e;
+ let p := fresh in
+ set (p := expr.interp ii e);
+ match v with
+ | context G[expr.interp ii ?e']
+ => unify e e'; let v' := context G[p] in change (k p = k' v')
+ end;
+ clearbody p; reflexivity
+ end
+ | .. ]
+ end ].
+
+ Lemma interp_to_expr_reify_and_let_binds_base_cps {t : base.type} {t' : base.type} (e1 : expr (type.base t)) (e2 : expr (type.base t))
+ G
+ (HG : forall t v1 v2, List.In (existT _ t (v1, v2)) G -> v1 == v2)
+ (Hwf : expr.wf G e1 e2)
+ (k1 : expr (type.base t) -> UnderLets _ (expr (type.base t')))
+ (k2 : base.interp t -> base.interp t')
+ (Hk : forall e1 v, interp e1 == v -> interp (to_expr (k1 e1)) == k2 v)
+ : interp (to_expr (reify_and_let_binds_base_cps e1 _ k1)) == k2 (interp e2).
+ Proof.
+ revert dependent G; revert dependent t'; induction t; cbn [reify_and_let_binds_base_cps]; intros;
+ try (cbv [SubstVarLike.is_var_fst_snd_pair_opp_cast] in *; erewrite !SubstVarLike.wfT_is_recursively_var_or_ident by eassumption);
+ break_innermost_match; interp_to_expr_reify_and_let_binds_base_cps_t Hk.
+ all: repeat match goal with H : list (sigT _) |- _ => revert dependent H end.
+ all: revert dependent k1; revert dependent k2.
+ all: lazymatch goal with
+ | [ H : length ?l1 = length ?l2 |- _ ]
+ => is_var l1; is_var l2; revert dependent l2; induction l1; intro l2; destruct l2; intros
+ end;
+ interp_to_expr_reify_and_let_binds_base_cps_t Hk.
+ Qed.
+
+ Lemma interp_let_bind_return {t} (e1 e2 : expr t)
+ G
+ (HG : forall t v1 v2, List.In (existT _ t (v1, v2)) G -> v1 == v2)
+ (Hwf : expr.wf G e1 e2)
+ : interp (let_bind_return e1) == interp e2.
+ Proof.
+ revert dependent G; induction t; intros; cbn [let_bind_return type.eqv expr.interp] in *; cbv [invert_Abs respectful] in *;
+ repeat first [ progress wf_safe_t
+ | progress expr.invert_subst
+ | progress expr.invert_match
+ | progress expr.inversion_wf
+ | progress break_innermost_match_hyps
+ | progress destruct_head' False
+ | solve [ wf_t ]
+ | match goal with
+ | [ H : _ |- expr.interp _ (let_bind_return ?e0) == expr.interp _ ?e ?v ]
+ => eapply (H e0 (e @ $v)%expr (cons _ _)); [ .. | solve [ wf_t ] ]; solve [ wf_t ]
+ | [ H : _ |- expr.interp _ (let_bind_return ?e0) == expr.interp _ ?e ?v ]
+ => cbn [expr.interp]; eapply H; [ | solve [ wf_t ] ]; solve [ wf_t ]
+ end ];
+ [].
+ { pose (P := fun t => { e1e2 : expr t * expr t | expr.wf G (fst e1e2) (snd e1e2) }).
+ pose ((exist _ (e1, e2) Hwf) : P _) as pkg.
+ change e1 with (fst (proj1_sig pkg)).
+ change e2 with (snd (proj1_sig pkg)).
+ clearbody pkg; clear Hwf e1 e2.
+ type.generalize_one_eq_var pkg; subst P; destruct pkg as [ [e1 e2] Hwf ].
+ cbn [fst snd proj1_sig proj2_sig] in *.
+ repeat match goal with
+ | [ |- context[proj1_sig (rew [fun t => @sig (@?A t) (@?P t)] ?pf in exist ?P0 ?x ?p)] ]
+ => progress replace (proj1_sig (rew pf in exist P0 x p)) with (rew [A] pf in x) by (case pf; reflexivity)
+ | [ |- context[fst (rew [fun t => @prod (@?A t) (@?B t)] ?pf in pair ?x ?y)] ]
+ => progress replace (fst (rew pf in pair x y)) with (rew [A] pf in x) by (case pf; reflexivity)
+ | [ |- context[snd (rew [fun t => @prod (@?A t) (@?B t)] ?pf in pair ?x ?y)] ]
+ => progress replace (fst (rew pf in pair x y)) with (rew [B] pf in y) by (case pf; reflexivity)
+ end.
+ assert (H' : t = match t' with type.base t' => t' | _ => t end) by (subst; reflexivity).
+ revert pf.
+ rewrite H'; clear H'.
+ induction Hwf; break_innermost_match; break_innermost_match_hyps;
+ repeat first [ progress intros
+ | progress type.inversion_type
+ | progress base.type.inversion_type
+ | progress wf_safe_t
+ | progress cbn [of_expr fst snd splice eq_rect type.decode f_equal to_expr] in *
+ | match goal with
+ | [ H : forall pf : ?x = ?x, _ |- _ ] => specialize (H eq_refl)
+ | [ H : forall x (pf : ?a = ?a), _ |- _ ] => specialize (fun x => H x eq_refl)
+ | [ H : forall x y (pf : ?a = ?a), _ |- _ ] => specialize (fun x y => H x y eq_refl)
+ | [ H : forall x y z (pf : ?a = ?a), _ |- _ ] => specialize (fun x y z => H x y z eq_refl)
+ | [ |- context[(expr_let x := _ in _)%expr] ] => progress cbn [expr.interp]; cbv [LetIn.Let_In]
+ | [ H : context[expr.interp _ _ = expr.interp _ _] |- expr.interp _ _ = expr.interp _ _ ]
+ => eapply H; eauto with nocore
+ end
+ | solve [ eauto ]
+ | solve [ eapply expr.wf_interp_Proper; eauto ] ].
+ all: eapply interp_to_expr_reify_and_let_binds_base_cps with (k1:=Base) (k2:=(fun x => x)); eauto; wf_safe_t. }
+ Qed.
+
+ Ltac recurse_interp_related_step :=
+ let do_replace v :=
+ ((tryif is_evar v then fail else idtac);
+ let v' := open_constr:(_) in
+ let v'' := fresh in
+ cut (v = v'); [ generalize v; intros v'' ?; subst v'' | symmetry ]) in
+ match goal with
+ | _ => progress cbv [expr.interp_related] in *
+ | _ => progress cbn [type.interp]
+ | [ |- context[(fst ?x, snd ?x)] ] => progress eta_expand
+ | [ |- context[match ?x with pair a b => _ end] ] => progress eta_expand
+ | [ |- expr.interp_related_gen ?ident_interp ?R ?f ?v ]
+ => do_replace v
+ | [ |- exists (fv : ?T1 -> ?T2) (ev : ?T1),
+ _ /\ _ /\ fv ev = ?x ]
+ => first [ do_replace x
+ | is_evar x; do 2 eexists; repeat apply conj; [ | | reflexivity ] ]
+ | _ => progress intros
+ | [ |- expr.interp_related_gen _ _ _ ?ev ] => is_evar ev; eassumption
+ | [ |- expr.interp_related_gen _ _ (?f @ ?x) ?ev ]
+ => is_evar ev;
+ let fh := fresh in
+ let xh := fresh in
+ set (fh := f); set (xh := x); cbn [expr.interp_related_gen]; subst fh xh;
+ do 2 eexists; repeat apply conj; [ | | reflexivity ]
+ | [ |- expr.interp_related_gen _ _ (expr.Abs ?f) _ ]
+ => let fh := fresh in set (fh := f); cbn [expr.interp_related_gen]; subst fh
+ | [ |- expr.interp_related_gen _ _ (expr.Ident ?idc) ?ev ]
+ => is_evar ev;
+ cbn [expr.interp_related_gen]; apply ident.gen_interp_Proper; reflexivity
+ | [ H : ?x == _ |- ?x == _ ] => exact H
+ | [ |- ?x = ?y ] => tryif first [ has_evar x | has_evar y ] then fail else (progress subst)
+ | [ |- ?x = ?x ] => tryif has_evar x then fail else reflexivity
+ | [ |- ?ev = _ ] => is_evar ev; reflexivity
+ | [ |- _ = ?ev ] => is_evar ev; reflexivity
+ end.
+
+ Local Ltac do_interp_related :=
+ repeat first [ progress cbv beta
+ | progress recurse_interp_related_step
+ | eassumption
+ | do 2 eexists; repeat apply conj; intros
+ | match goal with
+ | [ H : _ |- _ ] => apply H; clear H; solve [ do_interp_related ]
+ end ].
+
+ Lemma reify_and_let_binds_base_interp_related_of_ex {t e T k T' R} {v : T'}
+ : (exists kv xv,
+ expr.interp_related (@ident_interp) e xv
+ /\ (forall x1 x2,
+ expr.interp_related (@ident_interp) x1 x2
+ -> interp_related (@ident_interp) R (k x1) (kv x2))
+ /\ kv xv = v)
+ -> interp_related (@ident_interp) R (@reify_and_let_binds_base_cps _ t e T k) v.
+ Proof using Type.
+ cbv [expr.interp_related]; revert T T' k R v; induction t.
+ all: repeat first [ progress cbn [expr.interp_related_gen interp_related reify_and_let_binds_base_cps fst snd] in *
+ | progress cbv [expr.interp_related] in *
+ | progress intros
+ | assumption
+ | progress destruct_head'_ex
+ | progress destruct_head'_and
+ | break_innermost_match_step
+ | progress expr.invert_subst
+ | solve [ eauto ]
+ | solve [ do_interp_related ]
+ | match goal with
+ | [ H : expr.interp_related_gen ?ii _ (reify_list ?ls1) ?ls2 |- _ ] => change (expr.interp_related ii (reify_list ls1) ls2) in H; rewrite expr.reify_list_interp_related_iff in H
+ end ].
+ all: match goal with
+ | [ H : SubstVarLike.is_var_fst_snd_pair_opp_cast _ = _ |- _ ] => clear H
+ end.
+ all: lazymatch goal with
+ | [ H : List.Forall2 _ ?ls1 ?ls2
+ |- interp_related _ _
+ (list_rect ?Pv ?Nv ?Cv ?ls1 ?k)
+ (?f ?ls2) ]
+ => let P := fresh "P" in
+ let N := fresh "N" in
+ let C := fresh "C" in
+ is_var k; is_var f; is_var ls1; is_var ls2;
+ set (P:=Pv); set (N:=Nv); set (C:=Cv);
+ revert dependent f; intro f; revert dependent k; intro k; revert f k;
+ induction H; cbn [list_rect]; intros
+ end.
+ all: repeat match goal with
+ | [ F := ?f |- _ ]
+ => match goal with
+ | [ |- context G[F ?x] ]
+ => let G' := context G[f x] in
+ change G'; cbv beta
+ end
+ | [ H : forall x1 x2, ?R x1 x2 -> ?R' (?f1 x1) (?f2 x2) |- ?R' (?f1 _) (?f2 _) ]
+ => apply H; clear H
+ | [ |- expr.interp_related_gen _ _ _ nil ] => reflexivity
+ | [ H : _ |- interp_related _ _ (reify_and_let_binds_base_cps _ _ _) _ ] => apply H
+ | [ |- exists kv xv, _ /\ _ /\ kv xv = ?f (?x :: ?xs) ]
+ => exists (fun x' => f (x' :: xs)), x; repeat apply conj; [ | | reflexivity ]
+ | _ => assumption
+ | _ => progress intros
+ | [ IH : (forall k k', _ -> ?R (list_rect ?P ?N ?C ?ls1 k') (k ?ls2))
+ |- ?R (list_rect ?P ?N ?C ?ls1 ?k'v) ?RHS ]
+ => let kv := match (eval pattern ls2 in RHS) with ?kv _ => kv end in
+ apply (IH kv k'v); clear IH
+ | _ => solve [ do_interp_related ]
+ end.
+ Qed.
+
+ Lemma reify_and_let_binds_base_interp_related {t e v}
+ : expr.interp_related (@ident_interp) e v
+ -> interp_related (@ident_interp) (expr.interp_related (@ident_interp)) (@reify_and_let_binds_base_cps _ t e _ Base) v.
+ Proof using Type.
+ intro; eapply reify_and_let_binds_base_interp_related_of_ex.
+ eexists id, _; eauto.
+ Qed.
+
+ Lemma Interp_LetBindReturn {t} (e : expr.Expr t) (Hwf : expr.Wf e) : Interp (LetBindReturn e) == Interp e.
+ Proof.
+ apply interp_let_bind_return with (G:=nil); cbn [List.In]; eauto; tauto.
+ Qed.
+ End with_cast.
+
+ Lemma Wf_LetBindReturn {t} (e : expr.Expr t) (Hwf : expr.Wf e) : expr.Wf (LetBindReturn e).
+ Proof. intros ??; apply wf_let_bind_return, Hwf. Qed.
+ End reify.
+ End UnderLets.
+
+ Hint Resolve UnderLets.Wf_LetBindReturn : wf.
+ Hint Rewrite @UnderLets.Interp_LetBindReturn : interp.
+End Compilers.