Require Import Coq.Program.Equality.
Require Import Coq.Program.Tactics.
Require Export Needle.
Section Namespace.
  Inductive Namespace : Type :=
    | tm .
  Lemma eq_namespace_dec (a : Namespace) (b : Namespace) :
    (sumbool (a =
    b) (not (a =
    b))).
  Proof.
    decide equality .
  Defined.
End Namespace.

Section HVarlist.
  Inductive Hvl : Type :=
    | H0
    | HS (a : Namespace) (k : Hvl).

  Fixpoint appendHvl (k : Hvl) (k0 : Hvl) {struct k0} : Hvl :=
    match k0 with
      | (H0) => k
      | (HS a k0) => (HS a (appendHvl k k0))
    end.

  Lemma appendHvl_assoc  :
    (forall (k : Hvl) (k0 : Hvl) (k1 : Hvl) ,
      ((appendHvl (appendHvl k k0) k1) =
      (appendHvl k (appendHvl k0 k1)))).
  Proof.
    needleGenericWeakenAppend .
  Qed.
End HVarlist.

Section Index.
  Inductive Index (a : Namespace) : Type :=
    | I0
    | IS : (Index a) -> (Index a).

  Global Arguments I0 [a] .
  Global Arguments IS [a] _ .

  Lemma eq_index_dec {a : Namespace} (i : (Index a)) (j : (Index a)) :
    (sumbool (i =
    j) (not (i =
    j))).
  Proof.
    decide equality .
  Qed.

  Fixpoint weakenIndextm (x : (Index tm)) (k : Hvl) {struct k} : (Index tm) :=
    match k with
      | (H0) => x
      | (HS a k) => match a with
        | (tm) => (IS (weakenIndextm x k))
      end
    end.
  Lemma weakenIndextm_append  :
    (forall (x : (Index tm)) (k : Hvl) (k0 : Hvl) ,
      ((weakenIndextm (weakenIndextm x k) k0) =
      (weakenIndextm x (appendHvl k k0)))).
  Proof.
    needleGenericWeakenAppend .
  Qed.
End Index.

Section Terms.
  Inductive Ty : Set :=
    | tunit
    | tarr (T1 : Ty) (T2 : Ty)
    | tprod (T1 : Ty) (T2 : Ty).
  Scheme ind_Ty := Induction for Ty Sort Prop.

  Inductive Pat : Set :=
    | pvar (T : Ty)
    | pprod (p1 : Pat) (p2 : Pat).
  Scheme ind_Pat := Induction for Pat Sort Prop.

  Inductive Tm : Set :=
    | var (x : (Index tm))
    | tt
    | abs (T : Ty) (t : Tm)
    | app (t1 : Tm) (t2 : Tm)
    | prod (t1 : Tm) (t2 : Tm)
    | lett (p : Pat) (t1 : Tm)
        (t2 : Tm).
  Scheme ind_Tm := Induction for Tm Sort Prop.
End Terms.

Section Functions.
  Fixpoint bindPat (p : Pat) {struct p} : Hvl :=
    match p with
      | (pvar T) => (appendHvl (HS tm H0) H0)
      | (pprod p1 p2) => (appendHvl (bindPat p1) (appendHvl (bindPat p2) H0))
    end.
  Scheme ind_bindPat_Pat := Induction for Pat Sort Prop.
End Functions.

Section Shift.
  Inductive Cutoff (a : Namespace) : Type :=
    | C0
    | CS : (Cutoff a) -> (Cutoff a).

  Global Arguments C0 {a} .
  Global Arguments CS {a} _ .
  Fixpoint weakenCutofftm (c : (Cutoff tm)) (k : Hvl) {struct k} : (Cutoff tm) :=
    match k with
      | (H0) => c
      | (HS a k) => match a with
        | (tm) => (CS (weakenCutofftm c k))
      end
    end.

  Lemma weakenCutofftm_append  :
    (forall (c : (Cutoff tm)) (k : Hvl) (k0 : Hvl) ,
      ((weakenCutofftm (weakenCutofftm c k) k0) =
      (weakenCutofftm c (appendHvl k k0)))).
  Proof.
    needleGenericWeakenAppend .
  Qed.
  Fixpoint shiftIndex (c : (Cutoff tm)) (x : (Index tm)) {struct c} : (Index tm) :=
    match c with
      | (C0) => (IS x)
      | (CS c) => match x with
        | (I0) => I0
        | (IS x) => (IS (shiftIndex c x))
      end
    end.
  Fixpoint shiftTm (c : (Cutoff tm)) (s : Tm) {struct s} : Tm :=
    match s with
      | (var x) => (var (shiftIndex c x))
      | (tt) => (tt)
      | (abs T t) => (abs T (shiftTm (weakenCutofftm c (appendHvl (HS tm H0) H0)) t))
      | (app t1 t2) => (app (shiftTm (weakenCutofftm c H0) t1) (shiftTm (weakenCutofftm c H0) t2))
      | (prod t0 t3) => (prod (shiftTm (weakenCutofftm c H0) t0) (shiftTm (weakenCutofftm c H0) t3))
      | (lett p t4 t5) => (lett p (shiftTm (weakenCutofftm c H0) t4) (shiftTm (weakenCutofftm c (appendHvl (bindPat p) H0)) t5))
    end.
End Shift.

Section Weaken.
  Fixpoint weakenTy (S0 : Ty) (k : Hvl) {struct k} : Ty :=
    match k with
      | (H0) => S0
      | (HS tm k) => (weakenTy S0 k)
    end.
  Fixpoint weakenPat (p : Pat) (k : Hvl) {struct k} : Pat :=
    match k with
      | (H0) => p
      | (HS tm k) => (weakenPat p k)
    end.
  Fixpoint weakenTm (s : Tm) (k : Hvl) {struct k} : Tm :=
    match k with
      | (H0) => s
      | (HS tm k) => (shiftTm C0 (weakenTm s k))
    end.
End Weaken.

Section Subst.
  Inductive Trace (a : Namespace) : Type :=
    | X0
    | XS (b : Namespace)
        (T : (Trace a)).

  Global Arguments X0 [a] .
  Global Arguments XS [a] b _ .
  Fixpoint weakenTrace {a : Namespace} (x : (Trace a)) (k : Hvl) {struct k} : (Trace a) :=
    match k with
      | (H0) => x
      | (HS b k) => (XS b (weakenTrace x k))
    end.
  Lemma weakenTrace_append (a : Namespace) :
    (forall (x : (Trace a)) (k : Hvl) (k0 : Hvl) ,
      ((weakenTrace (weakenTrace x k) k0) =
      (weakenTrace x (appendHvl k k0)))).
  Proof.
    needleGenericWeakenAppend .
  Qed.
  Fixpoint substIndex (d : (Trace tm)) (s : Tm) (x : (Index tm)) {struct d} : Tm :=
    match d with
      | (X0) => match x with
        | (I0) => s
        | (IS x) => (var x)
      end
      | (XS tm d) => match x with
        | (I0) => (var I0)
        | (IS x) => (shiftTm C0 (substIndex d s x))
      end
    end.
  Fixpoint substTm (d : (Trace tm)) (s : Tm) (s0 : Tm) {struct s0} : Tm :=
    match s0 with
      | (var x) => (substIndex d s x)
      | (tt) => (tt)
      | (abs T t) => (abs T (substTm (XS tm d) s t))
      | (app t1 t2) => (app (substTm d s t1) (substTm d s t2))
      | (prod t0 t3) => (prod (substTm d s t0) (substTm d s t3))
      | (lett p t4 t5) => (lett p (substTm d s t4) (substTm (weakenTrace d (bindPat p)) s t5))
    end.
End Subst.

Global Hint Resolve (f_equal (shiftTm C0)) : cong_shift0.
 Hint Rewrite weakenCutofftm_append : interaction.
 Hint Rewrite weakenCutofftm_append : weakencutoff_append.
 Hint Rewrite weakenTrace_append : interaction.
 Hint Rewrite weakenTrace_append : weakentrace_append.
Lemma stability_weaken_bindPat  :
  (forall (k : Hvl) (p : Pat) ,
    ((bindPat (weakenPat p k)) =
    (bindPat p))).
Proof.
  needleGenericStabilityWeaken .
Qed.
 Hint Rewrite stability_weaken_bindPat : interaction.
 Hint Rewrite stability_weaken_bindPat : stability_weaken.
Section SubstShiftReflection.
  Lemma substIndex0_shiftIndex0_reflection_ind (s : Tm) :
    (forall (k0 : Hvl) (x2 : (Index tm)) ,
      ((substIndex (weakenTrace X0 k0) s (shiftIndex (weakenCutofftm C0 k0) x2)) =
      (var x2))).
  Proof.
    needleGenericSubstIndexShiftIndexReflectionInd .
  Qed.
  Definition subst0_shift0_Tm_reflection_ind := (ind_Tm (fun (s0 : Tm) =>
    (forall (k1 : Hvl) (s1 : Tm) ,
      ((substTm (weakenTrace X0 k1) s1 (shiftTm (weakenCutofftm C0 k1) s0)) =
      s0))) (fun (x5 : (Index tm)) =>
    (fun (k1 : Hvl) (s0 : Tm) =>
      (substIndex0_shiftIndex0_reflection_ind s0 k1 x5))) (fun (k1 : Hvl) (s0 : Tm) =>
    eq_refl) (fun (T : Ty) (t : Tm) IHt13 (k1 : Hvl) (s0 : Tm) =>
    (f_equal2 abs eq_refl (eq_trans (f_equal3 substTm (weakenTrace_append tm X0 k1 (HS tm H0)) eq_refl eq_refl) (IHt13 (HS tm k1) s0)))) (fun (t1 : Tm) IHt13 (t2 : Tm) IHt14 (k1 : Hvl) (s0 : Tm) =>
    (f_equal2 app (IHt13 k1 s0) (IHt14 k1 s0))) (fun (t1 : Tm) IHt13 (t2 : Tm) IHt14 (k1 : Hvl) (s0 : Tm) =>
    (f_equal2 prod (IHt13 k1 s0) (IHt14 k1 s0))) (fun (p : Pat) (t1 : Tm) IHt13 (t2 : Tm) IHt14 (k1 : Hvl) (s0 : Tm) =>
    (f_equal3 lett eq_refl (IHt13 k1 s0) (eq_trans (f_equal3 substTm (weakenTrace_append tm X0 k1 (bindPat p)) eq_refl (f_equal2 shiftTm (weakenCutofftm_append C0 k1 (bindPat p)) eq_refl)) (IHt14 (appendHvl k1 (bindPat p)) s0))))).
  Definition substTm0_shiftTm0_reflection (s1 : Tm) : (forall (s0 : Tm) ,
    ((substTm X0 s0 (shiftTm C0 s1)) =
    s1)) := (subst0_shift0_Tm_reflection_ind s1 H0).
