Library MetaCoq.Erasure.Erasure

From Coq Require Import Program ssreflect ssrbool.
From MetaCoq.Template Require Import Transform bytestring config utils EtaExpand.
From MetaCoq.PCUIC Require PCUICAst PCUICAstUtils PCUICProgram.
From MetaCoq.SafeChecker Require Import PCUICErrors PCUICWfEnvImpl.
From MetaCoq.Erasure Require EAstUtils ErasureFunction ErasureCorrectness EPretty Extract.
From MetaCoq.Erasure Require Import ETransform.

Import PCUICProgram.
Import PCUICTransform (template_to_pcuic_transform, pcuic_expand_lets_transform).

Import bytestring.
Local Open Scope bs.
Local Open Scope string_scope2.


Import Transform.

Obligation Tactic := program_simpl.

#[local] Existing Instance extraction_checker_flags.

Import EWcbvEval.

Program Definition erasure_pipeline {guard : abstract_guard_impl} (efl := EWellformed.all_env_flags) :
 Transform.t TemplateProgram.template_program EProgram.eprogram
  Ast.term EAst.term
  TemplateProgram.eval_template_program
  (EProgram.eval_eprogram {| with_prop_case := false; with_guarded_fix := false |}) :=
  
  template_to_pcuic_transform
  
  pcuic_expand_lets_transform
  
  erase_transform
  
  guarded_to_unguarded_fix (wcon := eq_refl) eq_refl
  
  remove_params_optimization (wcon := eq_refl)
  
  rebuild_wf_env_transform (efl := ERemoveParams.switch_no_params EWellformed.all_env_flags)
  
  optimize_prop_discr_optimization (efl := ERemoveParams.switch_no_params EWellformed.all_env_flags) (wcon := eq_refl) (hastrel := eq_refl) (hastbox := eq_refl)
  
  rebuild_wf_env_transform (efl := ERemoveParams.switch_no_params EWellformed.all_env_flags)
  
  inline_projections_optimization (fl := EWcbvEval.target_wcbv_flags) (wcon := eq_refl) (hastrel := eq_refl) (hastbox := eq_refl).

Import EGlobalEnv EWellformed.

Next Obligation.
  destruct H. split ⇒ //. sq.
  now eapply ETransform.expanded_eprogram_env_expanded_eprogram_cstrs.
Qed.

Definition run_erase_program {guard : abstract_guard_impl} := run erasure_pipeline.

Program Definition erasure_pipeline_fast {guard : abstract_guard_impl} (efl := EWellformed.all_env_flags) :=
  template_to_pcuic_transform
  pcuic_expand_lets_transform
  erase_transform
  guarded_to_unguarded_fix (wcon := eq_refl) eq_refl
  remove_params_fast_optimization (wcon := eq_refl) _
  rebuild_wf_env_transform (efl := ERemoveParams.switch_no_params EWellformed.all_env_flags)
  optimize_prop_discr_optimization (efl := ERemoveParams.switch_no_params EWellformed.all_env_flags) (wcon := eq_refl) (hastrel := eq_refl) (hastbox := eq_refl).
Next Obligation.
  destruct H; split ⇒ //. now eapply ETransform.expanded_eprogram_env_expanded_eprogram_cstrs.
Qed.

Definition run_erase_program_fast {guard : abstract_guard_impl} := run erasure_pipeline_fast.

Local Open Scope string_scope.

Axiom fake_guard_impl_properties :
(fix_cofix: PCUICTyping.FixCoFix)
       (Σ: PCUICAst.PCUICEnvironment.global_env_ext)
       (Γ: PCUICAst.PCUICEnvironment.context)
       (mfix: BasicAst.mfixpoint PCUICAst.term),
PCUICTyping.guard fix_cofix Σ Γ mfix fake_guard_impl fix_cofix Σ Γ mfix.

Global Program Instance fake_guard_impl : abstract_guard_impl :=
{| guard_impl := fake_guard_impl |}.
Next Obligation. apply fake_guard_impl_properties. Qed.

This uses the retyping-based erasure and assumes that the global environment and term are welltyped (for speed). As such this should only be used for testing, or when we know that the environment is wellformed and the term well-typed (e.g. when it comes directly from a Coq definition).

Axiom assume_that_we_only_erase_on_welltyped_programs : {cf : checker_flags},
   (p : Ast.Env.program), squash (TemplateProgram.wt_template_program p).

Program Definition erase_and_print_template_program {cf : checker_flags} (p : Ast.Env.program)
  : string :=
  let p' := run_erase_program (eta_expand_program p) _ in
  time "Pretty printing" EPretty.print_program p'.
Next Obligation.
  assert (ht : TemplateProgram.wt_template_program p ) by eapply assume_that_we_only_erase_on_welltyped_programs.
  split; auto.
  apply assume_that_we_only_erase_on_welltyped_programs.
  red.
  destruct ht as [[wfext [T ht]]].
  split; cbn. eapply EtaExpand.eta_expand_global_env_expanded. eapply wfext.
  eapply EtaExpand.expanded_env_irrel.
  epose proof (EtaExpand.eta_expand_expanded (Σ := Ast.Env.empty_ext p.1) [] [] p.2 T).
  forward H. apply wfext. specialize (H ht).
  forward H by constructor. cbn in H.
  destruct p as [ [] ]; cbn in ×. exact H.
Qed.

Program Definition erase_fast_and_print_template_program {cf : checker_flags} (p : Ast.Env.program)
  : string :=
  let p' := run_erase_program_fast (eta_expand_program p) _ in
  time "pretty-printing" EPretty.print_program p'.
Next Obligation.
  assert (ht : TemplateProgram.wt_template_program p ) by eapply assume_that_we_only_erase_on_welltyped_programs.
  split; auto.
  apply assume_that_we_only_erase_on_welltyped_programs.
  red.
  destruct ht as [[wfext [T ht]]].
  split; cbn. eapply EtaExpand.eta_expand_global_env_expanded. eapply wfext.
  eapply EtaExpand.expanded_env_irrel.
  epose proof (EtaExpand.eta_expand_expanded (Σ := Ast.Env.empty_ext p.1) [] [] p.2 T).
  forward H. apply wfext. specialize (H ht).
  forward H by constructor. cbn in H.
  destruct p as [ [] ]; cbn in ×. exact H.
Qed.