Library MetaCoq.Erasure.ErasureFunction



Section fix_sigma.
Variable Σ : global_env_ext.
Variable : wf Σ.

Definition term_rel : Relation_Definitions.relation ( Γ t, wellformed Σ Γ t) :=
  fun '(Γ2; B; H) '(Γ1; t1; H2)
     na A, red (fst Σ) Γ1 t1 (tProd na A B) × (Γ1,, vass na A) = Γ2.

Definition cod B t := match t with tProd _ _ B'B = B' | _False end.

Lemma wf_cod : WellFounded cod.

Lemma wf_cod' : WellFounded (Relation_Operators.clos_trans _ cod).

Lemma Acc_no_loop X (R : X X Prop) t : Acc R t R t t False.


Instance wf_reduction : WellFounded term_rel.





Lemma mkApps_tFix_inv t mfix n L :
  t = mkApps (tFix mfix n) L
  ( a b, t = tApp a b) + ((t = tFix mfix n) × (L = [])).

Notation err := (TypeError (Msg "hnf did not return normal form")).
Program Fixpoint normal_dec Γ t : typing_result ( t', red1 Σ Γ t t' False) :=
  match t with
  | tRel nmatch option_map decl_body (nth_error Γ n) with
               Some (Some body) ⇒ err
             | _ret _
             end
  | tVar nret _
  | tSort uret _
  | tProd na A BH1 <- normal_dec Γ A ;;
                      H2 <- normal_dec (Γ,, vass na A) B;;
                      ret _
  | tLambda na A BH1 <- normal_dec Γ A ;;
                      H2 <- normal_dec (Γ,, vass na A) B;;
                      ret _
  | tLetIn _ _ _ _err
  | tConst c umatch lookup_env Σ c with Some (ConstantDecl _ (Build_constant_body _ (Some _) _)) ⇒ err
                                       | _ret _
                 end
  | tInd _ _ret _
  | tConstruct _ _ _ret _
  | tCase _ _ _ _err
  | tProj _ _err
  
  
  | _TypeError (Msg "not implemented")
  end.
Solve All Obligations with firstorder congruence.

Inductive red' (Σ : global_env) (Γ : context) : term term Type :=
  refl_red' M : red' Σ Γ M M
| trans_red' : M P N : term, red1 Σ Γ M P red' Σ Γ P N red' Σ Γ M N.

Instance red'_transitive Γ : CRelationClasses.Transitive (red' Σ Γ).

Lemma red_red' Γ t t' : red Σ Γ t t' red' Σ Γ t t'.

Program Definition reduce_to_sort' Γ t (h : wellformed Σ Γ t)
  : typing_result (( u, red (fst Σ) Γ t (tSort u) ) + (( u, red (fst Σ) Γ t (tSort u) ) False)) :=
  match t with
  | tSort uret (inl (u; sq (refl_red _ _ _)))
  | _
    match hnf Γ t h with
    | tSort uret (inl (u; _))
    | t'match normal_dec Γ t' with Checked Hret (inr _) | TypeError tTypeError t end
    end
  end.

Program Definition reduce_to_prod' Γ t (h : wellformed Σ Γ t)
  : typing_result (( na a b, red (fst Σ) Γ t (tProd na a b) ) + (( na a b, red (fst Σ) Γ t (tProd na a b) ) False)) :=
  match t with
  | tProd na a bret (inl (na; a; b; sq (refl_red _ _ _)))
  | _
    match hnf Γ t h with
    | tProd na a bret (inl (na; a; b; _))
    | t'match normal_dec Γ t' with Checked Hret (inr _) | _TypeError (Msg "hnf did not return normal form") end
    end
  end.

Equations is_arity Γ ( : wf_local Σ Γ) T (HT : wellformed Σ Γ T) :
  typing_result ({Is_conv_to_Arity Σ Γ T} + {¬ Is_conv_to_Arity Σ Γ T})
  by wf ((Γ;T;HT) : ( Γ t, wellformed Σ Γ t)) term_rel :=
  {
    is_arity Γ T HT with (@reduce_to_sort' Γ T HT) ⇒ {
    | Checked (inl H)ret (left _) ;
    | Checked (inr Hs) with inspect (@reduce_to_prod' Γ T _) ⇒ {
      | exist (Checked (inl (na; A; B; H))) He
        match is_arity (Γ,, vass na A) _ B _ with
        | Checked (left H) ⇒ ret (left _)
        | Checked (right H) ⇒ ret (right _)
        | TypeError tTypeError t
        end;
      | exist (Checked (inr _)) Heret (right _);
      | exist (TypeError t) HeTypeError t } ;
    | TypeError tTypeError t
    }
  }.