End SubstShiftReflection.
Section ShiftInteraction.
  Section ShiftIndexCommInd.
    Lemma shiftIndex_shiftIndex0_comm_ind  :
      (forall (k : Hvl) (c : (Cutoff tm)) (x : (Index tm)) ,
        ((shiftIndex (weakenCutofftm (CS c) k) (shiftIndex (weakenCutofftm C0 k) x)) =
        (shiftIndex (weakenCutofftm C0 k) (shiftIndex (weakenCutofftm c k) x)))).
    Proof.
      needleGenericShiftIndexCommInd .
    Qed.
  End ShiftIndexCommInd.
  Section ShiftCommInd.
    Definition shift_shift0_Tm_comm_ind := (ind_Tm (fun (s : Tm) =>
      (forall (k0 : Hvl) (c0 : (Cutoff tm)) ,
        ((shiftTm (weakenCutofftm (CS c0) k0) (shiftTm (weakenCutofftm C0 k0) s)) =
        (shiftTm (weakenCutofftm C0 k0) (shiftTm (weakenCutofftm c0 k0) s))))) (fun (x2 : (Index tm)) =>
      (fun (k0 : Hvl) (c0 : (Cutoff tm)) =>
        (f_equal var (shiftIndex_shiftIndex0_comm_ind k0 c0 x2)))) (fun (k0 : Hvl) (c0 : (Cutoff tm)) =>
      eq_refl) (fun (T : Ty) (t : Tm) IHt6 (k0 : Hvl) (c0 : (Cutoff tm)) =>
      (f_equal2 abs eq_refl (IHt6 (HS tm k0) c0))) (fun (t1 : Tm) IHt6 (t2 : Tm) IHt7 (k0 : Hvl) (c0 : (Cutoff tm)) =>
      (f_equal2 app (IHt6 k0 c0) (IHt7 k0 c0))) (fun (t1 : Tm) IHt6 (t2 : Tm) IHt7 (k0 : Hvl) (c0 : (Cutoff tm)) =>
      (f_equal2 prod (IHt6 k0 c0) (IHt7 k0 c0))) (fun (p : Pat) (t1 : Tm) IHt6 (t2 : Tm) IHt7 (k0 : Hvl) (c0 : (Cutoff tm)) =>
      (f_equal3 lett eq_refl (IHt6 k0 c0) (eq_trans (f_equal2 shiftTm (weakenCutofftm_append (CS c0) k0 (bindPat p)) (f_equal2 shiftTm (weakenCutofftm_append C0 k0 (bindPat p)) eq_refl)) (eq_trans (IHt7 (appendHvl k0 (bindPat p)) c0) (f_equal2 shiftTm (eq_sym (weakenCutofftm_append C0 k0 (bindPat p))) (f_equal2 shiftTm (eq_sym (weakenCutofftm_append c0 k0 (bindPat p))) eq_refl))))))).
  End ShiftCommInd.
  Section ShiftComm.
    Definition shift_shift0_Tm_comm (s : Tm) : (forall (c0 : (Cutoff tm)) ,
      ((shiftTm (CS c0) (shiftTm C0 s)) =
      (shiftTm C0 (shiftTm c0 s)))) := (shift_shift0_Tm_comm_ind s H0).
  End ShiftComm.
End ShiftInteraction.
 Hint Rewrite shift_shift0_Tm_comm : interaction.
 Hint Rewrite shift_shift0_Tm_comm : shift_shift0.
Section WeakenShift.
  Lemma weakenTm_shiftTm  :
    (forall (k9 : Hvl) (c1 : (Cutoff tm)) (s9 : Tm) ,
      ((weakenTm (shiftTm c1 s9) k9) =
      (shiftTm (weakenCutofftm c1 k9) (weakenTm s9 k9)))).
  Proof.
    needleGenericWeakenShift .
  Qed.
End WeakenShift.
Section ShiftSubstInteraction.
  Section ShiftSubstIndexCommInd.
    Lemma shiftTm_substIndex0_comm_ind (c0 : (Cutoff tm)) (s0 : Tm) :
      (forall (k1 : Hvl) (x5 : (Index tm)) ,
        ((shiftTm (weakenCutofftm c0 k1) (substIndex (weakenTrace X0 k1) s0 x5)) =
        (substIndex (weakenTrace X0 k1) (shiftTm c0 s0) (shiftIndex (weakenCutofftm (CS c0) k1) x5)))).
    Proof.
      needleGenericShiftSubstIndexCommInd .
    Qed.
  End ShiftSubstIndexCommInd.
  Section ShiftSubstCommInd.
    Definition shift_subst0_Tm_comm_ind := (ind_Tm (fun (s1 : Tm) =>
      (forall (k2 : Hvl) (c1 : (Cutoff tm)) (s2 : Tm) ,
        ((shiftTm (weakenCutofftm c1 k2) (substTm (weakenTrace X0 k2) s2 s1)) =
        (substTm (weakenTrace X0 k2) (shiftTm c1 s2) (shiftTm (weakenCutofftm (CS c1) k2) s1))))) (fun (x8 : (Index tm)) =>
      (fun (k2 : Hvl) (c1 : (Cutoff tm)) (s1 : Tm) =>
        (shiftTm_substIndex0_comm_ind c1 s1 k2 x8))) (fun (k2 : Hvl) (c1 : (Cutoff tm)) (s1 : Tm) =>
      eq_refl) (fun (T : Ty) (t : Tm) IHt20 (k2 : Hvl) (c1 : (Cutoff tm)) (s1 : Tm) =>
      (f_equal2 abs eq_refl (eq_trans (f_equal2 shiftTm eq_refl (f_equal3 substTm (weakenTrace_append tm X0 k2 (HS tm H0)) eq_refl eq_refl)) (eq_trans (IHt20 (HS tm k2) c1 s1) (f_equal3 substTm (eq_sym (weakenTrace_append tm X0 k2 (HS tm H0))) eq_refl eq_refl))))) (fun (t1 : Tm) IHt20 (t2 : Tm) IHt21 (k2 : Hvl) (c1 : (Cutoff tm)) (s1 : Tm) =>
      (f_equal2 app (IHt20 k2 c1 s1) (IHt21 k2 c1 s1))) (fun (t1 : Tm) IHt20 (t2 : Tm) IHt21 (k2 : Hvl) (c1 : (Cutoff tm)) (s1 : Tm) =>
      (f_equal2 prod (IHt20 k2 c1 s1) (IHt21 k2 c1 s1))) (fun (p : Pat) (t1 : Tm) IHt20 (t2 : Tm) IHt21 (k2 : Hvl) (c1 : (Cutoff tm)) (s1 : Tm) =>
      (f_equal3 lett eq_refl (IHt20 k2 c1 s1) (eq_trans (f_equal2 shiftTm (weakenCutofftm_append c1 k2 (bindPat p)) (f_equal3 substTm (weakenTrace_append tm X0 k2 (bindPat p)) eq_refl eq_refl)) (eq_trans (IHt21 (appendHvl k2 (bindPat p)) c1 s1) (f_equal3 substTm (eq_sym (weakenTrace_append tm X0 k2 (bindPat p))) eq_refl (f_equal2 shiftTm (eq_sym (weakenCutofftm_append (CS c1) k2 (bindPat p))) eq_refl))))))).
  End ShiftSubstCommInd.
  Section ShiftSubstComm.
    Definition shiftTm_substTm0_comm (s2 : Tm) : (forall (c1 : (Cutoff tm)) (s1 : Tm) ,
      ((shiftTm c1 (substTm X0 s1 s2)) =
      (substTm X0 (shiftTm c1 s1) (shiftTm (CS c1) s2)))) := (shift_subst0_Tm_comm_ind s2 H0).
  End ShiftSubstComm.
  Section SubstShiftIndexCommInd.
    Lemma substIndex_shiftTm0_comm_ind (d : (Trace tm)) (s1 : Tm) :
      (forall (k2 : Hvl) (x8 : (Index tm)) ,
        ((substIndex (weakenTrace (XS tm d) k2) s1 (shiftIndex (weakenCutofftm C0 k2) x8)) =
        (shiftTm (weakenCutofftm C0 k2) (substIndex (weakenTrace d k2) s1 x8)))).
    Proof.
      needleGenericShiftSubstIndexCommInd .
    Qed.
  End SubstShiftIndexCommInd.
  Section SubstShiftCommInd.
    Definition subst_shift0_Tm_comm_ind := (ind_Tm (fun (s7 : Tm) =>
      (forall (k8 : Hvl) (d5 : (Trace tm)) (s8 : Tm) ,
        ((substTm (weakenTrace (XS tm d5) k8) s8 (shiftTm (weakenCutofftm C0 k8) s7)) =
        (shiftTm (weakenCutofftm C0 k8) (substTm (weakenTrace d5 k8) s8 s7))))) (fun (x11 : (Index tm)) =>
      (fun (k8 : Hvl) (d5 : (Trace tm)) (s7 : Tm) =>
        (substIndex_shiftTm0_comm_ind d5 s7 k8 x11))) (fun (k8 : Hvl) (d5 : (Trace tm)) (s7 : Tm) =>
      eq_refl) (fun (T : Ty) (t : Tm) IHt27 (k8 : Hvl) (d5 : (Trace tm)) (s7 : Tm) =>
      (f_equal2 abs eq_refl (eq_trans (f_equal3 substTm (weakenTrace_append tm (XS tm d5) k8 (HS tm H0)) eq_refl eq_refl) (eq_trans (IHt27 (HS tm k8) d5 s7) (f_equal2 shiftTm eq_refl (f_equal3 substTm (eq_sym (weakenTrace_append tm d5 k8 (HS tm H0))) eq_refl eq_refl)))))) (fun (t1 : Tm) IHt27 (t2 : Tm) IHt28 (k8 : Hvl) (d5 : (Trace tm)) (s7 : Tm) =>
      (f_equal2 app (IHt27 k8 d5 s7) (IHt28 k8 d5 s7))) (fun (t1 : Tm) IHt27 (t2 : Tm) IHt28 (k8 : Hvl) (d5 : (Trace tm)) (s7 : Tm) =>
      (f_equal2 prod (IHt27 k8 d5 s7) (IHt28 k8 d5 s7))) (fun (p : Pat) (t1 : Tm) IHt27 (t2 : Tm) IHt28 (k8 : Hvl) (d5 : (Trace tm)) (s7 : Tm) =>
      (f_equal3 lett eq_refl (IHt27 k8 d5 s7) (eq_trans (f_equal3 substTm (weakenTrace_append tm (XS tm d5) k8 (bindPat p)) eq_refl (f_equal2 shiftTm (weakenCutofftm_append C0 k8 (bindPat p)) eq_refl)) (eq_trans (IHt28 (appendHvl k8 (bindPat p)) d5 s7) (f_equal2 shiftTm (eq_sym (weakenCutofftm_append C0 k8 (bindPat p))) (f_equal3 substTm (eq_sym (weakenTrace_append tm d5 k8 (bindPat p))) eq_refl eq_refl))))))).
  End SubstShiftCommInd.
  Section SubstShiftComm.
    Definition substTm_shiftTm0_comm (s8 : Tm) : (forall (d5 : (Trace tm)) (s7 : Tm) ,
      ((substTm (XS tm d5) s7 (shiftTm C0 s8)) =
      (shiftTm C0 (substTm d5 s7 s8)))) := (subst_shift0_Tm_comm_ind s8 H0).
  End SubstShiftComm.
  Section SubstSubordInd.

  End SubstSubordInd.
  Section SubstSubord.

  End SubstSubord.
