Library MetaCoq.PCUIC.Syntax.PCUICUnivSubst

From Coq Require Import ssreflect.
From MetaCoq.Template Require Import utils.
From MetaCoq.PCUIC Require Import PCUICAst PCUICAstUtils PCUICInduction.

#[global]
Instance subst_instance_list A `{UnivSubst A} : UnivSubst (list A) :=
  fun uList.map (subst_instance u).

Lemma subst_instance_instance_length (u1 : Instance.t) u2 :
  #|subst_instance u2 u1| = #|u1|.
Proof.
  unfold subst_instance.
  now rewrite map_length.
Qed.
#[global]
Hint Rewrite subst_instance_instance_length : len.

Lemma subst_instance_nil {A} {ua : UnivSubst A} u (xs : list A) :
  subst_instance u [] = [].
Proof. reflexivity. Qed.

Lemma subst_instance_cons {A} {ua : UnivSubst A} u x (xs : list A) :
  subst_instance u (x :: xs) = subst_instance u x :: subst_instance u xs.
Proof. reflexivity. Qed.

Lemma subst_instance_lift u c n k :
  subst_instance u (lift n k c) = lift n k (subst_instance u c).
Proof.
  unfold subst_instance; cbn.
  induction c in k |- × using term_forall_list_ind; simpl; auto;
    autorewrite with map;
    try solve [f_equal; eauto; solve_all; eauto].
Qed.

Lemma subst_instance_mkApps u f a :
  subst_instance u (mkApps f a) =
  mkApps (subst_instance u f) (map (subst_instance u) a).
Proof.
  induction a in f |- *; auto.
  simpl map. simpl. now rewrite IHa.
Qed.

Lemma subst_instance_it_mkProd_or_LetIn u ctx t :
  subst_instance u (it_mkProd_or_LetIn ctx t) =
  it_mkProd_or_LetIn (subst_instance u ctx) (subst_instance u t).
Proof.
  unfold subst_instance; cbn.
  induction ctx in u, t |- *; simpl; unfold mkProd_or_LetIn; try congruence.
  rewrite IHctx. f_equal; unfold mkProd_or_LetIn.
  destruct a as [na [b|] ty]; simpl; eauto.
Qed.

Lemma subst_instance_it_mkLambda_or_LetIn u ctx t :
  subst_instance u (it_mkLambda_or_LetIn ctx t) =
  it_mkLambda_or_LetIn (subst_instance u ctx) (subst_instance u t).
Proof.
  unfold subst_instance; cbn.
  induction ctx in u, t |- *; simpl; unfold mkProd_or_LetIn; try congruence.
  rewrite IHctx. f_equal; unfold mkProd_or_LetIn.
  destruct a as [na [b|] ty]; simpl; eauto.
Qed.

Lemma subst_instance_subst u c (s : list term) k :
  subst_instance u (subst s k c) = subst (subst_instance u s) k (subst_instance u c).
Proof.
  unfold subst_instance, subst_instance_list; cbn.
  induction c in k |- × using term_forall_list_ind; simpl; auto;
    autorewrite with map;
    try solve [f_equal; eauto; solve_all; eauto].

  elim (Nat.leb k n); auto.
  rewrite nth_error_map.
  destruct (nth_error s (n - k)). simpl.
  now rewrite [subst_instance_constr _ _]subst_instance_lift.
  reflexivity.
Qed.

Lemma map_subst_instance_to_extended_list_k u ctx k :
  map (subst_instance u) (to_extended_list_k ctx k)
  = to_extended_list_k ctx k.
Proof.
  pose proof (to_extended_list_k_spec ctx k).
  solve_all. now destruct H as [n [-> _]].
Qed.

Lemma closedu_subst_instance u t
  : closedu 0 t subst_instance u t = t.
Proof.
  unfold subst_instance; cbn.
  induction t in |- × using term_forall_list_ind; simpl; auto; intros H';
    autorewrite with map;
    try f_equal; eauto with substu; unfold test_predicate_ku, test_branch, test_def in *;
      try solve [f_equal; eauto; repeat (rtoProp; solve_all); eauto with substu].
Qed.

Lemma subst_instance_closedu (u : Instance.t) (Hcl : closedu_instance 0 u) t :
  closedu #|u| t closedu 0 (subst_instance u t).
Proof.
  induction t in |- × using term_forall_list_ind; simpl; auto; intros H';
    autorewrite with map;
    try f_equal; auto with substu;
      unfold test_def, test_predicate_ku, test_branch in *; simpl;
      try solve [f_equal; eauto; repeat (rtoProp; solve_all); intuition auto with substu].
  rewrite [#|subst_instance_instance _ _|]subst_instance_instance_length. solve_all.
  eauto with substu.
Qed.

Lemma rev_subst_instance {u Γ} :
  List.rev (subst_instance u Γ) = subst_instance u (List.rev Γ).
Proof.
  unfold subst_instance, subst_instance_context, map_context.
  now rewrite map_rev.
Qed.

Lemma subst_instance_extended_subst u Γ n :
  map (subst_instance u) (extended_subst Γ n) =
  extended_subst (subst_instance u Γ) n.
Proof.
  induction Γ as [|[?[]?] ?] in n |- *; simpl; auto.
  - autorewrite with len.
    f_equal; auto.
    rewrite subst_instance_subst -IHΓ.
    rewrite <-subst_instance_lift; simpl.
    f_equal.
  - f_equal; auto.
Qed.