Newer
Older
(** Requires:
opam repo add iris-dev https://gitlab.mpi-sws.org/FP/opam-dev.git
opam update
opam install coq-iris=branch.gen_proofmode.2018-05-29.0.9b14f90a
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
*)
(**
This file contains an instantiation of the Generalized Proof Mode
(extending Iris) for CFML.
*)
Set Implicit Arguments.
From TLC Require Export LibCore.
From Sep Require Export TLCbuffer SepFunctor.
From iris Require bi proofmode.tactics.
(* We undo the setup done by Stdpp. *)
Global Generalizable No Variables.
Global Obligation Tactic := Coq.Program.Tactics.program_simpl.
(* ********************************************************************** *)
(* * Extension to the core interface that needs to be exposed to GPM *)
Module Type SepCoreHemptySig (SC : SepCore).
Import SC.
(** Implement a definition of heap_empty *)
Parameter heap_empty : heap.
(** Forces the definition of [hempty] to be the canonical one *)
Parameter hempty_eq :
hempty = (fun h => h = heap_empty).
End SepCoreHemptySig.
(* ********************************************************************** *)
(* * Subset of the interface of SepLogicSetup that needs to be exposed to GPM *)
Module Type SepSetupGPMSig (SC : SepCore).
Export SC.
Implicit Types h : heap.
Implicit Types H : hprop.
Implicit Types P : Prop.
(* ---------------------------------------------------------------------- *)
(* ** Definition of heap predicates *)
Definition hpure (P:Prop) : hprop :=
hexists (fun (p:P) => hempty).
Definition hor (H1 H2 : hprop) : hprop :=
fun h => H1 h \/ H2 h.
Definition hand (H1 H2 : hprop) : hprop :=
fun h => H1 h /\ H2 h.
Definition hwand (H1 H2 : hprop) : hprop :=
hexists (fun (H:hprop) => H \* (hpure (H \* H1 ==> H2))).
Definition qwand A (Q1 Q2:A->hprop) :=
hforall (fun x => hwand (Q1 x) (Q2 x)).
Definition htop : hprop :=
hexists (fun (H:hprop) => H).
(* ---------------------------------------------------------------------- *)
(* ** Some notation *)
Notation "'Hexists' x1 , H" := (hexists (fun x1 => H))
(at level 39, x1 ident, H at level 50) : heap_scope.
Notation "'Hexists' x1 x2 , H" := (Hexists x1, Hexists x2, H)
(at level 39, x1 ident, x2 ident, H at level 50) : heap_scope.
Notation "'Hexists' x1 x2 x3 , H" := (Hexists x1, Hexists x2, Hexists x3, H)
(at level 39, x1 ident, x2 ident, x3 ident, H at level 50) : heap_scope.
Notation "\[ P ]" := (hpure P)
(at level 0, P at level 99, format "\[ P ]") : heap_scope.
Notation "\Top" := (htop) : heap_scope.
Notation "H1 \--* H2" := (hwand H1 H2)
(at level 43) : heap_scope.
Notation "Q1 \---* Q2" := (qwand Q1 Q2)
(at level 43) : heap_scope.
(* ---------------------------------------------------------------------- *)
(* ** Definition of [local] *)
Notation "'~~' B" := (hprop->(B->hprop)->Prop)
(at level 8, only parsing) : type_scope.
Definition local B (F:~~B) : ~~B :=
fun (H:hprop) (Q:B->hprop) =>
H ==> Hexists H1 H2 Q1,
H1 \* H2 \* \[F H1 Q1 /\ Q1 \*+ H2 ===> Q \*+ \Top].
Definition is_local B (F:~~B) :=
F = local F.
(* ---------------------------------------------------------------------- *)
(* ** Properties *)
Parameter himpl_frame_r : forall H1 H2 H2',
H2 ==> H2' ->
(H1 \* H2) ==> (H1 \* H2').
Parameter hstar_pure : forall P H h,
(\[P] \* H) h = (P /\ H h).
Parameter hpure_intro : forall P h,
\[] h ->
P ->
\[P] h.
Parameter hpure_inv : forall P h,
\[P] h ->
P /\ \[] h.
Parameter htop_intro : forall h,
\Top h.
Parameter himpl_htop_r : forall H H',
H ==> H' ->
H ==> H' \* \Top.
Global Opaque hempty hpure hstar hexists htop.
(* ---------------------------------------------------------------------- *)
(* ** Tactics *)
Ltac hpull_xpull_iris_hook := idtac.
Ltac xlocal_core := idtac.
Parameter local_ramified_frame : forall B (Q1:B->hprop) H1 F H Q,
is_local F ->
F H1 Q1 ->
H ==> H1 \* (Q1 \---* Q) ->
F H Q.
End SepSetupGPMSig.
(* ********************************************************************** *)
(* * Proof Mode *)
Module SepLogicGPM (SC : SepCore) (SCH: SepCoreHemptySig SC) (SS : SepSetupGPMSig SC).
Export SS SCH.
(* ********************************************************************** *)
(* * Instantiating Iris Proof Mode *)
Module ProofModeInstantiate.
Import iris.bi.bi iris.proofmode.coq_tactics.
Export iris.proofmode.tactics.
Canonical Structure hpropC := leibnizC hprop.
Definition hpersistently (H : hprop) : hprop :=
fun _ => H heap_empty.
(* Proofmode's hpure has to be absorbing. So we redefine it here, and
we add later by hand the necessary infrastructure for CFML's hpure. *)
Definition hpure_abs (φ : Prop) : hprop := \[φ] \* \Top.
Program Canonical Structure hpropI : bi :=
Bi hprop _ _ (@pred_incl _) hempty hpure_abs hand hor
(@pred_impl _) hforall hexists hstar hwand hpersistently _ _.
Next Obligation. apply discrete_ofe_mixin, _. Qed.
Next Obligation.
Transparent hempty.
split; [split|..].
- intros ??; apply himpl_refl.
- intros ???; apply himpl_trans.
- intros. rewrite leibniz_equiv_iff. split=>?.
+ subst. auto.
+ apply himpl_antisym; naive_solver.
- by intros ??? ->%LibAxioms.prop_ext.
- solve_proper.
- solve_proper.
- solve_proper.
- by intros ???? ->%fun_ext_1.
- by intros ???? ->%fun_ext_1.
- solve_proper.
- solve_proper.
- solve_proper.
- intros ?????. rewrite /hpure_abs hstar_pure.
split; [done|apply htop_intro].
- intros ??. rewrite /hpure_abs=>Hφ h Hh. apply Hφ.
+ rewrite /hpure_abs hstar_pure in Hh. apply Hh.
+ rewrite hstar_pure. split; [done|]. apply htop_intro.
- rewrite /hpure_abs=>??? H. rewrite hstar_pure.
split; [|by apply htop_intro]. intros x. specialize (H x).
rewrite hstar_pure in H. apply H.
- by intros ??? [? _].
- by intros ??? [_ ?].
- intros P Q R HQ HR ?. by split; [apply HQ|apply HR].
- by left.
- by right.
- intros P Q R HP HQ ? [|]. by apply HP. by apply HQ.
- intros P Q R H ???. apply H. by split.
- intros P Q R H ? []. by apply H.
- intros A P Ψ H ???. by apply H.
- intros A Ψ a ? H. apply H.
- by eexists.
- intros A Φ Q H ? []. by eapply H.
- intros ??????. eapply pred_incl_trans. by apply himpl_frame_r.
rewrite (hstar_comm P Q') (hstar_comm Q Q'). by apply himpl_frame_r.
- intros. by rewrite hstar_hempty_l.
- intros. by rewrite hstar_hempty_l.
- intros. by rewrite hstar_comm.
- intros. by rewrite hstar_assoc.
- intros P Q R H ??. exists P. rewrite hstar_comm hstar_pure. auto.
- intros P Q R H. eapply pred_incl_trans.
{ rewrite hstar_comm. by apply himpl_frame_r. }
unfold hwand. rewrite hstar_comm hstar_hexists=>h [F HF].
rewrite (hstar_comm F) hstar_assoc hstar_pure in HF. destruct HF as [HR HF].
by apply HR.
- intros P Q H h. apply H.
- auto.
- unfold hpersistently. rewrite hempty_eq. intros h _. auto.
- auto.
- auto.
- intros P Q h. replace (hpersistently P) with (\[P heap_empty] \* \Top).
{ rewrite hstar_assoc !hstar_pure=>-[? _]. auto using htop_intro. }
extens=>h'. rewrite hstar_pure /hpersistently. naive_solver auto using htop_intro.
- intros P Q h [HP HQ]. rewrite -(hstar_hempty_l Q) in HQ.
eapply himpl_frame_l, HQ. rewrite hempty_eq. intros ? ->. apply HP.
Qed.
Lemma hpure_pure φ : \[φ] = bi_affinely ⌜φ⌝.
Proof.
extens=>h. split.
- split; [by eapply hpure_inv|by apply (himpl_htop_r (H:=\[φ]))].
- intros [? Hφ]. apply hpure_intro; [done|].
change ((\[φ] \* \Top%I) h) in Hφ. rewrite hstar_pure in Hφ. naive_solver.
Qed.
Lemma htop_True : \Top = True%I.
Proof.
extens=>h. split=>?.
- rewrite /bi_pure /= /hpure_abs hstar_pure. auto.
- apply htop_intro.
Qed.
Opaque hpure_abs.
Ltac unfold_proofmode :=
change (@bi_and hpropI) with hand;
change (@bi_or hpropI) with hor;
change (@bi_emp hpropI) with hempty;
change (@bi_forall hpropI) with hforall;
change (@bi_exist hpropI) with hexists;
change (@bi_sep hpropI) with hstar;
change (@bi_wand hpropI) with hwand.
End ProofModeInstantiate.
(* ********************************************************************** *)
(* * Tactics for better integration of Iris Proof Mode with CFML Iris *)
Module ProofMode.
Export ProofModeInstantiate.
Import iris.proofmode.coq_tactics. (* TODO: should it be Export? *)
(* We need to repeat all these hints appearing in proofmode/tactics.v,
so that they state something about CFML connectives. [Hint Extern]
patterns are not matched modulo canonical structure unification. *)
Hint Extern 0 (_ ==> _) => iStartProof.
Hint Extern 0 (envs_entails _ (hpure _)) => iPureIntro.
Hint Extern 0 (envs_entails _ (hempty)) => iEmpIntro.
Hint Extern 0 (envs_entails _ (hforall _)) => iIntros (?).
Hint Extern 0 (envs_entails _ (hwand _ _)) => iIntros "?".
Hint Extern 1 (envs_entails _ (hand _ _)) => iSplit.
Hint Extern 1 (envs_entails _ (hstar _ _)) => iSplit.
Hint Extern 1 (envs_entails _ (hexists _)) => iExists _.
Hint Extern 1 (envs_entails _ (hor _ _)) => iLeft.
Hint Extern 1 (envs_entails _ (hor _ _)) => iRight.
Hint Extern 2 (envs_entails _ (hstar _ _)) => progress iFrame : iFrame.
(* Specific instances for CFML. *)
Hint Extern 3 (envs_entails _ ?P) => is_evar P; iAccu.
Hint Extern 3 (envs_entails _ (?P _)) => is_evar P; iAccu.
Hint Extern 0 (envs_entails _ (\[_] \* _)) => iSplitR.
Hint Extern 0 (envs_entails _ (\[_] ∗ _)) => iSplitR.
Hint Extern 0 (envs_entails _ (_ \* \[_])) => iSplitL.
Hint Extern 0 (envs_entails _ (_ ∗ \[_])) => iSplitL.
Hint Extern 0 (envs_entails _ (\[] \* _)) => iSplitR.
Hint Extern 0 (envs_entails _ (\[] ∗ _)) => iSplitR.
Hint Extern 0 (envs_entails _ (_ \* \[])) => iSplitL.
Hint Extern 0 (envs_entails _ (_ ∗ \[])) => iSplitL.
(** * Specific Proofmode instances about hpure and htop. *)
Global Instance htop_absorbing : Absorbing \Top.
Proof. intros ??. apply htop_intro. Qed.
Global Instance htop_persistent : Persistent \Top.
Proof. intros ??. apply htop_intro. Qed.
Global Instance htop_into_pure : IntoPure \Top True.
Proof. unfold IntoPure. auto. Qed.
Global Instance htrop_from_pure a : FromPure a \Top True.
Proof. intros ??. apply htop_intro. Qed.
Global Instance hpure_affine φ : Affine \[φ].
Proof. rewrite hpure_pure. apply _. Qed.
Global Instance hpure_persistent φ : Persistent \[φ].
Proof. rewrite hpure_pure. apply _. Qed.
Global Instance hpure_into_pure φ : IntoPure \[φ] φ.
Proof. rewrite hpure_pure /IntoPure. by iDestruct 1 as "%". Qed.
Global Instance hpure_from_pure φ : FromPure true \[φ] φ.
Proof. by rewrite hpure_pure /FromPure /= /bi_affinely stdpp.base.comm. Qed.
Global Instance from_and_hpure φ ψ : FromAnd \[φ ∧ ψ] \[φ] \[ψ].
Proof. rewrite /FromAnd. auto. Qed.
Global Instance from_sep_hpure φ ψ : FromSep \[φ ∧ ψ] \[φ] \[ψ].
Proof. rewrite /FromSep. auto. Qed.
Global Instance into_and_hpure (p : bool) φ ψ : IntoAnd p \[φ ∧ ψ] \[φ] \[ψ].
Proof. rewrite /IntoAnd. (* do 2 f_equiv. auto. TODO *) admit. Qed.
Global Instance into_sep_hpure φ ψ : IntoSep \[φ ∧ ψ] \[φ] \[ψ].
Proof. rewrite /IntoSep. auto. Qed.
Global Instance from_or_hpure φ ψ : FromOr \[φ ∨ ψ] \[φ] \[ψ].
Proof. rewrite /FromOr. auto. Qed.
Global Instance into_or_hpure φ ψ : IntoOr \[φ ∨ ψ] \[φ] \[ψ].
Proof. rewrite /IntoOr. auto. Qed.
Global Instance from_exist_hpure {A} (φ : A → Prop) :
FromExist \[∃ x : A, φ x] (λ a : A, \[φ a]).
Proof. rewrite /FromExist. auto. Qed.
Global Instance into_exist_hpure {A} (φ : A → Prop) :
IntoExist \[∃ x : A, φ x] (λ a : A, \[φ a]).
Proof. rewrite /IntoExist. auto. Qed.
Global Instance from_forall_hpure {A : Type} `{Inhabited A} (φ : A → Prop) :
FromForall \[∀ a : A, φ a] (λ a : A, \[φ a]).
Proof. rewrite /FromForall. auto. Qed.
Global Instance frame_here_hpure p (φ : Prop) Q :
FromPure true Q φ → Frame p \[φ] Q emp.
Proof.
rewrite /FromPure /Frame=><- /=. destruct p=>/=; iIntros "[% _] !%"; auto.
Qed.
(** [PrepareHProp] / [iPrepare] tactic. *)
Class PrepareHProp (P Q : hprop) := prepare_hprop_eq : P = Q.
Hint Mode PrepareHProp ! - : typeclass_instances.
Arguments PrepareHProp _%I _%I.
Instance prepare_hprop_default (P : hprop) : PrepareHProp P P | 100.
Proof. done. Qed.
(* In the case [P ∗ Q] is under a definition, we do not wnat ot apply
this instance, because it would unfold the definition. Hence, we
use [Hint Extern] that will apply only if the star match without a
definition. *)
Lemma prepare_hprop_curry (P Q R S : hprop) :
PrepareHProp (P -∗ Q -∗ R) S → PrepareHProp (P ∗ Q -∗ R) S.
Proof.
rewrite /PrepareHProp=><-. apply leibniz_equiv. iSplit.
- iIntros "H ? ?"; iApply "H"; iFrame.
- iIntros "H [??]". by iApply ("H" with "[$]").
Qed.
Hint Extern 1 (PrepareHProp ((_ ∗ _) -∗ _) _) =>
simple eapply prepare_hprop_curry : typeclass_instances.
Hint Extern 1 (PrepareHProp ((_ \* _) -∗ _) _) =>
simple eapply prepare_hprop_curry : typeclass_instances.
Hint Extern 1 (PrepareHProp ((_ ∗ _)%I \--* _) _) =>
simple eapply prepare_hprop_curry : typeclass_instances.
Hint Extern 1 (PrepareHProp ((_ \* _) \--* _) _) =>
simple eapply prepare_hprop_curry : typeclass_instances.
Instance prepare_hprop_hempty_wand (P Q : hprop) :
PrepareHProp P Q → PrepareHProp (\[] -∗ P) Q.
Proof.
rewrite /PrepareHProp=><-. apply leibniz_equiv. iSplit; [|by iIntros "$ _"].
iIntros "H". by iApply "H".
Qed.
Instance prepare_hprop_next (P Q R : hprop) :
PrepareHProp P Q → PrepareHProp (R -∗ P) (R -∗ Q) | 10.
Proof. by rewrite /PrepareHProp=> ->. Qed.
Instance prepare_hprop_forall {A} (Φ Ψ : A → hprop) :
(∀ x, PrepareHProp (Φ x) (Ψ x)) → PrepareHProp (∀ x, Φ x) (∀ x, Ψ x).
Proof. rewrite /PrepareHProp=> H. by setoid_rewrite H. Qed.
Instance prepare_hprop_hstar (P P' Q Q' : hprop) :
PrepareHProp P P' → PrepareHProp Q Q' → PrepareHProp (P ∗ Q) (P' ∗ Q') | 10.
Proof. by rewrite /PrepareHProp=>-> ->. Qed.
Lemma prepare_hprop_hemp_hstar (P Q : hprop) :
PrepareHProp P Q → PrepareHProp (\[] \* P) Q.
Proof. rewrite /PrepareHProp=>->. by rewrite left_id. Qed.
Hint Extern 1 (PrepareHProp (\[] \* _) _) =>
simple apply prepare_hprop_hemp_hstar : typeclass_instances.
Hint Extern 1 (PrepareHProp (\[] ∗ _) _) =>
simple apply prepare_hprop_hemp_hstar : typeclass_instances.
Hint Extern 1 (PrepareHProp (emp%I \* _)%I _) =>
simple apply prepare_hprop_hemp_hstar : typeclass_instances.
Hint Extern 1 (PrepareHProp (emp ∗ _) _) =>
simple apply prepare_hprop_hemp_hstar : typeclass_instances.
Lemma prepare_hprop_hstar_hemp (P Q : hprop) :
PrepareHProp P Q → PrepareHProp (P \* \[]) Q.
Proof. rewrite /PrepareHProp=>->. by rewrite right_id. Qed.
Hint Extern 1 (PrepareHProp (_ \* \[]) _) =>
simple apply prepare_hprop_hstar_hemp : typeclass_instances.
Hint Extern 1 (PrepareHProp (_ ∗ \[]) _) =>
simple apply prepare_hprop_hstar_hemp : typeclass_instances.
Hint Extern 1 (PrepareHProp (_ \* emp%I)%I _) =>
simple apply prepare_hprop_hstar_hemp : typeclass_instances.
Hint Extern 1 (PrepareHProp (_ ∗ emp) _) =>
simple apply prepare_hprop_hstar_hemp : typeclass_instances.
Instance prepare_hprop_absorbingly (P Q : hprop) :
PrepareHProp P Q → PrepareHProp (<absorb> P) (<absorb> Q).
Proof. by unfold PrepareHProp=>->. Qed.
Lemma tac_prepare Δ (P Q : hprop) :
PrepareHProp P Q →
envs_entails Δ Q →
envs_entails Δ P.
Proof. by rewrite /PrepareHProp=>->. Qed.
Ltac iPrepare :=
iStartProof;
eapply tac_prepare; [apply _|cbv beta].
(* ProofMode's [iIntros] tend to move pure facts in Coq's context.
While, in general, this is desirable, this is not what we want
after having applied [local_ramified_frame] because we would loose
pure facts that will not be unified in [Q] when [Q] is an evar. As
a result, we use a specific version of this lemma where Q1 is
locked, and hence pure facts cannot escape.
This specific version is only used when the post-condition is
indeed an evar. *)
Lemma local_ramified_frame_locked {B} : forall (Q1 : B → hprop) H1 F H Q,
is_local F ->
F H1 Q1 ->
H ==> H1 \* (locked Q1 \---* Q) ->
F H Q.
Proof using. unlock. apply local_ramified_frame. Qed.
Ltac ram_apply lem :=
lazymatch goal with
| |- ?F _ ?Q =>
(is_evar Q; eapply local_ramified_frame_locked) ||
eapply local_ramified_frame
end; [xlocal_core tt|eapply lem|iPrepare].
(** Fix for hpull/xpull to unfold proof mode functions *)
Ltac hpull_xpull_iris_hook tt ::=
ProofModeInstantiate.unfold_proofmode.
End ProofMode.
End SepLogicGPM.