End ShiftSubstInteraction.
 Hint Rewrite substTm0_shiftTm0_reflection : interaction.
 Hint Rewrite substTm0_shiftTm0_reflection : reflection.
 Hint Rewrite substTm_shiftTm0_comm : interaction.
 Hint Rewrite substTm_shiftTm0_comm : subst_shift0.
 Hint Rewrite shiftTm_substTm0_comm : interaction.
 Hint Rewrite shiftTm_substTm0_comm : shift_subst0.
Section SubstSubstInteraction.
  Section SubstSubstIndexCommInd.
    Lemma substTm_substIndex0_commright_ind (d5 : (Trace tm)) (s7 : Tm) (s8 : Tm) :
      (forall (k8 : Hvl) (x11 : (Index tm)) ,
        ((substTm (weakenTrace d5 k8) s7 (substIndex (weakenTrace X0 k8) s8 x11)) =
        (substTm (weakenTrace X0 k8) (substTm d5 s7 s8) (substIndex (weakenTrace (XS tm d5) k8) s7 x11)))).
    Proof.
      needleGenericSubstSubstIndexCommInd .
    Qed.
  End SubstSubstIndexCommInd.
  Section SubstSubstCommInd.
    Definition subst_subst0_Tm_comm_ind := (ind_Tm (fun (s9 : Tm) =>
      (forall (k9 : Hvl) (d6 : (Trace tm)) (s10 : Tm) (s11 : Tm) ,
        ((substTm (weakenTrace d6 k9) s10 (substTm (weakenTrace X0 k9) s11 s9)) =
        (substTm (weakenTrace X0 k9) (substTm d6 s10 s11) (substTm (weakenTrace (XS tm d6) k9) s10 s9))))) (fun (x14 : (Index tm)) =>
      (fun (k9 : Hvl) (d6 : (Trace tm)) (s9 : Tm) (s10 : Tm) =>
        (substTm_substIndex0_commright_ind d6 s9 s10 k9 x14))) (fun (k9 : Hvl) (d6 : (Trace tm)) (s9 : Tm) (s10 : Tm) =>
      eq_refl) (fun (T : Ty) (t : Tm) IHt34 (k9 : Hvl) (d6 : (Trace tm)) (s9 : Tm) (s10 : Tm) =>
      (f_equal2 abs eq_refl (eq_trans (f_equal3 substTm (weakenTrace_append tm d6 k9 (HS tm H0)) eq_refl (f_equal3 substTm (weakenTrace_append tm X0 k9 (HS tm H0)) eq_refl eq_refl)) (eq_trans (IHt34 (HS tm k9) d6 s9 s10) (f_equal3 substTm (eq_sym (weakenTrace_append tm X0 k9 (HS tm H0))) eq_refl (f_equal3 substTm (eq_sym (weakenTrace_append tm (XS tm d6) k9 (HS tm H0))) eq_refl eq_refl)))))) (fun (t1 : Tm) IHt34 (t2 : Tm) IHt35 (k9 : Hvl) (d6 : (Trace tm)) (s9 : Tm) (s10 : Tm) =>
      (f_equal2 app (IHt34 k9 d6 s9 s10) (IHt35 k9 d6 s9 s10))) (fun (t1 : Tm) IHt34 (t2 : Tm) IHt35 (k9 : Hvl) (d6 : (Trace tm)) (s9 : Tm) (s10 : Tm) =>
      (f_equal2 prod (IHt34 k9 d6 s9 s10) (IHt35 k9 d6 s9 s10))) (fun (p : Pat) (t1 : Tm) IHt34 (t2 : Tm) IHt35 (k9 : Hvl) (d6 : (Trace tm)) (s9 : Tm) (s10 : Tm) =>
      (f_equal3 lett eq_refl (IHt34 k9 d6 s9 s10) (eq_trans (f_equal3 substTm (weakenTrace_append tm d6 k9 (bindPat p)) eq_refl (f_equal3 substTm (weakenTrace_append tm X0 k9 (bindPat p)) eq_refl eq_refl)) (eq_trans (IHt35 (appendHvl k9 (bindPat p)) d6 s9 s10) (f_equal3 substTm (eq_sym (weakenTrace_append tm X0 k9 (bindPat p))) eq_refl (f_equal3 substTm (eq_sym (weakenTrace_append tm (XS tm d6) k9 (bindPat p))) eq_refl eq_refl))))))).
  End SubstSubstCommInd.
  Section SubstSubstComm.
    Definition substTm_substTm0_comm (s11 : Tm) : (forall (d6 : (Trace tm)) (s9 : Tm) (s10 : Tm) ,
      ((substTm d6 s9 (substTm X0 s10 s11)) =
      (substTm X0 (substTm d6 s9 s10) (substTm (XS tm d6) s9 s11)))) := (subst_subst0_Tm_comm_ind s11 H0).
  End SubstSubstComm.
  Section WeakenSubst.
    Lemma weakenTm_substTm  :
      (forall (k9 : Hvl) (d6 : (Trace tm)) (s9 : Tm) (s10 : Tm) ,
        ((weakenTm (substTm d6 s9 s10) k9) =
        (substTm (weakenTrace d6 k9) s9 (weakenTm s10 k9)))).
    Proof.
      needleGenericWeakenSubst .
    Qed.
  End WeakenSubst.
  Section WeakenAppend.
    Lemma weakenTy_append  :
      (forall (S0 : Ty) (k9 : Hvl) (k10 : Hvl) ,
        ((weakenTy (weakenTy S0 k9) k10) =
        (weakenTy S0 (appendHvl k9 k10)))).
    Proof.
      needleGenericWeakenAppend .
    Qed.
    Lemma weakenPat_append  :
      (forall (p4 : Pat) (k9 : Hvl) (k10 : Hvl) ,
        ((weakenPat (weakenPat p4 k9) k10) =
        (weakenPat p4 (appendHvl k9 k10)))).
    Proof.
      needleGenericWeakenAppend .
    Qed.
    Lemma weakenTm_append  :
      (forall (s9 : Tm) (k9 : Hvl) (k10 : Hvl) ,
        ((weakenTm (weakenTm s9 k9) k10) =
        (weakenTm s9 (appendHvl k9 k10)))).
    Proof.
      needleGenericWeakenAppend .
    Qed.
  End WeakenAppend.
End SubstSubstInteraction.
 Hint Rewrite substTm_substTm0_comm : interaction.
 Hint Rewrite substTm_substTm0_comm : subst_subst0.
 Hint Rewrite weakenTm_shiftTm : weaken_shift.
 Hint Rewrite weakenTm_substTm : weaken_subst.
Section WellFormed.
  Fixpoint wfindex {a : Namespace} (k9 : Hvl) (i : (Index a)) {struct k9} : Prop :=
    match k9 with
      | (H0) => False
      | (HS b k9) => match (eq_namespace_dec a b) with
        | (left e) => match i with
          | (I0) => True
          | (IS i) => (wfindex k9 i)
        end
        | (right n) => (wfindex k9 i)
      end
    end.
  Inductive wfTy (k9 : Hvl) : Ty -> Prop :=
    | wfTy_tunit :
        (wfTy k9 (tunit))
    | wfTy_tarr {T5 : Ty}
        (wf : (wfTy k9 T5)) {T6 : Ty}
        (wf0 : (wfTy k9 T6)) :
        (wfTy k9 (tarr T5 T6))
    | wfTy_tprod {T7 : Ty}
        (wf : (wfTy k9 T7)) {T8 : Ty}
        (wf0 : (wfTy k9 T8)) :
        (wfTy k9 (tprod T7 T8)).
  Inductive wfPat (k9 : Hvl) : Pat -> Prop :=
    | wfPat_pvar {T5 : Ty}
        (wf : (wfTy k9 T5)) :
        (wfPat k9 (pvar T5))
    | wfPat_pprod {p5 : Pat}
        (wf : (wfPat k9 p5)) {p6 : Pat}
        (wf0 : (wfPat k9 p6)) :
        (wfPat k9 (pprod p5 p6)).
  Inductive wfTm (k9 : Hvl) : Tm -> Prop :=
    | wfTm_var {x17 : (Index tm)}
        (wfi : (wfindex k9 x17)) :
        (wfTm k9 (var x17))
    | wfTm_tt : (wfTm k9 (tt))
    | wfTm_abs {T5 : Ty}
        (wf : (wfTy k9 T5)) {t41 : Tm}
        (wf0 : (wfTm (HS tm k9) t41)) :
        (wfTm k9 (abs T5 t41))
    | wfTm_app {t42 : Tm}
        (wf : (wfTm k9 t42)) {t43 : Tm}
        (wf0 : (wfTm k9 t43)) :
        (wfTm k9 (app t42 t43))
    | wfTm_prod {t44 : Tm}
        (wf : (wfTm k9 t44)) {t45 : Tm}
        (wf0 : (wfTm k9 t45)) :
        (wfTm k9 (prod t44 t45))
    | wfTm_lett {p5 : Pat}
        (wf : (wfPat k9 p5)) {t46 : Tm}
        (wf0 : (wfTm k9 t46)) {t47 : Tm}
        (wf1 : (wfTm (appendHvl k9 (bindPat p5)) t47))
        : (wfTm k9 (lett p5 t46 t47)).
  Scheme ind_wfTy := Induction for wfTy Sort Prop.
  Scheme ind_wfPat := Induction for wfPat Sort Prop.
  Scheme ind_wfTm := Induction for wfTm Sort Prop.
