Library MetaRocq.Translations.param_generous_packed

(* Distributed under the terms of the MIT license. *)
Set Warnings "-notation-overridden".
From MetaRocq.Utils Require Import utils.
From MetaRocq.Template Require Import Checker All.
From MetaRocq.Translations Require Import translation_utils MiniHoTT_paths.

Import MRMonadNotation.

Reserved Notation "'tsl_ty_param'".

Unset MetaRocq Strict Unquote Universe Mode.

MetaRocq Quote Definition tSigma := @sigT.
MetaRocq Quote Definition tPair := @existT.
Definition pair ( : term) : term
  := tApp tPair [ ; ; ; ].
Definition pack (t u : term) : term
  := tApp tSigma [ t ; u ].
MetaRocq Run (t tmQuote (@sigT) ;;
            match t with
            | tInd i _tmDefinition "sigma_ind" i
            | _tmFail "bug"
            end).
Definition (t : term) : term
  := tProj (mkProjection sigma_ind 2 0) t.
Definition (t : term) : term
  := tProj (mkProjection sigma_ind 2 (S 0)) t.
Definition proj (b : bool) (t : term) : term
  := tProj (mkProjection sigma_ind 2 (if b then 0 else S 0)) t.

Definition refresh_universe u :=
  if Universe.is_level u then u else fresh_universe.

Definition refresh_sort_universe := Sort.map refresh_universe.

Fixpoint refresh_universes (t : term) {struct t} :=
  match t with
  | tSort stSort (refresh_sort_universe s)
  | tProd na b ttProd na b (refresh_universes t)
  | tLetIn na b t' ttLetIn na b t' (refresh_universes t)
  | _t
  end.

Local Instance tit : config.checker_flags
  := config.type_in_type.
#[export] Existing Instance Checker.default_fuel.

