Library MetaCoq.Erasure.Extract




Definition isErasable Σ Γ t := T, Σ ;;; Γ |- t : T × (isArity T + ( u, (Σ ;;; Γ |- T : tSort u) × is_prop_sort u))%type.

Module E := EAst.

Fixpoint mkAppBox c n :=
  match n with
  | 0 ⇒ c
  | S nmkAppBox (E.tApp c E.tBox) n
  end.

Definition opt_def {A} (a : option A) (e : A) : A :=
  match a with
  | Some xRet x
  | Nonee
  end.

Reserved Notation "Σ ;;; Γ |- s ⇝ℇ t" (at level 50, Γ, s, t at next level).

Inductive erases (Σ : global_env_ext) (Γ : context) : term E.term Prop :=
    erases_tRel : i : nat, Σ;;; Γ |- tRel i E.tRel i
  | erases_tVar : n : ident, Σ;;; Γ |- tVar n E.tVar n
  | erases_tEvar : (m m' : nat) (l : list term) (l' : list E.term),
                   All2 (erases Σ Γ) l l' Σ;;; Γ |- tEvar m l E.tEvar m' l'
  | erases_tLambda : (na : name) (b t : term) (t' : E.term),
                     Σ;;; (vass na b :: Γ) |- t t'
                     Σ;;; Γ |- tLambda na b t E.tLambda na t'
  | erases_tLetIn : (na : name) (t1 : term) (t1' : E.term)
                      (T t2 : term) (t2' : E.term),
                    Σ;;; Γ |- t1 t1'
                    Σ;;; (vdef na t1 T :: Γ) |- t2 t2'
                    Σ;;; Γ |- tLetIn na t1 T t2 E.tLetIn na t1' t2'
  | erases_tApp : (f u : term) (f' u' : E.term),
                  Σ;;; Γ |- f f'
                  Σ;;; Γ |- u u' Σ;;; Γ |- tApp f u E.tApp f' u'
  | erases_tConst : (kn : kername) (u : universe_instance),
                    Σ;;; Γ |- tConst kn u E.tConst kn
  | erases_tConstruct : (kn : inductive) (k : nat) (n : universe_instance),
                        Σ;;; Γ |- tConstruct kn k n E.tConstruct kn k
  | erases_tCase1 : (ind : inductive) (npar : nat) (T c : term)
                      (brs : list (nat × term)) (c' : E.term)
                      (brs' : list (nat × E.term)),
                    Informative Σ ind
                    Σ;;; Γ |- c c'
                    All2
                      (fun (x : nat × term) (x' : nat × E.term) ⇒
                       Σ;;; Γ |- snd x snd x' × fst x = fst x') brs brs'
                    Σ;;; Γ |- tCase (ind, npar) T c brs E.tCase (ind, npar) c' brs'
  | erases_tProj : (p : (inductive × nat) × nat) (c : term) (c' : E.term),
                   let ind := fst (fst p) in
                   Informative Σ ind
                   Σ;;; Γ |- c c' Σ;;; Γ |- tProj p c E.tProj p c'
  | erases_tFix : (mfix : mfixpoint term) (n : nat) (mfix' : list (E.def E.term)),
                  All2
                    (fun (d : def term) (d' : E.def E.term) ⇒
                     dname d = E.dname d'
                     × rarg d = E.rarg d'
                       × Σ;;; Γ ,,, PCUICLiftSubst.fix_context mfix |-
                         dbody d E.dbody d') mfix mfix'
                  Σ;;; Γ |- tFix mfix n E.tFix mfix' n
  | erases_tCoFix : (mfix : mfixpoint term) (n : nat) (mfix' : list (E.def E.term)),
                    All2
                      (fun (d : def term) (d' : E.def E.term) ⇒
                       dname d = E.dname d'
                       × rarg d = E.rarg d'
                         × Σ;;; Γ ,,, PCUICLiftSubst.fix_context mfix |-
                           dbody d E.dbody d') mfix mfix'
                    Σ;;; Γ |- tCoFix mfix n E.tCoFix mfix' n
  | erases_box : t : term, isErasable Σ Γ t Σ;;; Γ |- t E.tBox where "Σ ;;; Γ |- s ⇝ℇ t" := (erases Σ Γ s t).

Definition erases_constant_body (Σ : global_env_ext) (cb : constant_body) (cb' : E.constant_body) :=
  match cst_body cb, E.cst_body cb' with
  | Some b, Some b'erases Σ [] b b'
  | None, NoneTrue
  | _, _False
  end.

Definition erases_one_inductive_body (Σ : global_env_ext) (npars : nat) (arities : context) (oib : one_inductive_body) (oib' : E.one_inductive_body) :=
  let decty := opt_def (decompose_prod_n_assum [] npars oib.(ind_type)) ([], tRel 0) in
  let '(params, arity) := decty in
  let projctx := arities ,,, params ,, vass nAnon oib.(ind_type) in
  Forall2 (fun '((i,t), n) '((i',t'), n')erases Σ arities t t' n = n' i = i') oib.(ind_ctors) oib'.(E.ind_ctors)
  Forall2 (fun '(i,t) '(i',t')erases Σ [] t t' i = i') oib.(ind_projs) oib'.(E.ind_projs)
  oib'.(E.ind_name) = oib.(ind_name)
  oib'.(E.ind_kelim) = oib.(ind_kelim).

Definition erases_mutual_inductive_body (Σ : global_env_ext) (mib : mutual_inductive_body) (mib' : E.mutual_inductive_body) :=
  let bds := mib.(ind_bodies) in
  let arities := arities_context bds in
  Forall2 (erases_one_inductive_body Σ mib.(ind_npars) arities) bds (mib'.(E.ind_bodies))
  mib.(ind_npars) = mib'.(E.ind_npars).

Inductive erases_global_decls : global_env E.global_declarations Prop :=
| erases_global_nil : erases_global_decls [] []
| erases_global_cnst Σ cb cb' kn Σ' :
    erases_constant_body (Σ, cst_universes cb) cb cb'
    erases_global_decls Σ Σ'
    erases_global_decls (ConstantDecl kn cb :: Σ) (E.ConstantDecl kn cb' :: Σ')
| erases_global_ind Σ univs mib mib' kn Σ' :
    erases_mutual_inductive_body (Σ, univs) mib mib'
    erases_global_decls Σ Σ'
    erases_global_decls (InductiveDecl kn mib :: Σ) (E.InductiveDecl kn mib' :: Σ').

Definition erases_global Σ Σ' := erases_global_decls Σ Σ'.

Fixpoint inductive_arity (t : term) :=
  match t with
  | tApp f _ | f
    match f with
    | tInd ind uSome ind
    | _None
    end
  end.

Definition option_is_none {A} (o : option A) :=
  match o with
  | Some _false
  | Nonetrue
  end.

Definition is_axiom_decl g :=
  match g with
  | ConstantDecl kn cboption_is_none cb.(cst_body)
  | InductiveDecl kn indfalse
  end.

Definition axiom_free Σ :=
   c decl, declared_constant Σ c decl cst_body decl None.

Definition computational_ind Σ ind :=
  let 'mkInd mind n := ind in
  let mib := lookup_env Σ mind in
  match mib with
  | Some (InductiveDecl kn decl) ⇒
    match List.nth_error decl.(ind_bodies) n with
    | Some body
      match destArity [] body.(ind_type) with
      | Some aritynegb (Universe.is_prop (snd arity))
      | Nonefalse
      end
    | Nonefalse
    end
  | _false
  end.

Definition computational_type Σ T :=
   ind, inductive_arity T = Some ind computational_ind Σ ind.