End WellFormed.
Section ShiftWellFormed.
  Inductive shifthvl_tm : (forall (c2 : (Cutoff tm)) (k9 : Hvl) (k10 : Hvl) ,
    Prop) :=
    | shifthvl_tm_here (k9 : Hvl)
        : (shifthvl_tm C0 k9 (HS tm k9))
    | shifthvl_tm_there_tm
        (c2 : (Cutoff tm)) (k9 : Hvl)
        (k10 : Hvl) :
        (shifthvl_tm c2 k9 k10) -> (shifthvl_tm (CS c2) (HS tm k9) (HS tm k10)).
  Lemma weaken_shifthvl_tm  :
    (forall (k9 : Hvl) {c2 : (Cutoff tm)} {k10 : Hvl} {k11 : Hvl} ,
      (shifthvl_tm c2 k10 k11) -> (shifthvl_tm (weakenCutofftm c2 k9) (appendHvl k10 k9) (appendHvl k11 k9))).
  Proof.
    needleGenericWeakenHVarlistInsert .
  Qed.
  Lemma shift_wfindex_tm  :
    (forall (c2 : (Cutoff tm)) (k9 : Hvl) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) (x17 : (Index tm)) ,
      (wfindex k9 x17) -> (wfindex k10 (shiftIndex c2 x17))).
  Proof.
    needleGenericShiftWellFormedIndex .
  Qed.
  Definition shift_wfTy : (forall (k9 : Hvl) ,
    (forall (S0 : Ty) (wf : (wfTy k9 S0)) ,
      (forall (c2 : (Cutoff tm)) (k10 : Hvl) ,
        (shifthvl_tm c2 k9 k10) -> (wfTy k10 S0)))) := (fun (k9 : Hvl) =>
    (ind_wfTy k9 (fun (S0 : Ty) (wf : (wfTy k9 S0)) =>
      (forall (c2 : (Cutoff tm)) (k10 : Hvl) ,
        (shifthvl_tm c2 k9 k10) -> (wfTy k10 S0))) (fun (c2 : (Cutoff tm)) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) =>
      (wfTy_tunit k10)) (fun (T1 : Ty) (wf : (wfTy k9 T1)) IHT1 (T2 : Ty) (wf0 : (wfTy k9 T2)) IHT2 (c2 : (Cutoff tm)) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) =>
      (wfTy_tarr k10 (IHT1 c2 k10 (weaken_shifthvl_tm H0 ins)) (IHT2 c2 k10 (weaken_shifthvl_tm H0 ins)))) (fun (T1 : Ty) (wf : (wfTy k9 T1)) IHT1 (T2 : Ty) (wf0 : (wfTy k9 T2)) IHT2 (c2 : (Cutoff tm)) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) =>
      (wfTy_tprod k10 (IHT1 c2 k10 (weaken_shifthvl_tm H0 ins)) (IHT2 c2 k10 (weaken_shifthvl_tm H0 ins)))))).
  Definition shift_wfPat : (forall (k9 : Hvl) ,
    (forall (p5 : Pat) (wf : (wfPat k9 p5)) ,
      (forall (c2 : (Cutoff tm)) (k10 : Hvl) ,
        (shifthvl_tm c2 k9 k10) -> (wfPat k10 p5)))) := (fun (k9 : Hvl) =>
    (ind_wfPat k9 (fun (p5 : Pat) (wf : (wfPat k9 p5)) =>
      (forall (c2 : (Cutoff tm)) (k10 : Hvl) ,
        (shifthvl_tm c2 k9 k10) -> (wfPat k10 p5))) (fun (T : Ty) (wf : (wfTy k9 T)) (c2 : (Cutoff tm)) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) =>
      (wfPat_pvar k10 (shift_wfTy k9 T wf c2 k10 (weaken_shifthvl_tm H0 ins)))) (fun (p1 : Pat) (wf : (wfPat k9 p1)) IHp1 (p2 : Pat) (wf0 : (wfPat k9 p2)) IHp2 (c2 : (Cutoff tm)) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) =>
      (wfPat_pprod k10 (IHp1 c2 k10 (weaken_shifthvl_tm H0 ins)) (IHp2 c2 k10 (weaken_shifthvl_tm H0 ins)))))).
  Definition shift_wfTm : (forall (k9 : Hvl) ,
    (forall (s9 : Tm) (wf : (wfTm k9 s9)) ,
      (forall (c2 : (Cutoff tm)) (k10 : Hvl) ,
        (shifthvl_tm c2 k9 k10) -> (wfTm k10 (shiftTm c2 s9))))) := (ind_wfTm (fun (k9 : Hvl) (s9 : Tm) (wf : (wfTm k9 s9)) =>
    (forall (c2 : (Cutoff tm)) (k10 : Hvl) ,
      (shifthvl_tm c2 k9 k10) -> (wfTm k10 (shiftTm c2 s9)))) (fun (k9 : Hvl) (x17 : (Index tm)) (wfi : (wfindex k9 x17)) (c2 : (Cutoff tm)) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) =>
    (wfTm_var k10 (shift_wfindex_tm c2 k9 k10 ins x17 wfi))) (fun (k9 : Hvl) (c2 : (Cutoff tm)) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) =>
    (wfTm_tt k10)) (fun (k9 : Hvl) (T : Ty) (wf : (wfTy k9 T)) (t : Tm) (wf0 : (wfTm (HS tm k9) t)) IHt41 (c2 : (Cutoff tm)) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) =>
    (wfTm_abs k10 (shift_wfTy k9 T wf c2 k10 (weaken_shifthvl_tm H0 ins)) (IHt41 (CS c2) (HS tm k10) (weaken_shifthvl_tm (HS tm H0) ins)))) (fun (k9 : Hvl) (t1 : Tm) (wf : (wfTm k9 t1)) IHt41 (t2 : Tm) (wf0 : (wfTm k9 t2)) IHt42 (c2 : (Cutoff tm)) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) =>
    (wfTm_app k10 (IHt41 c2 k10 (weaken_shifthvl_tm H0 ins)) (IHt42 c2 k10 (weaken_shifthvl_tm H0 ins)))) (fun (k9 : Hvl) (t1 : Tm) (wf : (wfTm k9 t1)) IHt41 (t2 : Tm) (wf0 : (wfTm k9 t2)) IHt42 (c2 : (Cutoff tm)) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) =>
    (wfTm_prod k10 (IHt41 c2 k10 (weaken_shifthvl_tm H0 ins)) (IHt42 c2 k10 (weaken_shifthvl_tm H0 ins)))) (fun (k9 : Hvl) (p : Pat) (wf : (wfPat k9 p)) (t1 : Tm) (wf0 : (wfTm k9 t1)) IHt41 (t2 : Tm) (wf1 : (wfTm (appendHvl k9 (bindPat p)) t2)) IHt42 (c2 : (Cutoff tm)) (k10 : Hvl) (ins : (shifthvl_tm c2 k9 k10)) =>
    (wfTm_lett k10 (shift_wfPat k9 p wf c2 k10 (weaken_shifthvl_tm H0 ins)) (IHt41 c2 k10 (weaken_shifthvl_tm H0 ins)) (IHt42 (weakenCutofftm c2 (bindPat p)) (appendHvl k10 (bindPat p)) (weaken_shifthvl_tm (bindPat p) ins))))).
End ShiftWellFormed.
 Hint Resolve shift_wfindex_tm : infra.
 Hint Resolve shift_wfindex_tm : shift.
 Hint Resolve shift_wfindex_tm : shift_wf.
 Hint Resolve shift_wfindex_tm : wf.
 Hint Resolve shift_wfPat shift_wfTm shift_wfTy : infra.
 Hint Resolve shift_wfPat shift_wfTm shift_wfTy : shift.
 Hint Resolve shift_wfPat shift_wfTm shift_wfTy : shift_wf.
 Hint Resolve shift_wfPat shift_wfTm shift_wfTy : wf.
 Hint Constructors shifthvl_tm : infra.
 Hint Constructors shifthvl_tm : shift.
 Hint Constructors shifthvl_tm : shift_wf.
 Hint Constructors shifthvl_tm : wf.
 Hint Resolve weaken_shifthvl_tm : infra.
 Hint Resolve weaken_shifthvl_tm : shift.
 Hint Resolve weaken_shifthvl_tm : shift_wf.
 Hint Resolve weaken_shifthvl_tm : weaken.
 Hint Resolve weaken_shifthvl_tm : wf.
