Library MetaRocq.Erasure.ErasureProperties

(* Distributed under the terms of the MIT license. *)
From Stdlib Require Import Program ssreflect ssrbool.
From MetaRocq.Utils Require Import utils.
From MetaRocq.Common Require Import config.
From MetaRocq.Erasure Require Import EPrimitive ELiftSubst EGlobalEnv EWcbvEval Extract Prelim
     ESubstitution EArities EDeps.
From MetaRocq.PCUIC Require Import PCUICTyping PCUICGlobalEnv PCUICAst
  PCUICAstUtils PCUICConversion PCUICSigmaCalculus
  PCUICClosed PCUICClosedTyp
  PCUICWeakeningEnv PCUICWeakeningEnvTyp
  PCUICWeakeningConv PCUICWeakeningTyp PCUICSubstitution PCUICArities
  PCUICWcbvEval PCUICSR PCUICInversion
  PCUICLiftSubst
  PCUICUnivSubstitutionConv PCUICUnivSubstitutionTyp
  PCUICElimination PCUICCanonicity
  PCUICUnivSubst PCUICViews
  PCUICCumulativity PCUICSafeLemmata
  PCUICArities PCUICInductiveInversion
  PCUICContextConversion PCUICContextConversionTyp
  PCUICOnFreeVars PCUICWellScopedCumulativity PCUICValidity
  PCUICContexts PCUICEquality PCUICSpine
  PCUICInductives.
From MetaRocq.PCUIC Require Import PCUICTactics.

From Equations.Prop Require Import DepElim.

Local Set Keyed Unification.

Local Existing Instance config.extraction_checker_flags.

(* Properties of PCUIC *)

Lemma isLambda_subst_instance t u : isLambda t isLambda t@[u].
Proof. destruct t ⇒ //. Qed.

Lemma wf_local_rel_conv:
   Σ : global_env × universes_decl,
    wf Σ.1
     Γ Γ' : context,
      All2_fold (conv_decls cumulAlgo_gen Σ) Γ Γ'
       Γ0 : context, wf_local Σ Γ' wf_local_rel Σ Γ Γ0 wf_local_rel Σ Γ' Γ0.
Proof.
  intros Σ wfΣ Γ Γ' Γ0 ? .
  apply All_local_env_impl_ind with (1 := ) ⇒ Δ j wfΓ' Hj.
  apply lift_typing_impl with (1 := Hj) ⇒ t T HT.
  eapply context_conversion with (Γ ,,, Δ); eauto.
  - eapply All_local_env_app; eauto.
  - eapply conv_context_app_same; eauto.
Qed.