(* if b it is the first translation, else the second *)
Fixpoint tsl_rec (fuel : ) (Σ : global_env_ext) (E : tsl_table) (Γ : context)
         (b : bool) (t : term) {struct fuel} : tsl_result term :=
  match fuel with
  | Oraise NotEnoughFuel
  | S fuel
  match t with
  | tRel nret (proj b (tRel n))

  | tSort s
    if b then ret (tSort s)
    else ret (tLambda (nNamed "A") (tSort s) (tProd nAnon (tRel 0) (tSort s)))

  | tCast t c Aif b then
                     tsl_rec fuel Σ E Γ true t ;;
                     tsl_rec fuel Σ E Γ true A ;;
                    ret (tCast c )
                  else
                     tsl_rec fuel Σ E Γ true t ;;
                     tsl_rec fuel Σ E Γ false t ;;
                     tsl_rec fuel Σ E Γ false A ;;
                    ret (tCast c (tApp []))

  | tProd n A B
    if b then
      A' tsl_ty_param fuel Σ E Γ A ;;
          tsl_rec fuel Σ E (Γ ,, vass n A) true B ;;
         ret (tProd n A' )
    else
      A' tsl_ty_param fuel Σ E Γ A ;;
       tsl_rec fuel Σ E (Γ ,, vass n A) true B ;;
       tsl_rec fuel Σ E (Γ ,, vass n A) false B ;;
      ret (tLambda (nNamed "f") (tProd n A' )
                   (tProd n (lift 1 0 A')
                          (tApp (lift 1 1 )
                                [tApp (tRel 1) [tRel 0]])))

  | tLambda n A tA' tsl_ty_param fuel Σ E Γ A ;;
                    t' tsl_rec fuel Σ E (Γ ,, vass n A) b t ;;
                    ret (tLambda n A' t')

  | tLetIn n t A ut' tsl_term fuel Σ E Γ t ;;
                     A' tsl_ty_param fuel Σ E Γ A ;;
                     u' tsl_rec fuel Σ E (Γ ,, vdef n t A) b u ;;
                     ret (tLetIn n t' A' u')

  | tApp t ut' tsl_rec fuel Σ E Γ b t ;;
               u' monad_map (tsl_term fuel Σ E Γ) u ;;
               ret (tApp t' u')

  | tConst _ _ as t
  | tInd _ _ as t
  | tConstruct _ _ _ as tt' tsl_term fuel Σ E Γ t ;;
                            ret (proj b t')
  | _raise TranslationNotHandeled
  end
  end

with tsl_term (fuel : ) (Σ : global_env_ext) (E : tsl_table) (Γ : context)
               (t : term) {struct fuel} : tsl_result term :=
  match fuel with
  | Oraise NotEnoughFuel
  | S fuel
  match t with
  | tRel nret (tRel n)

  | tSort s
    ret (pair (tSort (sType fresh_universe))
              (tLambda (nNamed "A") (tSort (sType fresh_universe)) (tProd nAnon (tRel 0) (tSort (sType fresh_universe))))
              (tSort s)
              (tLambda (nNamed "A") (tSort s) (tProd nAnon (tRel 0) (tSort s))))

  | tCast t c At' tsl_term fuel Σ E Γ t ;;
                  A' tsl_ty_param fuel Σ E Γ A ;;
                  ret (tCast t' c A')

  | tConst s univslookup_tsl_table' E (ConstRef s)
  | tInd i univslookup_tsl_table' E (IndRef i)
  | tConstruct i n univslookup_tsl_table' E (ConstructRef i n)
  | tmatch infer' Σ Γ t with
         | Checked typlet typ := refresh_universes typ in
                          tsl_rec fuel Σ E Γ true t ;;
                          tsl_rec fuel Σ E Γ false t ;;
                          tsl_rec fuel Σ E Γ true typ ;;
                          tsl_rec fuel Σ E Γ false typ ;;
                         ret (pair )
        | TypeError traise (TypingError t)
        end
  end
  end
where "'tsl_ty_param'" := ( fuel Σ E Γ t
                         tsl_rec fuel Σ E Γ true t ;;
                         tsl_rec fuel Σ E Γ false t ;;
                        ret (pack )).

#[export] Instance tsl_param : Translation
  := {| tsl_id := tsl_ident ;
        tsl_tm := ΣEtsl_term fuel (fst ΣE) (snd ΣE) [] ;
        tsl_ty := Some ( ΣEtsl_ty_param fuel (fst ΣE) (snd ΣE) []) ;
        tsl_ind := todo "tsl" |}.

Notation "'TYPE'" := ({ A : Type & AType}).
Notation "'El' A" := (@sigT A.1 A.2) (at level 20).

Definition Ty := Type.
MetaRocq Run (Translate emptyTC "Ty").
Unset Universe Checking.
Check Tyᵗ : El Tyᵗ.

MetaRocq Run (TC ImplementExisting emptyTC "sigT" ;;
                     tmDefinition "TC" TC).
Next Obligation.
  unshelve econstructor.
(*   - intros A B. refine (sigma (El A) (fun x => sigma (B.1 x) (B.2 x))). *)
(*   - cbn. intros A B X. exact unit.  *)
(* Defined. *)
  - intros A B. refine (@sigT (El A) B.1).
  - cbn; intros A B. refine ( xB.2 x.1 x.2).
Defined.

MetaRocq Run (TC ImplementExisting TC "existT" ;;
                     tmDefinition "TC'" TC).
Next Obligation.
  unshelve econstructor.
(*   - intros A B x y. econstructor. exact y. *)
(*   - intros A B π1 H. constructor.  *)
(* Defined. *)
  - intros A B x y. econstructor. exact y.1.
  - cbn; intros A B x y. exact y.2.
Defined.

Time MetaRocq Run (TC ImplementExisting TC' "sigT_ind" ;;
                          tmDefinition "TC''" TC).
Next Obligation.
  unshelve econstructor.
(*   - intros A B P   s []. apply X1. *)
(*   - intros A B P   s []. apply X2. *)
(* Defined. *)
  - intros A B P [ ] [s s']. apply ( s.1 (s.2; s')).
  - intros A B P [ ] [s s']. apply ( s.1 (s.2; s')).
Defined.

MetaRocq Run (TC ImplementExisting TC'' "paths" ;;
                     tmDefinition "TC3" TC).
Next Obligation.
  unshelve econstructor.
  - intros A x y. refine (x.1 = y.1).
  - cbn; intros A x y p. refine (p # x.2 = y.2).
Defined.

MetaRocq Run (TC ImplementExisting "idpath" ;;
                     tmDefinition "TC4" TC).
Next Obligation.
  unshelve econstructor; reflexivity.
Defined.

MetaRocq Run (TC ImplementExisting "paths_ind" ;;
                     tmDefinition "TC5" TC).
Next Obligation.
  unshelve econstructor.
  - intros A [x x'] P X [y y'] [p q]. cbn in ×. destruct p, q; cbn.
    exact X.1.
  - intros A [x x'] P X [y y'] [p q]. cbn in ×. destruct p, q; cbn.
    exact X.2.
Defined.

Definition Funext :=
   A (B : AType) (f g : x, B x), ( x, paths (f x) (g x)) → paths f g.

MetaRocq Run (Translate "Funext").

Definition Funext_fullFunext : Funext A B f g, IsEquiv (@ A B f g).
Admitted.

Goal FunextEl Funextᵗ.
  simpl. intro H. assert ( := Funext_fullFunext H); clear H.
  rename into H.
  unshelve econstructor.
  - intros A B f g X. apply H. exact X.1.
  - intros A B f g [ ]; cbn in ×.
    apply H. intro x. rewrite transport_forall_constant.
    specialize ( x).
    refine (_ @ ).
    rewrite transport_compose.
    eapply . eapply ap.
    rewrite ap_apply_lD. now rewrite eisretr.
Defined.

Definition FALSE := X, X.
MetaRocq Run (Translate emptyTC "FALSE").

Proposition consistency_preservation : El FALSEᵗ → FALSE.
  compute.
  intros [f _] X.
  exact (f (X; _unit)).
Defined.

Definition UIP := A (x y : A) (p q : paths x y), paths p q.

MetaRocq Run (Translate "UIP").

Proposition uip_preservation : UIPEl UIPᵗ.
  simpl. intro H. unshelve econstructor.
  - intros A x y p q. apply H.
  - cbn. intros A x y p q. apply H.
Defined.

Notation " A × B " := (@sigT A ( _B)) : type_scope.

Definition equiv (A B : Type) : Type :=
   (f : AB) (g : BA),
    ( x, paths (g (f x)) x) × ( x, paths (f (g x)) x).

MetaRocq Run (TC ImplementExisting "False" ;;
                     tmDefinition "TC6" TC).
Next Obligation.
  unshelve econstructor.
  - exact False.
  - intros _. exact False.
Defined.

MetaRocq Run (TC Translate "equiv" ;;
                     tmDefinition "TC7" TC).

(* 244s (~ 4 min) to execute *)
(* Time
MetaRocq Run (H <- Implement TC7 "notUnivalence"
                     (exists A B, (equiv A B) × exists P, P A × ((P B) -> False)) ;;
                     tmPrint "done").
Check "proof".
Next Obligation.
  unshelve econstructor.
  - exists (bool; fun _=> unit).
    exists (unit; fun _=> bool).
    cbn. unshelve econstructor.
    + unshelve econstructor.
      unshelve econstructor.
      exists (fun _ => tt). exact pr1.
      unshelve econstructor.
      exists pr2. exact (fun _ => tt).
      split; |intros [[] x]; reflexivity.
      unshelve econstructor; reflexivity|.
      intros x []; reflexivity.
      cbn. intros [] x; reflexivity.
    + unshelve econstructor.
      exists (fun T => exists (x y : T.1), x = y -> False). exact (fun _ _ => unit).
      cbn; split.
      refine ((true; (false; _)); tt). intro e; inversion e.
      intros [[] [[] H]] _. apply H; reflexivity.
  - cbn. intros [[] [[] H]] _. apply H; reflexivity.
Defined. *)