Section SubstWellFormed.
  Inductive substhvl_tm (k9 : Hvl) : (forall (d6 : (Trace tm)) (k10 : Hvl) (k11 : Hvl) ,
    Prop) :=
    | substhvl_tm_here :
        (substhvl_tm k9 X0 (HS tm k9) k9)
    | substhvl_tm_there_tm
        {d6 : (Trace tm)} {k10 : Hvl}
        {k11 : Hvl} :
        (substhvl_tm k9 d6 k10 k11) -> (substhvl_tm k9 (XS tm d6) (HS tm k10) (HS tm k11)).
  Lemma weaken_substhvl_tm  :
    (forall {k10 : Hvl} (k9 : Hvl) {d6 : (Trace tm)} {k11 : Hvl} {k12 : Hvl} ,
      (substhvl_tm k10 d6 k11 k12) -> (substhvl_tm k10 (weakenTrace d6 k9) (appendHvl k11 k9) (appendHvl k12 k9))).
  Proof.
    needleGenericWeakenSubstHvl .
  Qed.
  Lemma substhvl_tm_wfindex_tm {k13 : Hvl} {s9 : Tm} (wft : (wfTm k13 s9)) :
    (forall {d6 : (Trace tm)} {k14 : Hvl} {k15 : Hvl} ,
      (substhvl_tm k13 d6 k14 k15) -> (forall {x17 : (Index tm)} ,
        (wfindex k14 x17) -> (wfTm k15 (substIndex d6 s9 x17)))).
  Proof.
    needleGenericSubstHvlWfIndexHom .
  Qed.
  Definition substhvl_tm_wfTy {k13 : Hvl} : (forall (k14 : Hvl) ,
    (forall (S1 : Ty) (wf0 : (wfTy k14 S1)) ,
      (forall {d6 : (Trace tm)} {k15 : Hvl} ,
        (substhvl_tm k13 d6 k14 k15) -> (wfTy k15 S1)))) := (fun (k14 : Hvl) =>
    (ind_wfTy k14 (fun (S1 : Ty) (wf0 : (wfTy k14 S1)) =>
      (forall {d6 : (Trace tm)} {k15 : Hvl} ,
        (substhvl_tm k13 d6 k14 k15) -> (wfTy k15 S1))) (fun {d6 : (Trace tm)} {k15 : Hvl} (del : (substhvl_tm k13 d6 k14 k15)) =>
      (wfTy_tunit k15)) (fun (T1 : Ty) (wf0 : (wfTy k14 T1)) IHT1 (T2 : Ty) (wf1 : (wfTy k14 T2)) IHT2 {d6 : (Trace tm)} {k15 : Hvl} (del : (substhvl_tm k13 d6 k14 k15)) =>
      (wfTy_tarr k15 (IHT1 (weakenTrace d6 H0) k15 (weaken_substhvl_tm H0 del)) (IHT2 (weakenTrace d6 H0) k15 (weaken_substhvl_tm H0 del)))) (fun (T1 : Ty) (wf0 : (wfTy k14 T1)) IHT1 (T2 : Ty) (wf1 : (wfTy k14 T2)) IHT2 {d6 : (Trace tm)} {k15 : Hvl} (del : (substhvl_tm k13 d6 k14 k15)) =>
      (wfTy_tprod k15 (IHT1 (weakenTrace d6 H0) k15 (weaken_substhvl_tm H0 del)) (IHT2 (weakenTrace d6 H0) k15 (weaken_substhvl_tm H0 del)))))).
  Definition substhvl_tm_wfPat {k13 : Hvl} : (forall (k14 : Hvl) ,
    (forall (p6 : Pat) (wf0 : (wfPat k14 p6)) ,
      (forall {d6 : (Trace tm)} {k15 : Hvl} ,
        (substhvl_tm k13 d6 k14 k15) -> (wfPat k15 p6)))) := (fun (k14 : Hvl) =>
    (ind_wfPat k14 (fun (p6 : Pat) (wf0 : (wfPat k14 p6)) =>
      (forall {d6 : (Trace tm)} {k15 : Hvl} ,
        (substhvl_tm k13 d6 k14 k15) -> (wfPat k15 p6))) (fun (T : Ty) (wf0 : (wfTy k14 T)) {d6 : (Trace tm)} {k15 : Hvl} (del : (substhvl_tm k13 d6 k14 k15)) =>
      (wfPat_pvar k15 (substhvl_tm_wfTy k14 T wf0 (weaken_substhvl_tm H0 del)))) (fun (p1 : Pat) (wf0 : (wfPat k14 p1)) IHp1 (p2 : Pat) (wf1 : (wfPat k14 p2)) IHp2 {d6 : (Trace tm)} {k15 : Hvl} (del : (substhvl_tm k13 d6 k14 k15)) =>
      (wfPat_pprod k15 (IHp1 (weakenTrace d6 H0) k15 (weaken_substhvl_tm H0 del)) (IHp2 (weakenTrace d6 H0) k15 (weaken_substhvl_tm H0 del)))))).
  Definition substhvl_tm_wfTm {k13 : Hvl} {s9 : Tm} (wf : (wfTm k13 s9)) : (forall (k14 : Hvl) ,
    (forall (s10 : Tm) (wf0 : (wfTm k14 s10)) ,
      (forall {d6 : (Trace tm)} {k15 : Hvl} ,
        (substhvl_tm k13 d6 k14 k15) -> (wfTm k15 (substTm d6 s9 s10))))) := (ind_wfTm (fun (k14 : Hvl) (s10 : Tm) (wf0 : (wfTm k14 s10)) =>
    (forall {d6 : (Trace tm)} {k15 : Hvl} ,
      (substhvl_tm k13 d6 k14 k15) -> (wfTm k15 (substTm d6 s9 s10)))) (fun (k14 : Hvl) {x17 : (Index tm)} (wfi : (wfindex k14 x17)) {d6 : (Trace tm)} {k15 : Hvl} (del : (substhvl_tm k13 d6 k14 k15)) =>
    (substhvl_tm_wfindex_tm wf del wfi)) (fun (k14 : Hvl) {d6 : (Trace tm)} {k15 : Hvl} (del : (substhvl_tm k13 d6 k14 k15)) =>
    (wfTm_tt k15)) (fun (k14 : Hvl) (T : Ty) (wf0 : (wfTy k14 T)) (t : Tm) (wf1 : (wfTm (HS tm k14) t)) IHt41 {d6 : (Trace tm)} {k15 : Hvl} (del : (substhvl_tm k13 d6 k14 k15)) =>
    (wfTm_abs k15 (substhvl_tm_wfTy k14 T wf0 (weaken_substhvl_tm H0 del)) (IHt41 (weakenTrace d6 (HS tm H0)) (HS tm k15) (weaken_substhvl_tm (HS tm H0) del)))) (fun (k14 : Hvl) (t1 : Tm) (wf0 : (wfTm k14 t1)) IHt41 (t2 : Tm) (wf1 : (wfTm k14 t2)) IHt42 {d6 : (Trace tm)} {k15 : Hvl} (del : (substhvl_tm k13 d6 k14 k15)) =>
    (wfTm_app k15 (IHt41 (weakenTrace d6 H0) k15 (weaken_substhvl_tm H0 del)) (IHt42 (weakenTrace d6 H0) k15 (weaken_substhvl_tm H0 del)))) (fun (k14 : Hvl) (t1 : Tm) (wf0 : (wfTm k14 t1)) IHt41 (t2 : Tm) (wf1 : (wfTm k14 t2)) IHt42 {d6 : (Trace tm)} {k15 : Hvl} (del : (substhvl_tm k13 d6 k14 k15)) =>
    (wfTm_prod k15 (IHt41 (weakenTrace d6 H0) k15 (weaken_substhvl_tm H0 del)) (IHt42 (weakenTrace d6 H0) k15 (weaken_substhvl_tm H0 del)))) (fun (k14 : Hvl) (p : Pat) (wf0 : (wfPat k14 p)) (t1 : Tm) (wf1 : (wfTm k14 t1)) IHt41 (t2 : Tm) (wf2 : (wfTm (appendHvl k14 (bindPat p)) t2)) IHt42 {d6 : (Trace tm)} {k15 : Hvl} (del : (substhvl_tm k13 d6 k14 k15)) =>
    (wfTm_lett k15 (substhvl_tm_wfPat k14 p wf0 (weaken_substhvl_tm H0 del)) (IHt41 (weakenTrace d6 H0) k15 (weaken_substhvl_tm H0 del)) (IHt42 (weakenTrace d6 (bindPat p)) (appendHvl k15 (bindPat p)) (weaken_substhvl_tm (bindPat p) del))))).
End SubstWellFormed.
 Hint Resolve substhvl_tm_wfindex_tm : infra.
 Hint Resolve substhvl_tm_wfindex_tm : subst.
 Hint Resolve substhvl_tm_wfindex_tm : subst_wf.
 Hint Resolve substhvl_tm_wfindex_tm : wf.
 Hint Resolve substhvl_tm_wfPat substhvl_tm_wfTm substhvl_tm_wfTy : infra.
 Hint Resolve substhvl_tm_wfPat substhvl_tm_wfTm substhvl_tm_wfTy : subst.
 Hint Resolve substhvl_tm_wfPat substhvl_tm_wfTm substhvl_tm_wfTy : subst_wf.
 Hint Resolve substhvl_tm_wfPat substhvl_tm_wfTm substhvl_tm_wfTy : wf.
 Hint Constructors substhvl_tm : infra.
 Hint Constructors substhvl_tm : subst.
 Hint Constructors substhvl_tm : subst_wf.
 Hint Constructors substhvl_tm : wf.
Fixpoint subhvl_tm (k13 : Hvl) {struct k13} : Prop :=
  match k13 with
    | (H0) => True
    | (HS a k13) => match a with
      | (tm) => (subhvl_tm k13)
    end
  end.
Lemma subhvl_tm_append  :
  (forall (k13 : Hvl) (k14 : Hvl) ,
    (subhvl_tm k13) -> (subhvl_tm k14) -> (subhvl_tm (appendHvl k13 k14))).
Proof.
  needleGenericSubHvlAppend .
Qed.
 Hint Resolve subhvl_tm_append : infra.
 Hint Resolve subhvl_tm_append : wf.
Lemma wfPat_strengthen_subhvl_tm  :
  (forall (k10 : Hvl) (k9 : Hvl) (p5 : Pat) ,
    (subhvl_tm k10) -> (wfPat (appendHvl k9 k10) (weakenPat p5 k10)) -> (wfPat k9 p5)).
Proof.
  needleGenericWellformedStrengthen .
Qed.
Lemma wfTy_strengthen_subhvl_tm  :
  (forall (k12 : Hvl) (k11 : Hvl) (S0 : Ty) ,
    (subhvl_tm k12) -> (wfTy (appendHvl k11 k12) (weakenTy S0 k12)) -> (wfTy k11 S0)).