Lemma conv_context_wf_local_app {A B A'} {Σ : global_env_ext} {wfΣ : wf Σ} :
  wf_local Σ (A ,,, B) wf_local Σ A' conv_context cumulAlgo_gen Σ A A' wf_local Σ (A' ,,, B).
Proof.
  intros wfab wfa' cv.
  eapply All_local_env_app ⇒ //.
  eapply wf_local_rel_conv; tea.
  now eapply All_local_env_app_inv.
Qed.


Lemma type_closed_subst {Σ t T} u : wf_ext Σ
  Σ ;;; [] t : T
   t 0 u = PCUICCSubst.csubst t 0 u.
Proof.
  intros wfΣ tc.
  apply subject_closed in tc; auto.
  rewrite PCUICCSubst.closed_subst; auto.
Qed.


Generic Properties of erasure
Lemma erases_ext_eq Σ Σ' Γ Γ' t1 t1' t2 t2' :
  Σ ;;; Γ
  Σ = Σ' Γ = Γ' = =
  Σ' ;;; Γ' .
Proof.
  intros. now subst.
Qed.


Erasure and applications


Lemma erases_App (Σ : global_env_ext) Γ f L t :
  erases Σ Γ (tApp f L) t
  (t = EAst.tBox × squash (isErasable Σ Γ (tApp f L)))
   f' L', t = EAst.tApp f' L'
            erases Σ Γ f f'
            erases Σ Γ L L'.
Proof.
  intros. generalize_eqs H.
  revert f L.
  inversion H; intros; try congruence; subst.
  - invs . right. repeat eexists; eauto.
  - left. split; eauto. now sq.
Qed.


Lemma erases_mkApps (Σ : global_env_ext) Γ f f' L L' :
  erases Σ Γ f f'
   (erases Σ Γ) L L'
  erases Σ Γ (mkApps f L) (EAst.mkApps f' L').
Proof.
  intros. revert f f' H; induction ; cbn; intros; eauto.
  eapply . econstructor. eauto. eauto.
Qed.


Lemma erases_mkApps_inv (Σ : global_env_ext) Γ f L t :
  Σ;;; Γ mkApps f L t
  ( L1 L2 L2', L =
                squash (isErasable Σ Γ (mkApps f ))
                erases Σ Γ (mkApps f ) EAst.tBox
                 (erases Σ Γ)
                t = EAst.mkApps EAst.tBox
  )
   f' L', t = EAst.mkApps f' L'
            erases Σ Γ f f'
             (erases Σ Γ) L L'.
Proof.
  intros. revert f H ; induction L; cbn in *; intros.
  - right. t, []. cbn. repeat split; eauto.
  - eapply IHL in H; eauto.
    destruct H as [ (? & ? & ? & ? & ? & ? & ? & ?) | (? & ? & ? & ? & ?)].
    + subst. left. (a :: x), , . destruct . repeat split; eauto.
    + subst.
      eapply erases_App in as [ ( & []) | (? & ? & ? & ? & ?)].
      × left. [a], L, . cbn. repeat split; eauto. now constructor.
      × subst. right. , ( :: ). repeat split; eauto.
Qed.


Lemma is_FixApp_erases Σ Γ t t' :
  Σ;;; Γ t t'
  negb (isFixApp t) negb (EAstUtils.isFixApp t').
Proof.
  induction 1; cbn; try congruence.
  - unfold isFixApp, head in ×. cbn. clear .
    cbn. rewrite PCUICAstUtils.fst_decompose_app_rec.
    unfold EAstUtils.isFixApp. now rewrite EAstUtils.head_tApp.
Qed.


Lemma is_ConstructApp_erases Σ Γ t t' :
  Σ;;; Γ t t'
  negb (isConstructApp t) negb (EAstUtils.isConstructApp t').
Proof. induction 1; cbn; try congruence.
- unfold isConstructApp in ×. clear .
  cbn. rewrite head_tapp.
  unfold EAstUtils.isConstructApp in ×.
  cbn. now rewrite EAstUtils.head_tApp.
Qed.


Lemma is_PrimApp_erases Σ Γ t t' :
  Σ;;; Γ t t'
  negb (isPrimApp t) negb (EAstUtils.isPrimApp t').
Proof. induction 1; cbn; try congruence.
- unfold isPrimApp in ×. clear .
  cbn. rewrite head_tapp.
  unfold EAstUtils.isPrimApp in ×.
  cbn. now rewrite EAstUtils.head_tApp.
Qed.


Lemma erases_isLambda {Σ Γ t u} :
  Σ ;;; Γ t u isLambda t EAst.isLambda u || EAstUtils.isBox u.
Proof.
  intros hf.
  induction hf ⇒ //.
Qed.


Preliminaries on arities and proofs

The erasure relation enjoys substitutivity with terms and universes, weakening, closure under reduction. It also preserves scoping of terms

Erasure is stable under context conversion


Lemma Is_type_conv_context (Σ : global_env_ext) (Γ : context) t (Γ' : context) :
  wf Σ wf_local Σ Γ wf_local Σ Γ'
  conv_context cumulAlgo_gen Σ Γ Γ' isErasable Σ Γ t isErasable Σ Γ' t.
Proof.
  intros.
  destruct as (? & ? & ?). red.
   x. split. eapply context_conversion. 3:eapply . all:eauto.
  destruct s as [? | [u []]].
  - left. eauto.
  - right. u. split; eauto. eapply context_conversion in ; eauto.
Qed.


#[global]
Hint Resolve Is_type_conv_context : core.

Lemma erases_context_conversion :
  env_prop
  ( (Σ : global_env_ext) (Γ : context) (t T : PCUICAst.term) ⇒
       Γ' : context,
        conv_context cumulAlgo_gen Σ Γ Γ'
        wf_local Σ Γ'
         t', erases Σ Γ t t' erases Σ Γ' t t')
  ( (Σ : global_env_ext) (Γ : context) j
     Γ' : context,
      conv_context cumulAlgo_gen Σ Γ Γ'
      wf_local Σ Γ'
      lift_wf_term ( t t', erases Σ Γ t t' erases Σ Γ' t t') j)
  ( Σ Γwf_local Σ Γ)
        .
Proof.
  apply typing_ind_env; intros Σ wfΣ Γ wfΓ; intros **; rename_all_hyps; auto.
  { destruct X as (Htm & u & (_ & Hty) & _). split; eauto. destruct j_term ⇒ // ?. cbn in ×. now eapply Htm. }
  all: match goal with [ H : erases _ _ ?a _ |- ?G ] ⇒ tryif is_var a then idtac else invs H end.
  all: try now (econstructor; eauto).
  - econstructor. eapply .
    econstructor. eauto. now constructor.
    constructor; auto.
    eapply lift_typing_impl with (1 := ) ⇒ ?? HT.
    eapply context_conversion. 3:eauto. all:eauto.
  - econstructor.
    now edestruct forall_Γ'; tea; eauto.
    eapply .
    econstructor. eauto. now constructor.
    constructor; auto.
    eapply lift_typing_impl with (1 := ) ⇒ ?? HT.
    eapply context_conversion. 3:eauto. all:eauto.
  - econstructor. eauto. eauto.
    eapply (All2i_All2_All2 ).
    intros ? ? ? (? & ?) (? & ? & (? & ?) & ? & ?) (? & ?).
    split. 2: assumption.
    rewrite (PCUICCasesContexts.inst_case_branch_context_eq a).
    eapply e.
    + rewrite case_branch_type_fst.
      eapply conv_context_app_same; eauto.
    + eapply typing_wf_local.
      eapply context_conversion.
      × exact .
      × eapply conv_context_wf_local_app; eauto.
      × eapply conv_context_app_same; eauto.
    + now rewrite case_branch_type_fst (PCUICCasesContexts.inst_case_branch_context_eq a).
  - econstructor.

    eapply All2_impl. eapply All2_All_mix_left. exact . eassumption.
    intros. cbn in ×.
    destruct as [IH []].
    split; intuition auto.
    eapply IH.
    + subst types.
      eapply conv_context_app_same; auto.
    + eapply conv_context_wf_local_app; eauto.
    + assumption.
  - econstructor.

    eapply All2_impl. eapply All2_All_mix_left. exact . eassumption.
    intros. cbn in ×.
    destruct as [IH []].
    split; intuition auto.
    eapply IH.
    + subst types. eapply conv_context_app_same; auto.
    + subst types. eapply conv_context_wf_local_app; eauto.
    + assumption.
  - econstructor. depelim ; constructor. depelim ; depelim ; constructor; eauto.
    solve_all.
Qed.


isErasable is stable under universe instantiation


Lemma isErasable_subst_instance (Σ : global_env_ext) Γ T univs u :
  wf_ext_wk Σ wf_local Σ Γ
  wf_local (Σ.1, univs) (subst_instance u Γ)
  isErasable Σ Γ T
  consistent_instance_ext (Σ.1,univs) (Σ.2) u
  isErasable (Σ.1,univs) (subst_instance u Γ) (subst_instance u T).
Proof.
  intros. destruct as (? & ? & [ | (? & ? & ?)]).
  - eapply typing_subst_instance in t; eauto.
    eexists. split.
    + eapply t; tas.
    + left. eapply isArity_subst_instance. eauto.
  - eapply typing_subst_instance in t; eauto.
    eexists. split.
    + eapply t; tas.
    + right.
      eapply typing_subst_instance in ; eauto.
      eexists. split.
      × eapply ; tas.
      × now rewrite is_propositional_subst_instance.
Qed.


Erasure is stable under instantiation of universes


Lemma fix_context_subst_instance:
   (mfix : list (BasicAst.def term)) (u : Instance.t),
    map (map_decl (subst_instance u))
        (fix_context mfix) =
    fix_context
      (map
         (map_def (subst_instance u)
                  (subst_instance u)) mfix).
Proof.
  intros mfix. unfold fix_context. intros.
  rewrite map_rev.
  rewrite mapi_map.
  rewrite map_mapi. f_equal. eapply mapi_ext. intros. cbn.
  unfold map_decl. cbn. unfold vass.
  rewrite subst_instance_lift. reflexivity.
Qed.


Lemma erases_subst_instance0
  : env_prop ( Σ Γ t Twf_ext_wk Σ
                            t' u univs,
                             wf_local (Σ.1, univs) (subst_instance u Γ)
      consistent_instance_ext (Σ.1,univs) (Σ.2) u
    Σ ;;; Γ t t'
    (Σ.1,univs) ;;; (subst_instance u Γ) subst_instance u t t')
    ( Σ Γ jwf_ext_wk Σ
         u univs,
        wf_local (Σ.1, univs) (subst_instance u Γ)
        consistent_instance_ext (Σ.1,univs) (Σ.2) u
        lift_wf_term ( t t', Σ ;;; Γ t t' (Σ.1,univs) ;;; (subst_instance u Γ) subst_instance u t t') j)
    ( Σ Γwf_local Σ Γ).
Proof.
  apply typing_ind_env; intros; cbn -[subst_instance] in *; auto.
  { destruct X as (Htm & s & (_ & Hty) & _). split; eauto. destruct j_term ⇒ // ?. cbn in ×. now eapply Htm. }
  all: match goal with [ H : erases _ _ ?a _ |- ?G ] ⇒ tryif is_var a then idtac else invs H end.
  all: try now (econstructor; eauto 2 using isErasable_subst_instance).
  - cbn. econstructor.
    eapply H in ; eauto. apply .
    cbn. econstructor. eauto.
    eapply lift_typing_fu_impl with (1 := ) ⇒ // ?? HT.
    now apply typing_subst_instance.
  - cbn. econstructor.
    now edestruct ; tea; eauto.
    eapply H in ; eauto. exact .
    cbn. econstructor. eauto.
    eapply lift_typing_fu_impl with (1 := ) ⇒ // ?? HT.
    now apply typing_subst_instance.
  - unfold subst_instance.
    cbn [subst_instance_constr]. econstructor; eauto.
    eapply All2_map_left.
    eapply (All2i_All2_All2 ).
    intros ? ? [] [] (? & ? & (? & ?) & (? & ?)) (? & ?). split.
    2: now cbn in ×.
    cbn -[app_context] in ×. fold (subst_instance u bbody).
    eapply erases_ext_eq.
    2, 4, 5: reflexivity. eapply e; eauto.
    + eapply typing_subst_instance_wf_local; eauto.
      destruct Σ; eassumption.
    + rewrite case_branch_type_fst PCUICCasesContexts.inst_case_branch_context_eq; eauto.
    + rewrite case_branch_type_fst PCUICCasesContexts.inst_case_branch_context_eq; eauto.
      rewrite subst_instance_app. unfold app_context. f_equal.
      now rewrite inst_case_branch_context_subst_instance.
  - assert (Hw : wf_local (Σ.1, univs) (subst_instance u (Γ ,,, types))).
    { eapply typing_subst_instance_wf_local; eauto. destruct Σ as [Σ Σu].
      now eapply All_mfix_wf. }

    cbn. econstructor; eauto.
    eapply All2_map_left.
    eapply All2_impl. eapply All2_All_mix_left. eapply . eassumption.
    intros d d' [IH []]; cbn in ×.
    split; auto.
    now eapply isLambda_subst_instance.
    eapply IH in .
    rewrite subst_instance_app in . subst types. 2:eauto.
    eapply erases_ctx_ext. eassumption. unfold app_context.
    f_equal.
    eapply fix_context_subst_instance. all: eauto.

  - assert (Hw : wf_local (Σ.1, univs) (subst_instance u (Γ ,,, types))).
    { eapply typing_subst_instance_wf_local; eauto. destruct Σ as [Σ Σu].
      now eapply All_mfix_wf. }

  cbn. econstructor; eauto.
  eapply All2_map_left.
  eapply All2_impl. eapply All2_All_mix_left. eapply . eassumption.
  intros d d' [IH (? & ? & ?)]; cbn in ×.
  repeat split; eauto.
  eapply IH in .
  rewrite subst_instance_app in ; eauto. subst types. 2:eauto.
  eapply erases_ctx_ext. eassumption. unfold app_context.
  f_equal.
  eapply fix_context_subst_instance. all: eauto.

  - cbn; constructor. depelim .
    depelim ; depelim ; repeat constructor; cbn; eauto.
    solve_all.
Qed.


Lemma erases_subst_instance :
   Σ : global_env_ext, wf_ext_wk Σ
   Γ, wf_local Σ Γ
   t T, Σ ;;; Γ t : T
     t' u univs,
  wf_local (Σ.1, univs) (subst_instance u Γ)
   consistent_instance_ext (Σ.1,univs) (Σ.2) u
    Σ ;;; Γ t t'
    (Σ.1,univs) ;;; (subst_instance u Γ) subst_instance u t t'.
Proof.
  intros Σ X Γ t T t' u univs H .
  unshelve eapply (erases_subst_instance0 Σ _ Γ _ _ _); tea; eauto.
Qed.


Lemma erases_subst_instance'' Σ φ Γ t T u univs t' :
  wf_ext_wk (Σ, univs)
  (Σ, univs) ;;; Γ t : T
  consistent_instance_ext (Σ, φ) univs u
  (Σ, univs) ;;; Γ t t'
  (Σ, φ) ;;; subst_instance u Γ
             subst_instance u t t'.
Proof.
  intros X . intros.
  eapply (erases_subst_instance (Σ, univs)); tas.
  eapply typing_wf_local; eassumption. eauto.
  eapply typing_wf_local.
  eapply typing_subst_instance''; eauto.
Qed.


Lemma erases_subst_instance_decl Σ Γ t T c decl u t' :
  wf Σ.1
  lookup_env Σ.1 c = Some decl
  (Σ.1, universes_decl_of_decl decl) ;;; Γ t : T
  consistent_instance_ext Σ (universes_decl_of_decl decl) u
  (Σ.1, universes_decl_of_decl decl) ;;; Γ t t'
   Σ ;;; subst_instance u Γ
             subst_instance u t t'.
Proof.
  destruct Σ as [Σ φ]. intros X .
  eapply erases_subst_instance''; tea. split; tas.
  eapply weaken_lookup_on_global_env'; tea.
Qed.


Erasure preserves scoping

Lemma erases_closed Σ Γ a e : PCUICAst.closedn #|Γ| a Σ ;;; Γ a e ELiftSubst.closedn #|Γ| e.
Proof.
  remember #|Γ| as Γl eqn:Heq.
  intros cla era.
  revert Γ e era Heq.
  pattern Γl, a.
  match goal with
  |- ?P Γl asimpl; eapply (term_closedn_list_ind P); auto; clear
  end; simpl; intros; subst k;
    match goal with [H:erases _ _ _ _ |- _] ⇒ depelim H end; trivial;
    simpl; try solve [solve_all].
  - now apply Nat.ltb_lt.
  - apply andb_and. split; eauto.
    eapply All_forallb. unfold tCaseBrsProp_k in .
    eapply All2_All_mix_left in ; eauto.
    close_Forall. intros [] []. cbn in ×. intros.
    solve_all. subst. rewrite length_map. eapply . eauto.
    rewrite app_context_length. cbn.
    now rewrite inst_case_branch_context_length.
  - epose proof (All2_length ).
    solve_all. destruct b. destruct y ; simpl in *; subst.
    unfold EAst.test_def; simpl; eauto.
    rewrite H. rewrite fix_context_length in .
    eapply . eauto. now rewrite length_app fix_context_length.
  - epose proof (All2_length ).
    solve_all. destruct y ; simpl in *; subst.
    unfold EAst.test_def; simpl; eauto.
    rewrite H. rewrite fix_context_length in .
    eapply . eauto. now rewrite length_app fix_context_length.
  - depelim H. depelim ; solve_all.
    depelim X; solve_all. eapply primProp_impl_test_prim.
    constructor; intuition eauto. solve_all.
Qed.


Auxilliary notion of wellformedness on PCUIC to prove that erased terms are wellformed

Section wellscoped.
  Import PCUICAst PCUICGlobalEnv.

  Definition lookup_constant Σ kn :=
    match PCUICEnvironment.lookup_env Σ kn with
    | Some (ConstantDecl d) ⇒ Some d
    | _None
    end.
  Import MRMonadNotation.

  Section Def.
  Context (Σ : global_env).
  Import ssrbool.

  Definition wf_brs ind brsl :=
    match lookup_inductive Σ ind with
    | Some (mib, oib)#|oib.(ind_ctors)| == brsl
    | Nonefalse
    end.

  Fixpoint wellformed (t : term) : bool :=
  match t with
  | tRel itrue
  | tPrim ptest_prim wellformed p
  | tEvar ev argsList.forallb (wellformed) args
  | tLambda _ N Mwellformed N && wellformed M
  | tApp u vwellformed u && wellformed v
  | tLetIn na b ty b'wellformed b && wellformed ty && wellformed b'
  | tCase ind p c brs
    let brs' := forallb (wellformed bbody) brs in
    wf_brs ind.(ci_ind) #|brs| && wellformed c && brs'
  | tProj p cisSome (lookup_projection Σ p) && wellformed c
  | tFix mfix idx
    (idx <? #|mfix|) &&
    List.forallb (test_def (wellformed) ( b(isLambda b) && wellformed b)) mfix
  | tCoFix mfix idx
    (idx <? #|mfix|) &&
    List.forallb (test_def wellformed wellformed) mfix
  | tConst kn _isSome (lookup_constant Σ kn)
  | tConstruct ind c _isSome (lookup_constructor Σ ind c)
  | tVar _true
  | tInd ind _isSome (lookup_inductive Σ ind)
  | tSort _true
  | tProd na wellformed && wellformed
  end.
  End Def.

  Arguments lookup_projection : simpl never.
  Lemma typing_wellformed :
    env_prop ( Σ Γ a Awellformed Σ a)
        ( Σ _ jlift_wfb_term (wellformed Σ) j)
        ( Σ ΓTrue).
  Proof.
    eapply typing_ind_env; cbn; intros ⇒ //.
    { destruct X as (Htm & _ & (_ & Hty) & _). unfold lift_wfb_term. rewrite Hty andb_true_r. destruct j_term ⇒ //. apply Htm. }
    all:try unfold lift_wfb_term in *; rtoProp; intuition auto.
    - unshelve eapply declared_constant_to_gen in ; eauto.
      red in . rewrite /lookup_constant /lookup_constant_gen //.
    - unshelve eapply declared_inductive_to_gen in isdecl; eauto.
      unfold lookup_inductive. now rewrite (declared_inductive_lookup_gen isdecl).
    - unshelve eapply declared_constructor_to_gen in isdecl; eauto.
      unfold lookup_constructor. rewrite (declared_constructor_lookup_gen isdecl) //.
    - unshelve eapply declared_inductive_to_gen in isdecl; eauto.
      rewrite /wf_brs.
      unfold lookup_inductive. rewrite (declared_inductive_lookup_gen isdecl).
      red in . apply Forall2_length in . now apply Nat.eqb_eq.
    - red in . eapply Forall2_All2 in .
      eapply All2i_All2_mix_left in ; tea. clear .
      solve_all.
    - unshelve eapply declared_projection_to_gen in isdecl; eauto.
      unfold lookup_projection. now rewrite (declared_projection_lookup_gen isdecl).
    - now eapply nth_error_Some_length, Nat.ltb_lt in .
    - move/andb_and: ⇒ [] hb _.
      unfold on_def_body, on_def_type, test_def in ×. cbn in ×.
      solve_all.
    - now eapply nth_error_Some_length, Nat.ltb_lt in .
    - unfold on_def_body, on_def_type, test_def in ×. cbn in ×.
      solve_all.
    - depelim ; solve_all; constructor; eauto.
  Qed.


  Lemma welltyped_wellformed {Σ : global_env_ext} {wfΣ : wf Σ} {Γ a} : welltyped Σ Γ a wellformed Σ a.
  Proof.
    intros []. eapply typing_wellformed; tea.
  Qed.


End wellscoped.

Import EWellformed.

Section trans_lookups.
  Context {Σ : global_env_ext} {Σ'} (g : globals_erased_with_deps Σ Σ').

  (* TODO simplify using lookup_*_declared lemmas *)
  Lemma trans_lookup_constant kn : isSome (lookup_constant Σ kn) isSome (EGlobalEnv.lookup_constant Σ' kn).
  Proof using g.
    unfold lookup_constant.
    destruct (lookup_env Σ kn) as [[]|] eqn:hl ⇒ //.
    destruct g as [? _]. destruct (H kn c) as [? [? ?]].
    eapply declared_constant_from_gen; eauto.
    erewrite EGlobalEnv.declared_constant_lookup; eauto.
  Qed.


  Lemma trans_lookup_inductive kn mib oib :
    lookup_inductive Σ kn = Some (mib, oib)
     mib' oib', EGlobalEnv.lookup_inductive Σ' kn = Some (mib', oib') #|oib.(ind_ctors)| = #|oib'.(EAst.ind_ctors)|.
  Proof. destruct g.
    destruct (lookup_inductive Σ kn) as [[]|] eqn:hl ⇒ /= // [=]. intros → →.
    eapply lookup_inductive_declared in hl.
    eapply declared_inductive_from_gen in hl.
    specialize ( kn mib oib hl) as [? [? [d er]]].
     x, .
    split. now rewrite (EGlobalEnv.declared_inductive_lookup d).
    depelim er. depelim hl. depelim d.
    eapply Forall2_nth_error_left in as [x' []]; tea.
    rewrite in . noconf . depelim . now apply Forall2_length in .
  Qed.


  Lemma trans_lookup_constructor kn c : isSome (lookup_constructor Σ kn c) isSome (EGlobalEnv.lookup_constructor Σ' kn c).
  Proof using g.
    destruct g.
    destruct (lookup_constructor Σ kn c) as [[[]]|] eqn:hl ⇒ /= // _.
    eapply (lookup_constructor_declared_gen (id:=(kn,c))) in hl.
    eapply declared_constructor_from_gen in hl.
    specialize ( _ _ _ hl.p1) as [mdecl' [idecl' [decli hl']]].
    destruct hl', hl. cbn in × |-.
    destruct . eapply Forall2_nth_error_left in as [? [? [erc erp]]]; tea.
    eapply Forall2_nth_error_left in erc as [? [? ?]]; tea.
    destruct decli as [declm decli]. rewrite in decli. noconf decli.
    erewrite (EGlobalEnv.declared_constructor_lookup (id:=(kn,c))) ⇒ //.
    split; tea. split; tea.
  Qed.


  Lemma lookup_projection_lookup_constructor {p mdecl idecl cdecl pdecl} :
    lookup_projection Σ p = Some (mdecl, idecl, cdecl, pdecl)
    lookup_constructor Σ p.(proj_ind) 0 = Some (mdecl, idecl, cdecl).
  Proof using Type.
    rewrite /lookup_projection /lookup_projection_gen /lookup_constructor.
    destruct lookup_constructor_gen as [[[? ?] ?]|] //=.
    now destruct nth_error ⇒ //.
  Qed.


  Lemma trans_lookup_projection p :
    isSome (lookup_projection Σ p)
    isSome (EGlobalEnv.lookup_projection Σ' p).
  Proof using g.
    destruct g.
    destruct (lookup_projection Σ p) as [[[[]]]|] eqn:hl ⇒ /= // _.
    pose proof (lookup_projection_lookup_constructor hl) as lc.
    unfold lookup_projection, lookup_projection_gen in hl. unfold lookup_constructor in lc.
    rewrite lc in hl.
    eapply (lookup_constructor_declared_gen (id:=(_,_))) in lc.
    eapply declared_constructor_from_gen in lc.
    specialize ( _ _ _ lc.p1) as [mdecl' [idecl' [decli hl']]].
    destruct hl', lc.
    destruct .
    destruct (nth_error (ind_projs o)) eqn:hnth ⇒ //. noconf hl.
    eapply Forall2_nth_error_left in as [? [? [erc [erp ?]]]]; tea.
    destruct decli. rewrite in ; noconf .
    eapply Forall2_nth_error_left in erc as [? [? ?]]; tea.
    eapply Forall2_nth_error_left in erp as [? [? ?]]; tea.
    rewrite /EGlobalEnv.lookup_projection /EGlobalEnv.lookup_constructor /EGlobalEnv.lookup_inductive.
    rewrite (EGlobalEnv.declared_minductive_lookup ); cbn -[nth_error]; rewrite //.
  Qed.


End trans_lookups.

Lemma erases_wellformed {Σ : global_env_ext} {wfΣ : wf Σ} {Γ a e} : welltyped Σ Γ a Σ ;;; Γ a e
   Σ', globals_erased_with_deps Σ Σ' @EWellformed.wellformed EWellformed.all_env_flags Σ' #|Γ| e.
Proof.
  intros wf.
  generalize (welltyped_wellformed wf).
  destruct wf. eapply subject_closed in X. move: X.
  remember #|Γ| as Γl eqn:Heq.
  intros cla wfa era.
  revert Γ e wfa era Heq.
  pattern Γl, a.
  match goal with
  |- ?P Γl asimpl; eapply (term_closedn_list_ind P); auto; clear
  end; simpl; intros; subst k;
    match goal with [H:erases _ _ _ _ |- _] ⇒ depelim H end; trivial;
    simpl; try solve [solve_all].
  - now apply Nat.ltb_lt.
  - eapply trans_lookup_constant in wfa; tea.
  - eapply trans_lookup_constructor in wfa; tea. now rewrite wfa.
  - move/andP: wfa ⇒ [] /andP[] lookup wfc wfbrs.
    apply/andP. split. apply/andP. split; eauto.
    { rewrite /wf_brs.
      move: lookup. rewrite /ErasureProperties.wf_brs.
      destruct lookup_inductive as [[mib oib]|] eqn:hli ⇒ //.
      eapply trans_lookup_inductive in hli as [mib' [oib' [ ]]]; tea.
      move/Nat.eqb_eq →. apply All2_length in . now apply Nat.eqb_eq. }
    eapply All_forallb. unfold tCaseBrsProp_k in .
    eapply All2_All_mix_left in ; eauto.
    eapply forallb_All in wfbrs.
    eapply All2_All_mix_left in ; eauto.
    close_Forall. intros [] []; move⇒ [] wf. cbn in ×. intros.
    solve_all. subst. rewrite length_map. eapply b; eauto.
    rewrite app_context_length. cbn.
    now rewrite inst_case_branch_context_length.
  - move/andP: wfa ⇒ [] hl hc.
    apply/andP; split.
    now eapply trans_lookup_projection in hl.
    eauto.
  - epose proof (All2_length ).
    unfold EWellformed.wf_fix_gen.
    rewrite -. move/andP: wfa ⇒ [] →.
    move/forallb_All. cbn. intros wfa.
    solve_all. destruct b.
    destruct y ; simpl in *; subst.
    unfold EAst.test_def; simpl; eauto.
    rewrite fix_context_length in .
    move/andP: ⇒ //; eauto. move⇒ [] wft /andP[] isl wf; eauto.
    eapply ; tea. eapply b. now rewrite length_app fix_context_length.
  - epose proof (All2_length ).
    unfold EWellformed.wf_fix_gen.
    rewrite -. move/andP: wfa ⇒ [] →.
    move/forallb_All. cbn. intros wfa.
    solve_all. destruct y ; simpl in *; subst.
    unfold EAst.test_def; simpl; eauto.
    rewrite fix_context_length in b.
    eapply b. now move: ⇒ /andP[]. eauto. now rewrite length_app fix_context_length. tea.
  - depelim H. solve_all. primProp.
    depelim ; depelim ; repeat constructor; cbn; intuition eauto. solve_all.
Qed.


Lemma eval_empty_brs {wfl : EWcbvEval.WcbvFlags} Σ ci p e : Σ E.tCase ci p [] e False.
Proof.
  intros He.
  depind He.
  - clear -. now rewrite nth_error_nil in .
  - clear -. now rewrite nth_error_nil in .
  - discriminate.
  - eapply .
  - cbn in i. discriminate.
Qed.


Lemma eval_case_tBox_inv {wfl : EWcbvEval.WcbvFlags} {Σ ci e brs} :
  Σ E.tCase ci EAst.tBox brs e
   n br, brs = [(n, br)] × inductive_isprop_and_pars Σ ci.1 = Some (true, ci.2) ×
  Σ ECSubst.substl (repeat EAst.tBox #|n|) br e.
Proof.
  intros He.
  depind He.
  - depelim . clear -H. symmetry in H. exfalso.
    destruct args using rev_case. discriminate.
    rewrite EAstUtils.mkApps_app in H. discriminate.
  - depelim .
  - n, . intuition auto.
  - depelim . clear -H. symmetry in H. exfalso.
    destruct args using rev_case. discriminate.
    rewrite EAstUtils.mkApps_app in H. discriminate.
  - cbn in i. discriminate.
Qed.


Lemma eval_case_eval_discr {wfl : EWcbvEval.WcbvFlags} {Σ ci c c' e brs} :
  Σ E.tCase ci c brs e
  Σ c c'
  Σ E.tCase ci c' brs e.
Proof.
  intros He Hc.
  depind He.
  - pose proof (EWcbvEval.eval_deterministic Hc). subst c'.
    econstructor; eauto. now eapply EWcbvEval.value_final, EWcbvEval.eval_to_value.
  - pose proof (EWcbvEval.eval_deterministic Hc). subst c'.
    eapply EWcbvEval.eval_iota_block; eauto. now eapply EWcbvEval.value_final, EWcbvEval.eval_to_value.
  - pose proof (EWcbvEval.eval_deterministic Hc). subst c'.
    eapply EWcbvEval.eval_iota_sing; tea. now constructor.
  - pose proof (EWcbvEval.eval_deterministic Hc). subst c'.
    eapply EWcbvEval.eval_cofix_case; tea.
    now eapply EWcbvEval.value_final, EWcbvEval.eval_to_value.
  - cbn in i. discriminate.
Qed.


Lemma eval_case_eval_inv_discr {wfl : EWcbvEval.WcbvFlags} {Σ ci c c' e brs} :
  Σ E.tCase ci c brs e
  Σ c' c
  Σ E.tCase ci c' brs e.
Proof.
  intros He Hc.
  depind He.
  - pose proof (eval_trans' Hc ); subst discr.
    econstructor; eauto.
  - pose proof (eval_trans' Hc ); subst discr.
    now econstructor; eauto.
  - pose proof (eval_trans' Hc ); subst discr.
    eapply EWcbvEval.eval_iota_sing; tea.
  - pose proof (eval_trans' Hc ); subst discr.
    eapply EWcbvEval.eval_cofix_case; tea.
  - cbn in i. discriminate.
Qed.


Lemma eval_proj_eval_inv_discr {wfl : EWcbvEval.WcbvFlags} {Σ p c c' e} :
  Σ E.tProj p c e
  Σ c' c
  Σ E.tProj p c' e.
Proof.
  intros He Hc.
  depind He.
  - pose proof (eval_trans' Hc ); subst discr.
    econstructor; eauto.
  - pose proof (eval_trans' Hc ); subst discr.
    now econstructor; tea.
  - pose proof (eval_trans' Hc ); subst discr.
    now econstructor; tea.
  - pose proof (eval_trans' Hc He); subst discr.
    now econstructor; tea.
  - cbn in i. discriminate.
Qed.