Library zoo.iris.proofmode.coq_tactics

From iris.bi Require Export
  bi
  telescopes.
From iris.proofmode Require Export
  base
  environments
  classes
  classes_make
  modality_instances.
From iris.prelude Require Import
  options.

Import bi.
Import env_notations.

Local Open Scope lazy_bool_scope.

Section tactics.
Context {PROP : bi}.
Implicit Types Γ : env PROP.
Implicit Types Δ : envs PROP.
Implicit Types P Q : PROP.

Starting and stopping the proof mode

Lemma tac_start P : envs_entails (Envs Enil Enil 1) P P.

Lemma tac_stop Δ P :
  (match env_intuitionistic Δ, env_spatial Δ with
   | Enil, Γsenv_to_prop Γs
   | Γp, Enil env_to_prop_and Γp
   | Γp, Γs env_to_prop_and Γp env_to_prop Γs
   end P)
  envs_entails Δ P.

Basic rules

Lemma tac_eval Δ Q Q' :
  (Q' Q)
  envs_entails Δ Q' envs_entails Δ Q.

Lemma tac_eval_in Δ i p P P' Q :
  envs_lookup i Δ = Some (p, P)
  (P P')
  match envs_simple_replace i p (Esnoc Enil i P') Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ Q.

Class AffineEnv (Γ : env PROP) := affine_env : Forall Affine Γ.
Global Instance affine_env_nil : AffineEnv Enil.
Global Instance affine_env_snoc Γ i P :
  Affine P AffineEnv Γ AffineEnv (Esnoc Γ i P).

Global Instance affine_env_bi `(!BiAffine PROP) Γ : AffineEnv Γ | 0.

Local Instance affine_env_spatial Δ :
  AffineEnv (env_spatial Δ) Affine ([∗] env_spatial Δ).

Lemma tac_emp_intro Δ : AffineEnv (env_spatial Δ) envs_entails Δ emp.

Lemma tac_assumption Δ i p P Q :
  envs_lookup i Δ = Some (p,P)
  FromAssumption p P Q
  (let Δ' := envs_delete true i p Δ in
   if env_spatial_is_nil Δ' then TCTrue
   else TCOr (Absorbing Q) (AffineEnv (env_spatial Δ')))
  envs_entails Δ Q.

Lemma tac_assumption_coq Δ P Q :
  ( P)
  FromAssumption false P Q
  (if env_spatial_is_nil Δ then TCTrue
   else TCOr (Absorbing Q) (AffineEnv (env_spatial Δ)))
  envs_entails Δ Q.

Lemma tac_rename Δ i j p P Q :
  envs_lookup i Δ = Some (p,P)
  match envs_simple_replace i p (Esnoc Enil j P) Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ Q.

Lemma tac_clear Δ i p P Q :
  envs_lookup i Δ = Some (p,P)
  (if p then TCTrue else TCOr (Affine P) (Absorbing Q))
  envs_entails (envs_delete true i p Δ) Q
  envs_entails Δ Q.

False

Pure

Lemma tac_pure_intro Δ Q φ a :
  FromPure a Q φ
  (if a then AffineEnv (env_spatial Δ) else TCTrue)
  φ
  envs_entails Δ Q.

Lemma tac_pure Δ i p P φ Q :
  envs_lookup i Δ = Some (p, P)
  IntoPure P φ
  (if p then TCTrue else TCOr (Affine P) (Absorbing Q))
  (φ envs_entails (envs_delete true i p Δ) Q) envs_entails Δ Q.

Lemma tac_pure_revert Δ φ P Q :
  MakeAffinely φ P
  envs_entails Δ (P -∗ Q)
  (φ envs_entails Δ Q).

Intuitionistic

Lemma tac_intuitionistic Δ i j p P P' Q :
  envs_lookup i Δ = Some (p, P)
  IntoPersistent p P P'
  (if p then TCTrue else TCOr (Affine P) (Absorbing Q))
  match envs_replace i p true (Esnoc Enil j P') Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ Q.

Lemma tac_spatial Δ i j p P P' Q :
  envs_lookup i Δ = Some (p, P)
  (if p then FromAffinely P' P else TCEq P' P)
  match envs_replace i p false (Esnoc Enil j P') Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ Q.

Implication and wand

Lemma tac_impl_intro Δ i P P' Q R :
  FromImpl R P Q
  (if env_spatial_is_nil Δ then TCTrue else Persistent P)
  FromAffinely P' P
  match envs_app false (Esnoc Enil i P') Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ R.
Lemma tac_impl_intro_intuitionistic Δ i P P' Q R :
  FromImpl R P Q
  IntoPersistent false P P'
  match envs_app true (Esnoc Enil i P') Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ R.
Lemma tac_impl_intro_drop Δ P Q R :
  FromImpl R P Q envs_entails Δ Q envs_entails Δ R.

Lemma tac_wand_intro Δ i P Q R :
  FromWand R P Q
  match envs_app false (Esnoc Enil i P) Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ R.

Lemma tac_wand_intro_intuitionistic Δ i P P' Q R :
  FromWand R P Q
  IntoPersistent false P P'
  TCOr (Affine P) (Absorbing Q)
  match envs_app true (Esnoc Enil i P') Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ R.
Lemma tac_wand_intro_drop Δ P Q R :
  FromWand R P Q
  TCOr (Affine P) (Absorbing Q)
  envs_entails Δ Q
  envs_entails Δ R.

Lemma tac_specialize remove_intuitionistic Δ i p j q P1 P2 R Q :
  envs_lookup i Δ = Some (p, P1)
  let Δ' := envs_delete remove_intuitionistic i p Δ in
  envs_lookup j Δ' = Some (q, R)
  IntoWand q p R P1 P2
  match envs_replace j q (p &&& q) (Esnoc Enil j P2) Δ' with
  | Some Δ''envs_entails Δ'' Q
  | NoneFalse
  end envs_entails Δ Q.

Lemma tac_specialize_assert Δ j (q am neg : bool) js R P1 P2 P1' Q :
  envs_lookup j Δ = Some (q, R)
  IntoWand q false R P1 P2
  (if am then AddModal P1' P1 Q else TCEq P1' P1)
  match
    '(Δ1,Δ2) envs_split (if neg is true then Right else Left)
                          js (envs_delete true j q Δ);
    Δ2' envs_app (negb am &&& q &&& env_spatial_is_nil Δ1) (Esnoc Enil j P2) Δ2;
    Some (Δ1,Δ2')
  with
  | Some (Δ1,Δ2')
     
     envs_entails Δ1 P1' envs_entails Δ2' Q
  | NoneFalse
  end envs_entails Δ Q.

Lemma tac_unlock_emp Δ Q : envs_entails Δ Q envs_entails Δ (emp locked Q).
Lemma tac_unlock_True Δ Q : envs_entails Δ Q envs_entails Δ (True locked Q).
Lemma tac_unlock Δ Q : envs_entails Δ Q envs_entails Δ (locked Q).

Lemma tac_specialize_frame Δ j (q am : bool) R P1 P2 P1' Q Q' :
  envs_lookup j Δ = Some (q, R)
  IntoWand q false R P1 P2
  (if am then AddModal P1' P1 Q else TCEq P1' P1)
  envs_entails (envs_delete true j q Δ) (P1' locked Q')
  Q' = (P2 -∗ Q)%I
  envs_entails Δ Q.

Lemma tac_specialize_assert_pure Δ j q a R P1 P2 φ Q :
  envs_lookup j Δ = Some (q, R)
  IntoWand q false R P1 P2
  FromPure a P1 φ
  φ
  match envs_simple_replace j q (Esnoc Enil j P2) Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ Q.

Lemma tac_specialize_assert_intuitionistic Δ j q P1 P1' P2 R Q :
  envs_lookup j Δ = Some (q, R)
  IntoWand q true R P1 P2
  Persistent P1
  IntoAbsorbingly P1' P1
  envs_entails (envs_delete true j q Δ) P1'
  match envs_simple_replace j q (Esnoc Enil j P2) Δ with
  | Some Δ''envs_entails Δ'' Q
  | NoneFalse
  end envs_entails Δ Q.

Lemma tac_specialize_intuitionistic_helper Δ j q P R R' Q :
  envs_lookup j Δ = Some (q,P)
  (if q then TCTrue else BiAffine PROP)
  envs_entails Δ (<absorb> R)
  IntoPersistent false R R'
  match envs_replace j q true (Esnoc Enil j R') Δ with
  | Some Δ''envs_entails Δ'' Q
  | NoneFalse
  end envs_entails Δ Q.

Lemma tac_specialize_intuitionistic_helper_done Δ i q P :
  envs_lookup i Δ = Some (q,P)
  envs_entails Δ (<absorb> P).

Lemma tac_revert Δ i Q :
  match envs_lookup_delete true i Δ with
  | Some (p,P,Δ')envs_entails Δ' ((if p then P else P)%I -∗ Q)
  | NoneFalse
  end
  envs_entails Δ Q.

Class IntoIH (φ : Prop) (Δ : envs PROP) (Q : PROP) :=
  into_ih : φ of_envs Δ Q.
Global Instance into_ih_entails Δ Q : IntoIH (envs_entails Δ Q) Δ Q.
Global Instance into_ih_forall {A} (φ : A Prop) Δ Φ :
  ( x, IntoIH (φ x) Δ (Φ x)) IntoIH ( x, φ x) Δ ( x, Φ x) | 2.
Global Instance into_ih_impl (φ ψ : Prop) Δ P Q :
  MakeAffinely φ P
  IntoIH ψ Δ Q IntoIH (φ ψ) Δ (P -∗ Q) | 1.

The instances into_ih_Forall and into_ih_Forall2 are used to support induction principles for mutual inductive types such as finitely branching trees:
Inductive ntree := Tree : list ntree → ntree.
Lemma ntree_ind (P : ntree → Prop) : (∀ l, Forall P l → P (Tree l)) → ∀ t, P t.
Note 1: We need an IntoIH instance for any predicate transformer (like Forall) that is used in induction principles. However, since nested induction with lists is most common, we currently only support Forall and Forall2.
Note 2: We could also write the instance into_ih_Forall using the big operator for conjunction, or using the forall quantifier. We use the big operator because that corresponds most closely to Forall, and we use the version with separating conjunction because we do not have a binary version of the big operator for conjunctions, and want to treat Forall and Forall2 consistently.
Global Instance into_ih_Forall {A} (φ : A Prop) l Δ Φ :
  ( x, IntoIH (φ x) Δ (Φ x))
  IntoIH (Forall φ l) Δ ([∗ list] x l, Φ x) | 2.
Global Instance into_ih_Forall2 {A B} (φ : A B Prop) l1 l2 Δ Φ :
  ( x1 x2, IntoIH (φ x1 x2) Δ (Φ x1 x2))
  IntoIH (Forall2 φ l1 l2) Δ ([∗ list] x1;x2 l1;l2, Φ x1 x2) | 2.

Lemma tac_revert_ih Δ P Q {φ : Prop} (Hφ : φ) :
  IntoIH φ Δ P
  env_spatial_is_nil Δ = true
  envs_entails Δ (<pers> P Q)
  envs_entails Δ Q.

Lemma tac_assert Δ j P Q :
  match envs_app true (Esnoc Enil j (P -∗ P)%I) Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end envs_entails Δ Q.

Definition IntoEmpValid (φ : Type) (P : PROP) := φ P.
These lemmas are Defined because the guardedness checker must see through them. See https://gitlab.mpi-sws.org/iris/iris/issues/274. For the same reason, their bodies use as little automation as possible.
Lemma into_emp_valid_here φ P : AsEmpValid DirectionIntoEmpValid φ P IntoEmpValid φ P.
Lemma into_emp_valid_impl (φ ψ : Type) P :
  φ IntoEmpValid ψ P IntoEmpValid (φ ψ) P.
Lemma into_emp_valid_forall {A} (φ : A Type) P x :
  IntoEmpValid (φ x) P IntoEmpValid ( x : A, φ x) P.
Lemma into_emp_valid_tforall {TT : tele} (φ : TT Prop) P x :
  IntoEmpValid (φ x) P IntoEmpValid (.. x : TT, φ x) P.
Lemma into_emp_valid_proj φ P : IntoEmpValid φ P φ P.

When called by the proof mode, the proof of P is produced by calling into_emp_valid_proj. That call must be transparent to the guardedness checker, per https://gitlab.mpi-sws.org/iris/iris/issues/274; hence, it must be done outside tac_pose_proof, so the latter can remain opaque.
Lemma tac_pose_proof Δ j P Q :
  ( P)
  match envs_app true (Esnoc Enil j P) Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ Q.

Lemma tac_pose_proof_hyp Δ i j Q :
  match envs_lookup_delete false i Δ with
  | NoneFalse
  | Some (p, P, Δ')
    match envs_app p (Esnoc Enil j P) Δ' with
    | NoneFalse
    | Some Δ''envs_entails Δ'' Q
    end
  end
  envs_entails Δ Q.

Lemma tac_apply Δ i p R P1 P2 :
  envs_lookup i Δ = Some (p, R)
  IntoWand p false R P1 P2
  envs_entails (envs_delete true i p Δ) P1 envs_entails Δ P2.

Conjunction splitting

Separating conjunction splitting

Lemma tac_sep_split Δ d js P Q1 Q2 :
  FromSep P Q1 Q2
  match envs_split d js Δ with
  | NoneFalse
  | Some (Δ1,Δ2)envs_entails Δ1 Q1 envs_entails Δ2 Q2
  end envs_entails Δ P.

Combining

For the iCombine tactic, users provide a Ps : list PROP which should be combined to a single PROP. The (public) classes currently available, MaybeCombineSepAs and CombineSepGives, can combine two given PROPs. The following CombineSepsAs and CombineSepsAsGives typeclasses are an implementation detail of iCombine, lifting the combining operation to one on list PROP.
Computing the 'gives' clause for a list of hypotheses is somewhat involved. We cannot just fold CombineSepGives over the list, since the output of the first CombineSepGives is not suitable as the input for the next iteration. For example, one might have CombineSepGives (own γ a) (own γ b) (✓ (a b)). This does not directly allow us to combine [own γ a; own γ b; own γ c] to (a b c), since CombineSepGives (✓ (b c)) (own γ a) ? does not work. We need to first compute the 'as' clause of the tail to proceed: that is, use the fact that the 'as' clause of [own γ b; own γ c] is own γ (b c). We could let CombineSepsAs compute the 'as' clause of the tail separately, but this results in quadratic complexity. We therefore bundle both clauses in the CombineSepsAsGives typeclass given below.
Note that an alternative would be to compute pairwise 'gives' clauses of the head of the list with every element in the tail, and -ing that with the 'gives' clause of the tail. In the example above, this would result in (a b) (a c) (b c). This approach is not strong enough: it does not allow us to conclude (a b c).
Class CombineSepsAsGives {PROP : bi} (Ps : list PROP) (Q R : PROP) := {
  combine_seps_as_gives_as : [∗] Ps Q;
  combine_seps_as_gives_gives : [∗] Ps <pers> R;
}.
Global Arguments CombineSepsAsGives {_} _%_I _%_I _%_I.
Global Arguments combine_seps_as_gives_as {_} _%_I _%_I _%_I {_}.
Global Arguments combine_seps_as_gives_gives {_} _%_I _%_I _%_I {_}.

Global Instance combine_seps_as_gives_nil : @CombineSepsAsGives PROP [] emp True.
Global Instance combine_seps_as_gives_singleton P :
  CombineSepsAsGives [P] P True | 1.
Global Instance combine_seps_gives_cons P Ps Q R Q' progress R' R'':
  CombineSepsAsGives Ps Q R
  MaybeCombineSepAs P Q Q' progress
  CombineSepGives P Q R'
  MakeAnd R R' R''
  CombineSepsAsGives (P :: Ps) Q' R'' | 2.
By and-ing R and R', the resulting 'gives' clause R'' will contain redundant information in some cases. However, this is necessary in other cases.
For example, if we take Ps = [own γ q1; own γ q2; own γ q3] with fracR as the cmra, we get R'' = (q2 + q3 1) (q1 + q2 + q3 1). Here, the first conjunct R follows from the second R', so there is redundancy.
However, if we take Ps = [own γ (CoPset E1); own γ (CoPset E2); own γ (CoPset E3)] with coPset_disjR as the cmra, we get R'' = (E2 ## E3) (E1 ## (E2 E3)), where the first conjunct does not follow from the second conjunct. Similarly for Ps = [l ↦{q1} v1; l ↦{q2} v2; l {q3} v3], where R'' = (v1 = v2) (v2 = v3) {..other info about qs..}.

If just the 'as' clause is needed, we will instead look for instances of the following CombineSepsAs typeclass.
Class CombineSepsAs {PROP : bi} (Ps : list PROP) (Q : PROP) :=
  combine_seps_as : [∗] Ps Q.
Global Arguments CombineSepsAs {_} _%_I _%_I.
Global Arguments combine_seps_as {_} _%_I _%_I {_}.

To ensure consistency of the output Q with that of CombineSepsAsGives, the only instance of CombineSepsAs is constructed with an instance of CombineSepsAsGives. The one thing we need to keep in mind here is that instances of CombineSepsAsGives can only be found if CombineSepGives instances exist. Unlike for the 'as' clause, there is no trivial 'gives' combination --- if the user writes a 'gives' clause, they intend to receive non-trivial information, and should receive an error if this cannot be found.
To still allow trivial combining with an 'as' clause, we add a trivial CombineSepGives instance only during the typeclass search of CombineSepsAs via CombineSepsAsGives. This means we both get consistent output Q from CombineSepsAsGives and CombineSepsAs, while iCombine "H1 H2" gives "H" still fails if "H1" and "H2" are unrelated

Conjunction/separating conjunction elimination

Lemma tac_and_destruct Δ i p j1 j2 P P1 P2 Q :
  envs_lookup i Δ = Some (p, P)
  (if p then IntoAnd true P P1 P2 else IntoSep P P1 P2)
  match envs_simple_replace i p (Esnoc (Esnoc Enil j1 P1) j2 P2) Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ Q.

Lemma tac_and_destruct_choice Δ i p d j P P1 P2 Q :
  envs_lookup i Δ = Some (p, P)
  (if p then IntoAnd p P P1 P2 : Type else
    TCOr (IntoAnd p P P1 P2) (TCAnd (IntoSep P P1 P2)
      (if d is Left then TCOr (Affine P2) (Absorbing Q)
       else TCOr (Affine P1) (Absorbing Q))))
  match envs_simple_replace i p (Esnoc Enil j (if d is Left then P1 else P2)) Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end envs_entails Δ Q.

Framing

Lemma tac_frame_pure Δ (φ : Prop) P Q :
  φ Frame true φ P Q envs_entails Δ Q envs_entails Δ P.

Lemma tac_frame Δ i p R P Q :
  envs_lookup i Δ = Some (p, R)
  Frame p R P Q
  envs_entails (envs_delete false i p Δ) Q envs_entails Δ P.

Disjunction

Lemma tac_or_l Δ P Q1 Q2 :
  FromOr P Q1 Q2 envs_entails Δ Q1 envs_entails Δ P.
Lemma tac_or_r Δ P Q1 Q2 :
  FromOr P Q1 Q2 envs_entails Δ Q2 envs_entails Δ P.

Lemma tac_or_destruct Δ i p j1 j2 P P1 P2 Q :
  envs_lookup i Δ = Some (p, P) IntoOr P P1 P2
  match envs_simple_replace i p (Esnoc Enil j1 P1) Δ,
        envs_simple_replace i p (Esnoc Enil j2 P2) Δ with
  | Some Δ1, Some Δ2envs_entails Δ1 Q envs_entails Δ2 Q
  | _, _False
  end
  envs_entails Δ Q.

Forall

Lemma tac_forall_intro {A} Δ (Φ : A PROP) Q name :
  FromForall Q Φ name
  (
   let _ := name in
    a, envs_entails Δ (Φ a))
  envs_entails Δ Q.

Lemma tac_forall_specialize {A} Δ i p P (Φ : A PROP) Q :
  envs_lookup i Δ = Some (p, P) IntoForall P Φ
  ( x : A,
      match envs_simple_replace i p (Esnoc Enil i (Φ x)) Δ with
      | NoneFalse
      | Some Δ'envs_entails Δ' Q
      end)
  envs_entails Δ Q.

Lemma tac_forall_revert {A} Δ (Φ : A PROP) :
  envs_entails Δ ( a, Φ a) a, envs_entails Δ (Φ a).

Existential

Lemma tac_exist {A} Δ P (Φ : A PROP) :
  FromExist P Φ ( a, envs_entails Δ (Φ a)) envs_entails Δ P.

Lemma tac_exist_destruct {A} Δ i p j P (Φ : A PROP) (name: ident_name) Q :
  envs_lookup i Δ = Some (p, P) IntoExist P Φ name
  (
    let _ := name in
     a,
     match envs_simple_replace i p (Esnoc Enil j (Φ a)) Δ with
     | Some Δ'envs_entails Δ' Q
     | NoneFalse
     end)
  envs_entails Δ Q.

Modalities

Lemma tac_modal_elim Δ i j p p' φ P' P Q Q' :
  envs_lookup i Δ = Some (p, P)
  ElimModal φ p p' P P' Q Q'
  φ
  match envs_replace i p p' (Esnoc Enil j P') Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q'
  end
  envs_entails Δ Q.

Accumulate hypotheses

Lemma tac_accu Δ P :
  env_to_prop (env_spatial Δ) = P
  envs_entails Δ P.

Invariants

Lemma tac_inv_elim {X : Type} Δ i j φ p Pinv Pin Pout (Pclose : option (X PROP))
      Q (Q' : X PROP) :
  envs_lookup i Δ = Some (p, Pinv)
  ElimInv φ Pinv Pin Pout Pclose Q Q'
  φ
  ( R,
    match envs_app false (Esnoc Enil j
      (Pin -∗
       ( x, Pout x -∗ pm_option_fun Pclose x -∗? Q' x) -∗
       R
      )%I) (envs_delete false i p Δ)
    with Some Δ''envs_entails Δ'' R | NoneFalse end)
  envs_entails Δ Q.

Rewriting

Lemma tac_rewrite `{!Sbi PROP} Δ i p Pxy d Q :
  envs_lookup i Δ = Some (p, Pxy)
   {A : ofe} (x y : A) (Φ : A PROP),
    IntoInternalEq Pxy x y
    (Q ⊣⊢ Φ (if d is Left then y else x))
    NonExpansive Φ
    envs_entails Δ (Φ (if d is Left then x else y)) envs_entails Δ Q.

Lemma tac_rewrite_in `{!Sbi PROP} Δ i p Pxy j q P d Q :
  envs_lookup i Δ = Some (p, Pxy)
  envs_lookup j Δ = Some (q, P)
   {A : ofe} (x y : A) (Φ : A PROP),
    IntoInternalEq Pxy x y
    (P ⊣⊢ Φ (if d is Left then y else x))
    NonExpansive Φ
    match envs_simple_replace j q (Esnoc Enil j (Φ (if d is Left then x else y))) Δ with
    | NoneFalse
    | Some Δ'envs_entails Δ' Q
    end
    envs_entails Δ Q.

Löb

Lemma tac_löb Δ i Q :
  BiLöb PROP
  env_spatial_is_nil Δ = true
  match envs_app true (Esnoc Enil i ( Q)%I) Δ with
  | NoneFalse
  | Some Δ'envs_entails Δ' Q
  end
  envs_entails Δ Q.
End tactics.

Introduction of modalities

The following private classes are used internally by tac_modal_intro / iModIntro to transform the proofmode environments when introducing a modality.
The class TransformIntuitionisticEnv M C Γin Γout is used to transform the intuitionistic environment using a type class C.
Inputs:
  • Γin : the original environment.
  • M : the modality that the environment should be transformed into.
  • C : PROP PROP Prop : a type class that is used to transform the individual hypotheses. The first parameter is the input and the second parameter is the output.
Outputs:
  • Γout : the resulting environment.
Class TransformIntuitionisticEnv {PROP1 PROP2} (M : modality PROP1 PROP2)
    (C : PROP2 PROP1 Prop) (Γin : env PROP2) (Γout : env PROP1) := {
  transform_intuitionistic_env :
    ( P Q, C P Q P M ( Q))
    ( P Q, M P M Q M (P Q))
    <affine> env_and_persistently Γin M (<affine> env_and_persistently Γout);
  transform_intuitionistic_env_wf : env_wf Γin env_wf Γout;
  transform_intuitionistic_env_dom i : Γin !! i = None Γout !! i = None;
}.

Class TransformSpatialEnv {PROP1 PROP2} (M : modality PROP1 PROP2)
    (C : PROP2 PROP1 Prop) (Γin : env PROP2) (Γout : env PROP1)
    (filtered : bool) := {
  transform_spatial_env :
    ( P Q, C P Q P M Q)
    ([∗] Γin) M ([∗] Γout) if filtered then True else emp;
  transform_spatial_env_wf : env_wf Γin env_wf Γout;
  transform_spatial_env_dom i : Γin !! i = None Γout !! i = None;
}.

Inductive IntoModalIntuitionisticEnv {PROP2} : {PROP1} (M : modality PROP1 PROP2)
    (Γin : env PROP2) (Γout : env PROP1), modality_action PROP1 PROP2 Prop :=
  | MIEnvIsEmpty_intuitionistic {PROP1} (M : modality PROP1 PROP2) :
     IntoModalIntuitionisticEnv M Enil Enil MIEnvIsEmpty
  | MIEnvForall_intuitionistic (M : modality PROP2 PROP2) (C : PROP2 Prop) Γ :
     TCForall C (env_to_list Γ)
     IntoModalIntuitionisticEnv M Γ Γ (MIEnvForall C)
  | MIEnvTransform_intuitionistic {PROP1}
       (M : modality PROP1 PROP2) (C : PROP2 PROP1 Prop) Γin Γout :
     TransformIntuitionisticEnv M C Γin Γout
     IntoModalIntuitionisticEnv M Γin Γout (MIEnvTransform C)
  | MIEnvClear_intuitionistic {PROP1 : bi} (M : modality PROP1 PROP2) Γ :
     IntoModalIntuitionisticEnv M Γ Enil MIEnvClear
  | MIEnvId_intuitionistic (M : modality PROP2 PROP2) Γ :
     IntoModalIntuitionisticEnv M Γ Γ MIEnvId.
Existing Class IntoModalIntuitionisticEnv.
Global Existing Instances MIEnvIsEmpty_intuitionistic MIEnvForall_intuitionistic
  MIEnvTransform_intuitionistic MIEnvClear_intuitionistic MIEnvId_intuitionistic.

Inductive IntoModalSpatialEnv {PROP2} : {PROP1} (M : modality PROP1 PROP2)
    (Γin : env PROP2) (Γout : env PROP1), modality_action PROP1 PROP2 bool Prop :=
  | MIEnvIsEmpty_spatial {PROP1} (M : modality PROP1 PROP2) :
     IntoModalSpatialEnv M Enil Enil MIEnvIsEmpty false
  | MIEnvForall_spatial (M : modality PROP2 PROP2) (C : PROP2 Prop) Γ :
     TCForall C (env_to_list Γ)
     IntoModalSpatialEnv M Γ Γ (MIEnvForall C) false
  | MIEnvTransform_spatial {PROP1}
       (M : modality PROP1 PROP2) (C : PROP2 PROP1 Prop) Γin Γout fi :
     TransformSpatialEnv M C Γin Γout fi
     IntoModalSpatialEnv M Γin Γout (MIEnvTransform C) fi
  | MIEnvClear_spatial {PROP1 : bi} (M : modality PROP1 PROP2) Γ :
     IntoModalSpatialEnv M Γ Enil MIEnvClear false
  | MIEnvId_spatial (M : modality PROP2 PROP2) Γ :
     IntoModalSpatialEnv M Γ Γ MIEnvId false.
Existing Class IntoModalSpatialEnv.
Global Existing Instances MIEnvIsEmpty_spatial MIEnvForall_spatial
  MIEnvTransform_spatial MIEnvClear_spatial MIEnvId_spatial.

Section tac_modal_intro.
  Context {PROP1 PROP2 : bi} (M : modality PROP1 PROP2).

  Global Instance transform_intuitionistic_env_nil C : TransformIntuitionisticEnv M C Enil Enil.
  Global Instance transform_intuitionistic_env_snoc (C : PROP2 PROP1 Prop) Γ Γ' i P Q :
    C P Q
    TransformIntuitionisticEnv M C Γ Γ'
    TransformIntuitionisticEnv M C (Esnoc Γ i P) (Esnoc Γ' i Q).
  Global Instance transform_intuitionistic_env_snoc_not (C : PROP2 PROP1 Prop) Γ Γ' i P :
    TransformIntuitionisticEnv M C Γ Γ'
    TransformIntuitionisticEnv M C (Esnoc Γ i P) Γ' | 100.

  Global Instance transform_spatial_env_nil C :
    TransformSpatialEnv M C Enil Enil false.
  Global Instance transform_spatial_env_snoc (C : PROP2 PROP1 Prop) Γ Γ' i P Q fi :
    C P Q
    TransformSpatialEnv M C Γ Γ' fi
    TransformSpatialEnv M C (Esnoc Γ i P) (Esnoc Γ' i Q) fi.

  Global Instance transform_spatial_env_snoc_not
      (C : PROP2 PROP1 Prop) Γ Γ' i P fi fi' :
    TransformSpatialEnv M C Γ Γ' fi
    TCIf (TCEq fi false)
      (TCIf (Affine P) (TCEq fi' false) (TCEq fi' true))
      (TCEq fi' true)
    TransformSpatialEnv M C (Esnoc Γ i P) Γ' fi' | 100.

The actual introduction tactic
The class MaybeIntoLaterNEnvs is used by tactics that need to introduce laters, e.g., the symbolic execution tactics.