Proof.
  needleGenericWellformedStrengthen .
Qed.
 Hint Extern 2 ((wfPat _ _)) => match goal with
  | H : (wfPat (appendHvl _ _) (weakenPat _ _)) |- _ => apply (wfPat_strengthen_subhvl_tm) in H
end : infra wf.
 Hint Extern 2 ((wfTy _ _)) => match goal with
  | H0 : (wfTy (appendHvl _ _) (weakenTy _ _)) |- _ => apply (wfTy_strengthen_subhvl_tm) in H0
end : infra wf.
Section Context.
  Inductive Env : Type :=
    | empty
    | evar (G : Env) (T : Ty).
  Fixpoint appendEnv (G : Env) (G0 : Env) : Env :=
    match G0 with
      | (empty) => G
      | (evar G1 T) => (evar (appendEnv G G1) T)
    end.
  Fixpoint domainEnv (G : Env) : Hvl :=
    match G with
      | (empty) => H0
      | (evar G0 T) => (HS tm (domainEnv G0))
    end.
  Lemma appendEnv_assoc  :
    (forall (G : Env) (G0 : Env) (G1 : Env) ,
      ((appendEnv G (appendEnv G0 G1)) =
      (appendEnv (appendEnv G G0) G1))).
  Proof.
    needleGenericAppendEnvAssoc .
  Qed.
  Lemma domainEnv_appendEnv  :
    (forall (G : Env) (G0 : Env) ,
      ((domainEnv (appendEnv G G0)) =
      (appendHvl (domainEnv G) (domainEnv G0)))).
  Proof.
    needleGenericDomainEnvAppendEnv .
  Qed.
  Fixpoint shiftEnv (c2 : (Cutoff tm)) (G : Env) : Env :=
    match G with
      | (empty) => empty
      | (evar G0 T) => (evar (shiftEnv c2 G0) T)
    end.
  Fixpoint substEnv (d6 : (Trace tm)) (s9 : Tm) (G : Env) : Env :=
    match G with
      | (empty) => empty
      | (evar G0 T) => (evar (substEnv d6 s9 G0) T)
    end.
  Lemma domainEnv_shiftEnv  :
    (forall (c2 : (Cutoff tm)) (G : Env) ,
      ((domainEnv (shiftEnv c2 G)) =
      (domainEnv G))).
  Proof.
    needleGenericDomainEnvShiftEnv .
  Qed.
  Lemma domainEnv_substEnv  :
    (forall (d6 : (Trace tm)) (s9 : Tm) (G : Env) ,
      ((domainEnv (substEnv d6 s9 G)) =
      (domainEnv G))).
  Proof.
    needleGenericDomainEnvSubstEnv .
  Qed.
End Context.
 Hint Rewrite domainEnv_appendEnv : interaction.
 Hint Rewrite domainEnv_appendEnv : env_domain_append.
Section ContextStuff.
  Section ShiftEnvAppendEnv.
    Lemma shiftEnv_appendEnv  :
      (forall (c2 : (Cutoff tm)) (G : Env) (G0 : Env) ,
        ((shiftEnv c2 (appendEnv G G0)) =
        (appendEnv (shiftEnv c2 G) (shiftEnv (weakenCutofftm c2 (domainEnv G)) G0)))).
    Proof.
      needleGenericShiftEnvAppendEnv .
    Qed.
  End ShiftEnvAppendEnv.
  Section SubstEnvAppendEnv.
    Lemma substEnv_appendEnv  :
      (forall (d6 : (Trace tm)) (s9 : Tm) (G : Env) (G0 : Env) ,
        ((substEnv d6 s9 (appendEnv G G0)) =
        (appendEnv (substEnv d6 s9 G) (substEnv (weakenTrace d6 (domainEnv G)) s9 G0)))).
    Proof.
      needleGenericSubstEnvAppendEnv .
    Qed.
  End SubstEnvAppendEnv.
  Section Lookups.
    Inductive lookup_evar : Env -> (Index tm) -> Ty -> Prop :=
      | lookup_evar_here {G : Env}
          {T5 : Ty} :
          (wfTy (domainEnv G) T5) -> (lookup_evar (evar G T5) I0 T5)
      | lookup_evar_there_evar
          {G : Env} {x17 : (Index tm)}
          {T5 : Ty} {T6 : Ty} :
          (lookup_evar G x17 T5) -> (lookup_evar (evar G T6) (IS x17) T5).
    Lemma lookup_evar_inversion_here  :
      (forall (G : Env) (S1 : Ty) (S2 : Ty) ,
        (lookup_evar (evar G S1) I0 S2) -> (S1 =
        S2)).
    Proof.
      needleGenericLookupInversion .
    Qed.
    Lemma lookup_evar_functional  :
      (forall {G : Env} {x17 : (Index tm)} ,
        (forall {S1 : Ty} ,
          (lookup_evar G x17 S1) -> (forall {S2 : Ty} ,
            (lookup_evar G x17 S2) -> (S1 =
            S2)))).
    Proof.
      needleGenericLookupFunctional .
    Qed.
    Lemma lookup_evar_wf  :
      (forall {G : Env} {x17 : (Index tm)} {S1 : Ty} ,
        (lookup_evar G x17 S1) -> (wfTy (domainEnv G) S1)).
    Proof.
      needleGenericLookupWellformedData .
    Qed.
    Lemma weaken_lookup_evar  :
      (forall {G : Env} (G0 : Env) {x17 : (Index tm)} {T5 : Ty} ,
        (lookup_evar G x17 T5) -> (lookup_evar (appendEnv G G0) (weakenIndextm x17 (domainEnv G0)) (weakenTy T5 (domainEnv G0)))).
    Proof.
      needleGenericWeakenLookup .
    Qed.
    Lemma lookup_evar_wfindex  :
      (forall {G : Env} {x17 : (Index tm)} {S1 : Ty} ,
        (lookup_evar G x17 S1) -> (wfindex (domainEnv G) x17)).
    Proof.
      needleGenericLookupWellformedIndex .
    Qed.
  End Lookups.
  Inductive shift_evar : (Cutoff tm) -> Env -> Env -> Prop :=
    | shift_evar_here {G : Env}
        {T5 : Ty} :
        (shift_evar C0 G (evar G T5))
    | shiftevar_there_evar
        {c2 : (Cutoff tm)} {G : Env}
        {G0 : Env} {T : Ty} :
        (shift_evar c2 G G0) -> (shift_evar (CS c2) (evar G T) (evar G0 T)).
  Lemma weaken_shift_evar  :
    (forall (G : Env) {c2 : (Cutoff tm)} {G0 : Env} {G1 : Env} ,
      (shift_evar c2 G0 G1) -> (shift_evar (weakenCutofftm c2 (domainEnv G)) (appendEnv G0 G) (appendEnv G1 G))).
  Proof.
    needleGenericWeakenInsertEnv .
  Qed.
  Lemma shift_evar_shifthvl_tm  :
    (forall {c2 : (Cutoff tm)} {G : Env} {G0 : Env} ,
      (shift_evar c2 G G0) -> (shifthvl_tm c2 (domainEnv G) (domainEnv G0))).
  Proof.
    needleGenericInsertEnvInsertHvl .
  Qed.
  Inductive subst_evar (G : Env) (T5 : Ty) (s9 : Tm) : (Trace tm) -> Env -> Env -> Prop :=
    | subst_evar_here :
        (subst_evar G T5 s9 X0 (evar G T5) G)
    | subst_evar_there_evar
        {d6 : (Trace tm)} {G0 : Env}
        {G1 : Env} {T : Ty} :
        (subst_evar G T5 s9 d6 G0 G1) -> (subst_evar G T5 s9 (XS tm d6) (evar G0 T) (evar G1 T)).
  Lemma weaken_subst_evar {G : Env} {T5 : Ty} {s9 : Tm} :
    (forall (G0 : Env) {d6 : (Trace tm)} {G1 : Env} {G2 : Env} ,
      (subst_evar G T5 s9 d6 G1 G2) -> (subst_evar G T5 s9 (weakenTrace d6 (domainEnv G0)) (appendEnv G1 G0) (appendEnv G2 G0))).
  Proof.
    needleGenericWeakenSubstEnv .
  Qed.
  Lemma subst_evar_substhvl_tm {G : Env} {s9 : Tm} {T5 : Ty} :
    (forall {d6 : (Trace tm)} {G0 : Env} {G1 : Env} ,
      (subst_evar G T5 s9 d6 G0 G1) -> (substhvl_tm (domainEnv G) d6 (domainEnv G0) (domainEnv G1))).
  Proof.
    needleGenericSubstEnvSubstHvl .
  Qed.
End ContextStuff.
 Hint Constructors lookup_evar : infra.
 Hint Constructors lookup_evar : lookup.
 Hint Constructors lookup_evar : shift.
 Hint Constructors lookup_evar : subst.
 Hint Resolve weaken_lookup_evar : infra.
 Hint Resolve weaken_lookup_evar : lookup.
 Hint Resolve weaken_lookup_evar : shift.
 Hint Resolve weaken_lookup_evar : weaken.
Lemma weaken_lookup_evar_here  :
  (forall {G : Env} (G0 : Env) {T5 : Ty} (wf : (wfTy (domainEnv G) T5)) ,
    (lookup_evar (appendEnv (evar G T5) G0) (weakenIndextm I0 (domainEnv G0)) (weakenTy T5 (domainEnv G0)))).
Proof.
  eauto with lookup .
Qed.
 Hint Constructors wfPat wfTm wfTy : infra.
 Hint Constructors wfPat wfTm wfTy : wf.
 Hint Extern 10 ((wfPat _ _)) => autorewrite with env_domain_append in *  : infra wf.
 Hint Extern 10 ((wfTm _ _)) => autorewrite with env_domain_append in *  : infra wf.
 Hint Extern 10 ((wfTy _ _)) => autorewrite with env_domain_append in *  : infra wf.
 Hint Extern 2 ((wfTy _ _)) => match goal with
  | H : (wfTy _ (tunit)) |- _ => inversion H; subst; clear H
  | H : (wfTy _ (tarr _ _)) |- _ => inversion H; subst; clear H
  | H : (wfTy _ (tprod _ _)) |- _ => inversion H; subst; clear H