End fix_sigma.

Definition wf_ext_wf Σ : wf_ext Σ wf Σ := fst.

Program Definition is_erasable (Sigma : PCUICAst.global_env_ext) ( : wf_ext Sigma) (Gamma : context) ( : wf_local Sigma Gamma) (t : PCUICAst.term) :
  typing_result ({isErasable Sigma Gamma t} +{(isErasable Sigma Gamma t False) × welltyped Sigma Gamma t}) :=
  mlet (T; _) <- @make_graph_and_infer _ _ Gamma t ;;
  mlet b <- is_arity Sigma _ Gamma _ T _ ;;
  if b : {_} + {_} then
    ret (left _)
  else mlet (K; _) <- @make_graph_and_infer _ _ Gamma T ;;
       mlet (u;_) <- @reduce_to_sort _ Sigma _ Gamma K _ ;;
      match is_prop_sort u with trueret (left _) | falseret (right _) end
.

Section Erase.

  Definition is_box c :=
    match c with
    | E.tBoxtrue
    | _false
    end.

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

  Definition on_snd_map {A B C} (f : B C) (p : A × B) :=
    (fst p, f (snd p)).

  Variable (Σ : global_env_ext)( : wf_ext Σ ).


  Section EraseMfix.
    Context (erase : (Γ : context) ( : wf_local Σ Γ ) (t : term), typing_result E.term).

    Program Definition erase_mfix Γ ( : wf_local Σ Γ) (defs : mfixpoint term) : typing_result (EAst.mfixpoint E.term) :=
      let Γ' := (PCUICLiftSubst.fix_context defs ++ Γ)%list in
      monad_map (fun dH <- _ ;;
                   dbody' <- erase Γ' H d.(dbody);;
                          ret ({| E.dname := d.(dname); E.rarg := d.(rarg);
                                  E.dbody := dbody' |})) defs.

  End EraseMfix.

  Equations(noind) erase (Γ : context) ( : wf_local Σ Γ ) (t : term) : typing_result E.term :=
    erase Γ t with (is_erasable Σ Γ t) :=
    {
      erase Γ _ (Checked (left _)) := ret (E.tBox);
      erase Γ _ (TypeError t) := TypeError t ;
      erase Γ (tRel i) _ := ret (E.tRel i) ;
      erase Γ (tVar n) _ := ret (E.tVar n) ;
      erase Γ (tEvar m l) _ := l' <- monad_map (erase Γ ) l;; ret (E.tEvar m l') ;
      erase Γ (tSort u) _ := ret E.tBox

      ; erase Γ (tConst kn u) _ := ret (E.tConst kn)
      ; erase Γ (tInd kn u) _ := ret E.tBox
      ; erase Γ (tConstruct kn k u) _ := ret (E.tConstruct kn k)
      ; erase Γ (tProd na b t) _ := ret E.tBox
      ; erase Γ (tLambda na b t) _ :=
                           t' <- erase (vass na b :: Γ) _ t;;
                              ret (E.tLambda na t')
      ; erase Γ (tLetIn na b t0 t1) _ :=
                              b' <- erase Γ b;;
                                 t1' <- erase (vdef na b t0 :: Γ) _ t1;;
                                 ret (E.tLetIn na b' t1')
      ; erase Γ (tApp f u) _ :=
                     f' <- erase Γ f;;
                        l' <- erase Γ u;;
                        ret (E.tApp f' l')
      ; erase Γ (tCase ip p c brs) _ :=
                             c' <- erase Γ c;;
                                brs' <- monad_map (T :=typing_result) (fun xx' <- erase Γ (snd x);; ret (fst x, x')) brs;;
                                ret (E.tCase ip c' brs')
      ; erase Γ (tProj p c) _ :=
                      c' <- erase Γ c;;
                         ret (E.tProj p c')
      ; erase Γ (tFix mfix n) _ :=
                        mfix' <- erase_mfix (erase) Γ mfix;;
                              ret (E.tFix mfix' n)
      ; erase Γ (tCoFix mfix n) _ :=
                          mfix' <- erase_mfix (erase) Γ mfix;;
                                ret (E.tCoFix mfix' n)
    }.

End Erase.


Lemma erases_erase (Σ : global_env_ext) Γ t T (wfΣ : wf_ext Σ) (wfΓ : wf_local Σ Γ) t' :
  Σ ;;; Γ |- t : T
  erase Σ (wfΣ) Γ (wfΓ) t = Checked t'
  erases Σ Γ t t'.
Print Assumptions erases_erase.

Lemma erase_Some_typed {Σ wfΣ Γ wfΓ t r} :
  erase Σ wfΣ Γ wfΓ t = Checked r T, Σ ;;; Γ |- t : T.

Definition optM {M : Type Type} `{Monad M} {A B} (x : option A) (f : A M B) : M (option B) :=
  match x with
  | Some xy <- f x ;; ret (Some y)
  | Noneret None
  end.

Lemma wf_local_nil {Σ} : wf_local Σ [] .

Definition erase_constant_body Σ wfΣ (cb : constant_body) : typing_result E.constant_body :=
  ty <- erase Σ wfΣ [] wf_local_nil cb.(cst_type) ;;
  body <- optM cb.(cst_body) (fun berase Σ wfΣ [] wf_local_nil b);;
  ret {| E.cst_body := body; |}.

Definition lift_opt_typing {A} (a : option A) (e : type_error) : typing_result A :=
  match a with
  | Some xret x
  | Noneraise e
  end.

Definition erase_one_inductive_body Σ wfΣ npars arities Har
           (oib : one_inductive_body) : typing_result E.one_inductive_body :=
  decty <- lift_opt_typing (decompose_prod_n_assum [] npars oib.(ind_type))
        (NotAnInductive oib.(ind_type)) ;;
  let '(params, arity) := decty in
  type <- erase Σ wfΣ [] wf_local_nil oib.(ind_type) ;;
  ctors <- monad_map (fun '(x, y, z)y' <- erase Σ wfΣ arities Har y;; ret (x, y', z)) oib.(ind_ctors);;
  let projctx := arities ,,, params ,, vass nAnon oib.(ind_type) in
  projs <- monad_map (fun '(x, y)y' <- erase Σ wfΣ [] wf_local_nil y;; ret (x, y')) oib.(ind_projs);;
  ret {| E.ind_name := oib.(ind_name);
         E.ind_kelim := oib.(ind_kelim);
         E.ind_ctors := ctors;
         E.ind_projs := projs |}.

Program Definition erase_mutual_inductive_body Σ wfΣ
           (mib : mutual_inductive_body) (Hm : wf_local Σ (arities_context (ind_bodies mib)) )
: typing_result E.mutual_inductive_body :=
  let bds := mib.(ind_bodies) in
  let arities := arities_context bds in
  bodies <- monad_map (erase_one_inductive_body Σ wfΣ mib.(ind_npars) arities _) bds ;;
  ret {| E.ind_npars := mib.(ind_npars);
         E.ind_bodies := bodies; |}.

Program Fixpoint erase_global_decls Σ : wf Σ typing_result E.global_declarations := fun wfΣ
  match Σ with
  | []ret []
  | ConstantDecl kn cb :: Σ
    cb' <- erase_constant_body (Σ, cst_universes cb) _ cb;;
    Σ' <- erase_global_decls Σ _;;
    ret (E.ConstantDecl kn cb' :: Σ')
  | InductiveDecl kn mib :: Σ
    mib' <- erase_mutual_inductive_body (Σ, ind_universes mib) _ mib _ ;;
    Σ' <- erase_global_decls Σ _;;
    ret (E.InductiveDecl kn mib' :: Σ')
  end.

Program Definition erase_global Σ : wf Σ _:=
  fun wfΣ
  Σ' <- erase_global_decls Σ wfΣ ;;
  ret Σ'.

Lemma erase_global_correct Σ (wfΣ : wf Σ) Σ' :
  erase_global Σ wfΣ = Checked Σ'
  erases_global Σ Σ'.