end : infra wf.
 Hint Extern 2 ((wfPat _ _)) => match goal with
  | H : (wfPat _ (pvar _)) |- _ => inversion H; subst; clear H
  | H : (wfPat _ (pprod _ _)) |- _ => inversion H; subst; clear H
end : infra wf.
 Hint Extern 2 ((wfTm _ _)) => match goal with
  | H : (wfTm _ (var _)) |- _ => inversion H; subst; clear H
  | H : (wfTm _ (tt)) |- _ => inversion H; subst; clear H
  | H : (wfTm _ (abs _ _)) |- _ => inversion H; subst; clear H
  | H : (wfTm _ (app _ _)) |- _ => inversion H; subst; clear H
  | H : (wfTm _ (prod _ _)) |- _ => inversion H; subst; clear H
  | H : (wfTm _ (lett _ _ _)) |- _ => inversion H; subst; clear H
end : infra wf.
 Hint Resolve lookup_evar_wf : infra.
 Hint Resolve lookup_evar_wf : wf.
 Hint Resolve lookup_evar_wfindex : infra.
 Hint Resolve lookup_evar_wfindex : lookup.
 Hint Resolve lookup_evar_wfindex : wf.
 Hint Constructors shift_evar : infra.
 Hint Constructors shift_evar : shift.
 Hint Constructors shift_evar : subst.
 Hint Resolve weaken_shift_evar : infra.
 Hint Resolve weaken_shift_evar : shift.
 Hint Resolve shift_evar_shifthvl_tm : infra.
 Hint Resolve shift_evar_shifthvl_tm : shift.
 Hint Resolve shift_evar_shifthvl_tm : shift_wf.
 Hint Resolve shift_evar_shifthvl_tm : wf.
 Hint Constructors subst_evar : infra.
 Hint Constructors subst_evar : subst.
 Hint Resolve weaken_subst_evar : infra.
 Hint Resolve weaken_subst_evar : subst.
 Hint Resolve subst_evar_substhvl_tm : infra.
 Hint Resolve subst_evar_substhvl_tm : subst.
 Hint Resolve subst_evar_substhvl_tm : subst_wf.
 Hint Resolve subst_evar_substhvl_tm : wf.
 Hint Resolve subst_evar_substhvl_tm : substenv_substhvl.
Lemma shift_evar_lookup_evar  :
  (forall {c2 : (Cutoff tm)} {G : Env} {G0 : Env} (ins : (shift_evar c2 G G0)) {x17 : (Index tm)} {T5 : Ty} ,
    (lookup_evar G x17 T5) -> (lookup_evar G0 (shiftIndex c2 x17) T5)).
Proof.
  needleGenericInsertLookup .
Qed.
 Hint Resolve shift_evar_lookup_evar : infra.
 Hint Resolve shift_evar_lookup_evar : lookup.
 Hint Resolve shift_evar_lookup_evar : shift.
Fixpoint size_Ty (S0 : Ty) {struct S0} : nat :=
  match S0 with
    | (tunit) => 1
    | (tarr T1 T2) => (plus 1 (plus (size_Ty T1) (size_Ty T2)))
    | (tprod T0 T3) => (plus 1 (plus (size_Ty T0) (size_Ty T3)))
  end.
Fixpoint size_Pat (p : Pat) {struct p} : nat :=
  match p with
    | (pvar T) => (plus 1 (size_Ty T))
    | (pprod p1 p2) => (plus 1 (plus (size_Pat p1) (size_Pat p2)))
  end.
Fixpoint size_Tm (s : Tm) {struct s} : nat :=
  match s with
    | (var x) => 1
    | (tt) => 1
    | (abs T t) => (plus 1 (plus (size_Ty T) (size_Tm t)))
    | (app t1 t2) => (plus 1 (plus (size_Tm t1) (size_Tm t2)))
    | (prod t0 t3) => (plus 1 (plus (size_Tm t0) (size_Tm t3)))
    | (lett p t4 t5) => (plus 1 (plus (size_Pat p) (plus (size_Tm t4) (size_Tm t5))))
  end.
Lemma shift_size_Tm  :
  (forall (s9 : Tm) (c1 : (Cutoff tm)) ,
    ((size_Tm (shiftTm c1 s9)) =
    (size_Tm s9))).
Proof.
  apply_mutual_ind ind_Tm.
  - intros x15 c1.
  reflexivity.
  - intros c2; simpl; apply ((f_equal S)); reflexivity.
  - intros T4 t34 IHt34.
  intros c2; simpl; apply ((f_equal S)); repeat (apply ((f_equal2 plus))).
  + reflexivity.
  + exact ((IHt34 (CS c2))).
  - intros t35 IHt35 t36 IHt36.
  intros c2; simpl; apply ((f_equal S)); repeat (apply ((f_equal2 plus))).
  + exact ((IHt35 c2)).
  + exact ((IHt36 c2)).
  - intros t37 IHt37 t38 IHt38.
  intros c2; simpl; apply ((f_equal S)); repeat (apply ((f_equal2 plus))).
  + exact ((IHt37 c2)).
  + exact ((IHt38 c2)).
  - intros p4 t39 IHt39 t40 IHt40.
  intros c2; simpl; apply ((f_equal S)); repeat (apply ((f_equal2 plus))).
  + reflexivity.
  + exact ((IHt39 c2)).
  + exact ((IHt40 (weakenCutofftm c2 (bindPat p4)))).
Qed.

 Hint Rewrite shift_size_Tm : interaction.
 Hint Rewrite shift_size_Tm : shift_size.
Lemma weaken_size_Pat  :
  (forall (k9 : Hvl) (p5 : Pat) ,
    ((size_Pat (weakenPat p5 k9)) =
    (size_Pat p5))).
Proof.
  needleGenericWeakenSize .
Qed.
Lemma weaken_size_Tm  :
  (forall (k9 : Hvl) (s9 : Tm) ,
    ((size_Tm (weakenTm s9 k9)) =
    (size_Tm s9))).
Proof.
  needleGenericWeakenSize .
Qed.
Lemma weaken_size_Ty  :
  (forall (k9 : Hvl) (S0 : Ty) ,
    ((size_Ty (weakenTy S0 k9)) =
    (size_Ty S0))).
Proof.
  needleGenericWeakenSize .
Qed.
 Hint Rewrite weaken_size_Pat weaken_size_Tm weaken_size_Ty : interaction.
 Hint Rewrite weaken_size_Pat weaken_size_Tm weaken_size_Ty : weaken_size.


(* Distributed under the terms of the MIT license. *)
From MetaCoq.Utils Require Import utils.
From MetaCoq.Common Require Import config.
From MetaCoq.Template Require Import Ast AstUtils Induction UnivSubst.
From Equations Require Import Equations.
Require Import ssreflect ssrbool.

(** * Well-formedness of terms and types in typing derivations

  The internal representation of terms is not canonical, so we show
  that only well-formed terms and types can appear in typing derivations
  and the global context.

  The invariants are:
  - Application nodes have always at least one argument, and they cannot
    be nested (keeping terms in "spine" representation).
  - Each `Case` refers to a declared inductive in the environment, and
    the predicate context and branches contexts have lengths that match
    the inductive declaration. This eases the proof of translation to PCUIC,
    in particular reduction on well-formed terms in Template translate to
    reductions in PCUIC, without further typing assumptions.
*)

(** Well-formed terms: invariants which are not ensured by the OCaml type system *)

Notation wf_nactx :=
  (All2 (fun x y => eq_binder_annot x (decl_name y))).

Inductive wf {Σ} : term -> Type :=
| wf_tRel n : wf (tRel n)
| wf_tVar id : wf (tVar id)
| wf_tEvar n l : All wf l -> wf (tEvar n l)
| wf_tSort u : wf (tSort u)
| wf_tCast t k t' : wf t -> wf t' -> wf (tCast t k t')
| wf_tProd na t b : wf t -> wf b -> wf (tProd na t b)
| wf_tLambda na t b : wf t -> wf b -> wf (tLambda na t b)
| wf_tLetIn na t b b' : wf t -> wf b -> wf b' -> wf (tLetIn na t b b')
| wf_tApp t u : isApp t = false -> u <> nil -> wf t -> All wf u -> wf (tApp t u)
| wf_tConst k u : wf (tConst k u)
| wf_tInd i u : wf (tInd i u)
| wf_tConstruct i k u : wf (tConstruct i k u)
| wf_tCase ci p c brs mdecl idecl :
    declared_inductive Σ ci.(ci_ind) mdecl idecl ->
    ci.(ci_npar) = mdecl.(ind_npars) ->
    wf_nactx p.(pcontext) (ind_predicate_context ci.(ci_ind) mdecl idecl) ->
    #|pparams p| = context_assumptions (ind_params mdecl) ->
    All wf (pparams p) -> wf (preturn p) ->
    wf c ->
    All2 (fun cdecl br =>
      wf_nactx br.(bcontext) (cstr_branch_context ci.(ci_ind) mdecl cdecl) ×
      wf (bbody br)) idecl.(ind_ctors) brs ->
    wf (tCase ci p c brs)
| wf_tProj p t :
  wf t ->
  wf (tProj p t)
| wf_tFix mfix k : All (fun def => wf def.(dtype) × wf def.(dbody)) mfix ->
                   wf (tFix mfix k)
| wf_tCoFix mfix k : All (fun def => wf def.(dtype) × wf def.(dbody)) mfix -> wf (tCoFix mfix k)
| wf_tInt i : wf (tInt i)
| wf_tFloat f : wf (tFloat f).
Arguments wf : clear implicits.
Derive Signature for wf.

(** * Inversion lemmas for the well-formedness judgement *)

Definition wf_Inv Σ (t : term) : Type :=
  match t with
  | tRel _ | tVar _ | tSort _ => unit
  | tInt _ | tFloat _ => unit
  | tEvar n l => All (wf Σ) l
  | tCast t k t' => wf Σ t * wf Σ t'
  | tProd na t b => wf Σ t * wf Σ b
  | tLambda na t b => wf Σ t * wf Σ b
  | tLetIn na t b b' => wf Σ t * wf Σ b * wf Σ b'
  | tApp t u => (isApp t = false) * (u <> nil) * wf Σ t * All (wf Σ) u
  | tConst c _ => unit
  | tInd ind _ => unit
  | tConstruct ind k _ => unit
  | tCase ci p c brs =>
    ∑ mdecl idecl,
    [× declared_inductive Σ ci.(ci_ind) mdecl idecl,
       ci.(ci_npar) = mdecl.(ind_npars),
       wf_nactx p.(pcontext) (ind_predicate_context ci.(ci_ind) mdecl idecl),
       #|pparams p| = context_assumptions (ind_params mdecl),
       All (wf Σ) (pparams p),
       wf Σ (preturn p),
       wf Σ c &
       All2 (fun cdecl br =>
         wf_nactx br.(bcontext) (cstr_branch_context ci.(ci_ind) mdecl cdecl) ×
        wf Σ (bbody br)) idecl.(ind_ctors) brs]
  | tProj p t => wf Σ t
  | tFix mfix k => All (fun def => wf Σ def.(dtype) * wf Σ def.(dbody)) mfix
  | tCoFix mfix k => All (fun def => wf Σ def.(dtype) * wf Σ def.(dbody)) mfix
  end.

Lemma wf_inv {Σ t} (w : wf Σ t) : wf_Inv Σ t.
Proof.
  induction w; simpl; eauto; intuition eauto; try constructor.
Defined.

Lemma lift_to_list Σ (P : term -> Prop) : (forall t, wf Σ t -> P t) -> forall l, All (wf Σ) l -> Forall P l.
Proof.
  intros IH.
  fix lift_to_list 1.
  destruct l; constructor.
  apply IH. now inversion_clear X.
  apply lift_to_list. now inversion_clear X.
Defined.

Lemma lift_to_wf_list Σ (P : term -> Type) : forall l, All (fun t => wf Σ t -> P t) l ->
  All (wf Σ) l -> All P l.
Proof.
  induction 1. constructor.
  inversion_clear 1.
  constructor; auto.
Qed.

Ltac inv H := inversion_clear H.

Lemma term_wf_forall_list_ind Σ :
  forall P : term -> Type,
    (forall n : nat, P (tRel n)) ->
    (forall i : ident, P (tVar i)) ->
    (forall (n : nat) (l : list term), All P l -> P (tEvar n l)) ->
    (forall s, P (tSort s)) ->
    (forall t : term, P t -> forall (c : cast_kind) (t0 : term), P t0 -> P (tCast t c t0)) ->
    (forall (n : aname) (t : term), P t -> forall t0 : term, P t0 -> P (tProd n t t0)) ->
    (forall (n : aname) (t : term), P t -> forall t0 : term, P t0 -> P (tLambda n t t0)) ->
    (forall (n : aname) (t : term),
        P t -> forall t0 : term, P t0 -> forall t1 : term, P t1 -> P (tLetIn n t t0 t1)) ->
    (forall t : term, isApp t = false -> wf Σ t -> P t ->
                      forall l : list term, l <> nil -> All (wf Σ) l -> All P l -> P (tApp t l)) ->
    (forall s (u : list Level.t), P (tConst s u)) ->
    (forall (i : inductive) (u : list Level.t), P (tInd i u)) ->
    (forall (i : inductive) (n : nat) (u : list Level.t),
      P (tConstruct i n u)) ->
    (forall (ci : case_info) (p : predicate term) mdecl idecl,
        declared_inductive Σ ci.(ci_ind) mdecl idecl ->
        ci.(ci_npar) = mdecl.(ind_npars) ->
        #|pparams p| = context_assumptions (ind_params mdecl) ->
        wf_nactx p.(pcontext) (ind_predicate_context ci.(ci_ind) mdecl idecl) ->
        tCasePredProp P P p -> forall t : term, P t -> forall l : list (branch term),
        All2 (fun cdecl br =>
          wf_nactx br.(bcontext) (cstr_branch_context ci.(ci_ind) mdecl cdecl) ×
          P (bbody br)) idecl.(ind_ctors) l -> P (tCase ci p t l)) ->
    (forall (s : projection) (t : term),

      P t -> P (tProj s t)) ->
    (forall (m : mfixpoint term) (n : nat), tFixProp P P m -> P (tFix m n)) ->
    (forall (m : mfixpoint term) (n : nat), tFixProp P P m -> P (tCoFix m n)) ->
    (forall i, P (tInt i)) ->
    (forall f, P (tFloat f)) ->
    forall t : term, wf Σ t -> P t.
Proof.
  intros P H2 H3 H4 H5 H6 H7 H8 H9 H10 H11 H12 H13 H14 H15 H16 H17 H18 H19.
  intros until t. revert t.
  apply (term_forall_list_rect (fun t => wf Σ t -> P t));
    intros; try solve [match goal with
                 H : _ |- _ => apply H
              end; auto].
  - apply H4. inv X0.
    eauto using lift_to_wf_list.

  - inv X1; auto.
  - inv X1; auto.
  - inv X1; auto.
  - inv X2; auto.
  - inv X1; auto.
    apply H10; auto.
    eauto using lift_to_wf_list.

  - destruct X.
    inv X2; eapply H14; eauto.
    + split; auto. solve_all.
    + red in X1. solve_all.

  - inv X0; auto.

  - inv X0; auto.
    apply H16. red. red in X. solve_all.
  - inv X0; auto.
    apply H17. red. red in X. solve_all.
Qed.

Definition wf_decl Σ d :=
  match decl_body d with
  | Some b => wf Σ b
  | None => True
  end * wf Σ (decl_type d).

Definition wf_decl_pred Σ : context -> term -> typ_or_sort -> Type :=
  (fun _ t T => wf Σ t * match T with
                        | Typ T => wf Σ T
                        | Sort => True
                        end).

Lemma wf_mkApp Σ u a : wf Σ u -> wf Σ a -> wf Σ (mkApp u a).
Proof.
  intros H H'.
  inversion_clear H; try constructor; simpl; auto; try congruence; try constructor; auto.
  intro. destruct u0; simpl in *; congruence. solve_all.
  apply All_app_inv; auto. all:econstructor; eauto.
Qed.

Lemma wf_mkApps Σ u a : wf Σ u -> All (wf Σ) a -> wf Σ (mkApps u a).
Proof.
  intros H H'.
  induction a; simpl; auto.
  inversion_clear H; try constructor; simpl; auto; try congruence; try constructor; auto.
  intro. destruct u0; simpl in *; congruence.
  solve_all. apply All_app_inv; auto.
  all:econstructor; eauto.
Qed.

Lemma lift_isApp n k t : isApp t = false -> isApp (lift n k t) = false.
Proof.
  induction t; auto.
Qed.

#[export] Hint Resolve lift_isApp : all.

Lemma wf_lift Σ n k t : wf Σ t -> wf Σ (lift n k t).
Proof.
  intros wft; revert t wft k.
  apply (term_wf_forall_list_ind Σ (fun t => forall k, wf Σ (lift n k t)));
    intros; try cbn; econstructor; simpl; eauto; try solve [solve_all].
    destruct l; cbn in *. auto. discriminate. now rewrite map_length.
Qed.
Require Import PeanoNat.
Import Nat.

Lemma wf_subst Σ ts k u : All (wf Σ) ts -> wf Σ u -> wf Σ (subst ts k u).
Proof.
  intros wfts wfu.
  induction wfu in k using term_wf_forall_list_ind; simpl; intros; try econstructor; cbn in *; eauto;
    solve_all.

  - unfold subst. destruct (leb_spec_Set k n).
    destruct nth_error eqn:Heq. apply (nth_error_all Heq) in wfts.
    apply wf_lift; auto. constructor. constructor.
  - apply wf_mkApps; auto. solve_all.
  - now rewrite map_length.
Qed.

Lemma wf_subst1 Σ t k u : wf Σ t -> wf Σ u -> wf Σ (subst1 t k u).
Proof.
  intros wft wfu. apply wf_subst. constructor; auto. auto.
Qed.

#[export] Hint Resolve wf_mkApps wf_subst wf_subst1 wf_lift : wf.

Lemma wf_strip_outer_cast Σ t : WfAst.wf Σ t -> WfAst.wf Σ (strip_outer_cast t).
Proof.
  induction t; auto.
  simpl. intros H; now inv H.
Qed.

Lemma wf_mkApps_napp Σ t u : ~~ isApp t -> WfAst.wf Σ (mkApps t u) -> WfAst.wf Σ t * All (WfAst.wf Σ) u.
Proof.
  induction u in t |- *; simpl.
  - intuition.
  - intros Happ H; destruct t; try solve [inv H; intuition auto].
    specialize (IHu (tApp t0 (u ++ [a]))).
    forward IHu.
    induction u; trivial. discriminate.
Qed.
#[export] Hint Resolve wf_mkApps_napp : wf.

Lemma wf_mkApps_inv Σ t u : WfAst.wf Σ (mkApps t u) -> All (WfAst.wf Σ) u.
Proof.
  induction u in t |- *; simpl.
  - intuition.
  - intros H; destruct t; try solve [inv H; intuition auto].
    specialize (IHu (tApp t0 (args ++ [a]))).
    forward IHu.
    induction u; trivial.
    simpl. rewrite <- app_assoc. simpl. apply H.
    intuition. inv H.
    now apply All_app in X0.
Qed.
#[export] Hint Resolve wf_mkApps_inv : wf.
#[export] Hint Constructors WfAst.wf : wf.

Lemma isLambda_isApp t : isLambda t = true -> ~~ isApp t.
Proof. destruct t; simpl; congruence. Qed.

Lemma wf_subst_instance Σ u c :
  wf Σ c -> wf Σ (subst_instance u c).
Proof.
  induction 1 using term_wf_forall_list_ind; simpl; try solve [ cbn; constructor; auto using All_map; solve_all ].
  - cbn. constructor; auto. destruct t0; simpl in *; try congruence.
    destruct l; simpl in *; congruence.
    now apply All_map.
  - cbn; econstructor; eauto; simpl; solve_all.
    now rewrite map_length.
Qed.

Lemma wf_nth Σ:
  forall (n : nat) (args : list term), All (wf Σ) args -> wf Σ (nth n args tDummy).
Proof.
  intros n args H. induction H in n; destruct n; simpl; try constructor; auto.
Qed.
#[export] Hint Resolve wf_nth : core.