diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1fa75c28797a6a1f7544030ae2f3c606c272fcea..8ab85ac5c05a8870df09ef77cb295a5aa31f21f3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,6 +3,7 @@ image: ralfjung/opam-ci:latest stages: - build - deploy + - build_more variables: CPU_CORES: "9" @@ -19,7 +20,6 @@ variables: - 'time make -k -j$CPU_CORES TIMED=y 2>&1 | tee build-log.txt' - 'if fgrep Axiom build-log.txt >/dev/null; then exit 1; fi' - 'cat build-log.txt | egrep "[a-zA-Z0-9_/-]+ \((real|user): [0-9]" | tee build-time.txt' - - 'if test -n "$VALIDATE" && (( RANDOM % 10 == 0 )); then make validate; fi' cache: key: "$CI_JOB_NAME" paths: @@ -42,6 +42,7 @@ opam: build-coq.8.7.dev: <<: *template + stage: build_more variables: OPAM_PINS: "coq version 8.7.dev" artifacts: diff --git a/docs/algebra.tex b/docs/algebra.tex index 9cfed25eaca982e31b347286ce1b1b4eabe61bd7..3ba0967042888774ba91ee1af53f50d672ba8acc 100644 --- a/docs/algebra.tex +++ b/docs/algebra.tex @@ -37,7 +37,8 @@ Elements that cannot be distinguished by programs within $n$ steps remain indist The category $\OFEs$ consists of OFEs as objects, and non-expansive functions as arrows. \end{defn} -Note that $\OFEs$ is cartesian closed. In particular: +Note that $\OFEs$ is bicartesian closed, \ie it has all sums, products and exponentials as well as an initial and a terminal object. +In particular: \begin{defn} Given two OFEs $\ofe$ and $\ofeB$, the set of non-expansive functions $\set{f : \ofe \nfn \ofeB}$ is itself an OFE with \begin{align*} diff --git a/docs/base-logic.tex b/docs/base-logic.tex index f0b97ad9c950ade18eae79cfd362e1052dca58d4..2a45cae7cbd88a1fc94619caf86a6a06aadb95df 100644 --- a/docs/base-logic.tex +++ b/docs/base-logic.tex @@ -32,18 +32,25 @@ Below, $\melt$ ranges over $\monoid$ and $i$ ranges over $\set{1,2}$. \begin{align*} \type \bnfdef{}& \sigtype \mid + 0 \mid 1 \mid + \type + \type \mid \type \times \type \mid \type \to \type \\[0.4em] \term, \prop, \pred \bnfdef{}& \var \mid \sigfn(\term_1, \dots, \term_n) \mid + \textlog{abort}\; \term \mid () \mid (\term, \term) \mid \pi_i\; \term \mid \Lam \var:\type.\term \mid \term(\term) \mid +\\& + \textlog{inj}_i\; \term \mid + \textlog{match}\; \term \;\textlog{with}\; \Ret\textlog{inj}_1\; \var. \term \mid \Ret\textlog{inj}_2\; \var. \term \;\textlog{end} \mid +% \melt \mid \mcore\term \mid \term \mtimes \term \mid @@ -67,7 +74,10 @@ Below, $\melt$ ranges over $\monoid$ and $i$ ranges over $\set{1,2}$. {\later\prop} \mid \upd \prop \end{align*} -Recursive predicates must be \emph{guarded}: in $\MU \var. \term$, the variable $\var$ can only appear under the later $\later$ modality. +Well-typedness forces recursive definitions to be \emph{guarded}: +In $\MU \var. \term$, the variable $\var$ can only appear under the later $\later$ modality. +Furthermore, the type of the definition must be \emph{complete}. +The type $\Prop$ is complete, and if $\type$ is complete, then so is $\type' \to \type$. Note that the modalities $\upd$, $\always$, $\plainly$ and $\later$ bind more tightly than $*$, $\wand$, $\land$, $\lor$, and $\Ra$. @@ -106,7 +116,10 @@ In writing $\vctx, x:\type$, we presuppose that $x$ is not already declared in $ }{ \vctx \proves \wtt {\sigfn(\term_1, \dots, \term_n)} {\type_{n+1}} } -%%% products +%%% empty, unit, products, sums +\and + \infer{\vctx \proves \wtt\term{0}} + {\vctx \proves \wtt{\textlog{abort}\; \term}\type} \and \axiom{\vctx \proves \wtt{()}{1}} \and @@ -115,6 +128,14 @@ In writing $\vctx, x:\type$, we presuppose that $x$ is not already declared in $ \and \infer{\vctx \proves \wtt{\term}{\type_1 \times \type_2} \and i \in \{1, 2\}} {\vctx \proves \wtt{\pi_i\,\term}{\type_i}} +\and + \infer{\vctx \proves \wtt\term{\type_i} \and i \in \{1, 2\}} + {\vctx \proves \wtt{\textlog{inj}_i\;\term}{\type_1 + \type_2}} +\and + \infer{\vctx \proves \wtt\term{\type_1 + \type_2} \and + \vctx, \var:\type_1 \proves \wtt{\term_1}\type \and + \vctx, \varB:\type_2 \proves \wtt{\term_2}\type} + {\vctx \proves \wtt{\textlog{match}\; \term \;\textlog{with}\; \Ret\textlog{inj}_1\; \var. \term_1 \mid \Ret\textlog{inj}_2\; \varB. \term_2 \;\textlog{end}}{\type}} %%% functions \and \infer{\vctx, x:\type \proves \wtt{\term}{\type'}} @@ -125,7 +146,7 @@ In writing $\vctx, x:\type$, we presuppose that $x$ is not already declared in $ {\vctx \proves \wtt{\term(\termB)}{\type'}} %%% monoids \and - \infer{}{\vctx \proves \wtt\munit{\textlog{M}}} + \infer{}{\vctx \proves \wtt\melt{\textlog{M}}} \and \infer{\vctx \proves \wtt\melt{\textlog{M}}}{\vctx \proves \wtt{\mcore\melt}{\textlog{M}}} \and @@ -157,7 +178,8 @@ In writing $\vctx, x:\type$, we presuppose that $x$ is not already declared in $ \and \infer{ \vctx, \var:\type \proves \wtt{\term}{\type} \and - \text{$\var$ is guarded in $\term$} + \text{$\var$ is guarded in $\term$} \and + \text{$\type$ is complete} }{ \vctx \proves \wtt{\MU \var:\type. \term}{\type} } @@ -286,7 +308,7 @@ This is entirely standard. % {} % {\pfctx \proves \mu\var: \type. \prop =_{\type} \prop[\mu\var: \type. \prop/\var]} \end{mathparpagebreakable} -Furthermore, we have the usual $\eta$ and $\beta$ laws for projections, $\lambda$ and $\mu$. +Furthermore, we have the usual $\eta$ and $\beta$ laws for projections, $\textlog{abort}$, sum elimination, $\lambda$ and $\mu$. \paragraph{Laws of (affine) bunched implications.} @@ -317,8 +339,8 @@ Furthermore, we have the usual $\eta$ and $\beta$ laws for projections, $\lambda {\plainly\prop \proves \always\prop} \and \begin{array}[c]{rMcMl} - \TRUE &\proves& \plainly{\TRUE} \\ - (\plainly P \Ra \plainly Q) &\proves& \plainly (\plainly P \Ra Q) + (\plainly P \Ra \plainly Q) &\proves& \plainly (\plainly P \Ra Q) \\ +\plainly ( ( P \Ra Q) \land (Q \Ra P ) ) &\proves& P =_{\Prop} Q \end{array} \and \begin{array}[c]{rMcMl} @@ -326,8 +348,8 @@ Furthermore, we have the usual $\eta$ and $\beta$ laws for projections, $\lambda \All x. \plainly{\prop} &\proves& \plainly{\All x. \prop} \\ \plainly{\Exists x. \prop} &\proves& \Exists x. \plainly{\prop} \end{array} -\and -\infer[PropExt]{}{\plainly ( ( P \Ra Q) \land (Q \Ra P ) ) \proves P =_{\Prop} Q} +%\and +%\infer[PropExt]{}{\plainly ( ( P \Ra Q) \land (Q \Ra P ) ) \proves P =_{\Prop} Q} \end{mathpar} \paragraph{Laws for the persistence modality.} @@ -340,8 +362,8 @@ Furthermore, we have the usual $\eta$ and $\beta$ laws for projections, $\lambda {\always\prop \proves \prop} \and \begin{array}[c]{rMcMl} - \always{\prop} \land \propB &\proves& \always{\prop} * \propB \\ - (\plainly P \Ra \always Q) &\proves& \always (\plainly P \Ra Q) + (\plainly P \Ra \always Q) &\proves& \always (\plainly P \Ra Q) \\ + \always{\prop} \land \propB &\proves& \always{\prop} * \propB \end{array} \and \begin{array}[c]{rMcMl} @@ -358,7 +380,7 @@ Furthermore, we have the usual $\eta$ and $\beta$ laws for projections, $\lambda {\prop \proves \propB} {\later\prop \proves \later{\propB}} \and -\infer[L{\"o}b] +\inferhref{L{\"o}b}{Loeb} {} {(\later\prop\Ra\prop) \proves \prop} \and diff --git a/docs/ghost-state.tex b/docs/ghost-state.tex index d8cd9b8fa4d95d17197ec5a4dd8672854f2deede..bd10d54efa60000c9290d79789776440300a521a 100644 --- a/docs/ghost-state.tex +++ b/docs/ghost-state.tex @@ -35,8 +35,13 @@ We collect here some important and frequently used derived proof rules. \infer{} {\prop \proves \later\prop} + + \infer{} + {\TRUE \proves \plainly\TRUE} \end{mathparpagebreakable} +Noteworthy here is the fact that $\prop \proves \later\prop$ can be derived from Löb induction, and $\TRUE \proves \plainly\TRUE$ can be derived via $\plainly$ commuting with universal quantification ranging over the empty type $0$. + \subsection{Persistent assertions} We call an assertion $\prop$ \emph{persistent} if $\prop \proves \always\prop$. These are assertions that ``don't own anything'', so we can (and will) treat them like ``normal'' intuitionistic assertions. diff --git a/docs/model.tex b/docs/model.tex index af3ed1e4fd53c6eb62d3d2e139e68589bc12669b..6100fb39be49d0689d410ad482466b1962b4a34e 100644 --- a/docs/model.tex +++ b/docs/model.tex @@ -9,11 +9,13 @@ The semantic domains are interpreted as follows: \[ \begin{array}[t]{@{}l@{\ }c@{\ }l@{}} \Sem{\Prop} &\eqdef& \UPred(\monoid) \\ -\Sem{\textlog{M}} &\eqdef& \monoid +\Sem{\textlog{M}} &\eqdef& \monoid \\ +\Sem{0} &\eqdef& \Delta \emptyset \\ +\Sem{1} &\eqdef& \Delta \{ () \} \end{array} \qquad\qquad \begin{array}[t]{@{}l@{\ }c@{\ }l@{}} -\Sem{1} &\eqdef& \Delta \{ () \} \\ +\Sem{\type + \type'} &\eqdef& \Sem{\type} + \Sem{\type} \\ \Sem{\type \times \type'} &\eqdef& \Sem{\type} \times \Sem{\type} \\ \Sem{\type \to \type'} &\eqdef& \Sem{\type} \nfn \Sem{\type} \\ \end{array} @@ -80,9 +82,15 @@ For every definition, we have to show all the side-conditions: The maps have to \Sem{\vctx \proves \MU \var:\type. \term : \type}_\gamma &\eqdef \mathit{fix}(\Lam \termB : \Sem{\type}. \Sem{\vctx, x : \type \proves \term : \type}_{\mapinsert \var \termB \gamma}) \\ ~\\ + \Sem{\vctx \proves \textlog{abort}\;\term : \type}_\gamma &\eqdef \mathit{abort}_{\Sem\type}(\Sem{\vctx \proves \term:0}_\gamma) \\ \Sem{\vctx \proves () : 1}_\gamma &\eqdef () \\ \Sem{\vctx \proves (\term_1, \term_2) : \type_1 \times \type_2}_\gamma &\eqdef (\Sem{\vctx \proves \term_1 : \type_1}_\gamma, \Sem{\vctx \proves \term_2 : \type_2}_\gamma) \\ - \Sem{\vctx \proves \pi_i(\term) : \type_i}_\gamma &\eqdef \pi_i(\Sem{\vctx \proves \term : \type_1 \times \type_2}_\gamma) \\ + \Sem{\vctx \proves \pi_i\; \term : \type_i}_\gamma &\eqdef \pi_i(\Sem{\vctx \proves \term : \type_1 \times \type_2}_\gamma) \\ + \Sem{\vctx \proves \textlog{inj}_i\;\term : \type_1 + \type_2}_\gamma &\eqdef \mathit{inj}_i(\Sem{\vctx \proves \term : \type_i}_\gamma) \\ + \Sem{\vctx \proves \textlog{match}\; \term \;\textlog{with}\; \Ret\textlog{inj}_1\; \var_1. \term_1 \mid \Ret\textlog{inj}_2\; \var_2. \term_2 \;\textlog{end} : \type }_\gamma &\eqdef + \Sem{\vctx, \var_i:\type_i \proves \term_i : \type}_{\mapinsert{\var_i}\termB \gamma} \\ + &\qquad \text{where $\Sem{\vctx \proves \term : \type_1 + \type_2}_\gamma = \mathit{inj}_i(\termB)$} + \\ ~\\ \Sem{ \melt : \textlog{M} }_\gamma &\eqdef \melt \\ \Sem{\vctx \proves \mcore\term : \textlog{M}}_\gamma &\eqdef \mcore{\Sem{\vctx \proves \term : \textlog{M}}_\gamma} \\ @@ -94,6 +102,7 @@ For every definition, we have to show all the side-conditions: The maps have to An environment $\vctx$ is interpreted as the set of finite partial functions $\rho$, with $\dom(\rho) = \dom(\vctx)$ and $\rho(x)\in\Sem{\vctx(x)}$. +Above, $\mathit{fix}$ is the fixed-point on COFEs, and $\mathit{abort}_T$ is the unique function $\emptyset \to T$. \paragraph{Logical entailment.} We can now define \emph{semantic} logical entailment. diff --git a/opam b/opam index f15ec44511f6d54609188b7f973bb8133d67400f..5d2cef8c9c67aa0b71e0c65377d97c3ea58ee6bc 100644 --- a/opam +++ b/opam @@ -10,6 +10,6 @@ build: [make "-j%{jobs}%"] install: [make "install"] remove: ["rm" "-rf" "%{lib}%/coq/user-contrib/iris"] depends: [ - "coq" { >= "8.7.dev" & < "8.8~" } - "coq-stdpp" { (= "dev.2017-11-22.1") | (= "dev") } + "coq" { >= "8.7.dev" & < "8.8~" | (= "dev") } + "coq-stdpp" { (= "dev.2017-11-29.1") | (= "dev") } ] diff --git a/theories/algebra/cmra.v b/theories/algebra/cmra.v index 8c0aadf791ecb702288bf281048c42c97cccc463..0c1a040fe84a3579d0eb511bb74d34e1ac80caf9 100644 --- a/theories/algebra/cmra.v +++ b/theories/algebra/cmra.v @@ -555,11 +555,15 @@ Proof. split; first by rewrite cmra_valid_validN. eauto using cmra_discrete_valid, cmra_validN_le with lia. Qed. +Lemma cmra_discrete_valid_iff_0 `{CmraDiscrete A} n x : ✓{0} x ↔ ✓{n} x. +Proof. by rewrite -!cmra_discrete_valid_iff. Qed. Lemma cmra_discrete_included_iff `{OfeDiscrete A} n x y : x ≼ y ↔ x ≼{n} y. Proof. split; first by apply cmra_included_includedN. intros [z ->%(discrete_iff _ _)]; eauto using cmra_included_l. Qed. +Lemma cmra_discrete_included_iff_0 `{OfeDiscrete A} n x y : x ≼{0} y ↔ x ≼{n} y. +Proof. by rewrite -!cmra_discrete_included_iff. Qed. (** Cancelable elements *) Global Instance cancelable_proper : Proper (equiv ==> iff) (@Cancelable A). @@ -1231,92 +1235,93 @@ Qed. (** ** CMRA for the option type *) Section option. Context {A : cmraT}. - Implicit Types x y : A. + Implicit Types a b : A. + Implicit Types ma mb : option A. Local Arguments core _ _ !_ /. Local Arguments pcore _ _ !_ /. - Instance option_valid : Valid (option A) := λ mx, - match mx with Some x => ✓ x | None => True end. - Instance option_validN : ValidN (option A) := λ n mx, - match mx with Some x => ✓{n} x | None => True end. - Instance option_pcore : PCore (option A) := λ mx, Some (mx ≫= pcore). + Instance option_valid : Valid (option A) := λ ma, + match ma with Some a => ✓ a | None => True end. + Instance option_validN : ValidN (option A) := λ n ma, + match ma with Some a => ✓{n} a | None => True end. + Instance option_pcore : PCore (option A) := λ ma, Some (ma ≫= pcore). Arguments option_pcore !_ /. - Instance option_op : Op (option A) := union_with (λ x y, Some (x ⋅ y)). - - Definition Some_valid x : ✓ Some x ↔ ✓ x := reflexivity _. - Definition Some_validN x n : ✓{n} Some x ↔ ✓{n} x := reflexivity _. - Definition Some_op x y : Some (x ⋅ y) = Some x ⋅ Some y := eq_refl. - Lemma Some_core `{CmraTotal A} x : Some (core x) = core (Some x). - Proof. rewrite /core /=. by destruct (cmra_total x) as [? ->]. Qed. - Lemma Some_op_opM x my : Some x ⋅ my = Some (x ⋅? my). - Proof. by destruct my. Qed. - - Lemma option_included (mx my : option A) : - mx ≼ my ↔ mx = None ∨ ∃ x y, mx = Some x ∧ my = Some y ∧ (x ≡ y ∨ x ≼ y). + Instance option_op : Op (option A) := union_with (λ a b, Some (a ⋅ b)). + + Definition Some_valid a : ✓ Some a ↔ ✓ a := reflexivity _. + Definition Some_validN a n : ✓{n} Some a ↔ ✓{n} a := reflexivity _. + Definition Some_op a b : Some (a ⋅ b) = Some a ⋅ Some b := eq_refl. + Lemma Some_core `{CmraTotal A} a : Some (core a) = core (Some a). + Proof. rewrite /core /=. by destruct (cmra_total a) as [? ->]. Qed. + Lemma Some_op_opM a ma : Some a ⋅ ma = Some (a ⋅? ma). + Proof. by destruct ma. Qed. + + Lemma option_included ma mb : + ma ≼ mb ↔ ma = None ∨ ∃ a b, ma = Some a ∧ mb = Some b ∧ (a ≡ b ∨ a ≼ b). Proof. split. - - intros [mz Hmz]. - destruct mx as [x|]; [right|by left]. - destruct my as [y|]; [exists x, y|destruct mz; inversion_clear Hmz]. - destruct mz as [z|]; inversion_clear Hmz; split_and?; auto; + - intros [mc Hmc]. + destruct ma as [a|]; [right|by left]. + destruct mb as [b|]; [exists a, b|destruct mc; inversion_clear Hmc]. + destruct mc as [c|]; inversion_clear Hmc; split_and?; auto; setoid_subst; eauto using cmra_included_l. - - intros [->|(x&y&->&->&[Hz|[z Hz]])]. - + exists my. by destruct my. + - intros [->|(a&b&->&->&[Hc|[c Hc]])]. + + exists mb. by destruct mb. + exists None; by constructor. - + exists (Some z); by constructor. + + exists (Some c); by constructor. Qed. - Lemma option_includedN n (mx my : option A) : - mx ≼{n} my ↔ mx = None ∨ ∃ x y, mx = Some x ∧ my = Some y ∧ (x ≡{n}≡ y ∨ x ≼{n} y). + Lemma option_includedN n ma mb : + ma ≼{n} mb ↔ ma = None ∨ ∃ x y, ma = Some x ∧ mb = Some y ∧ (x ≡{n}≡ y ∨ x ≼{n} y). Proof. split. - - intros [mz Hmz]. - destruct mx as [x|]; [right|by left]. - destruct my as [y|]; [exists x, y|destruct mz; inversion_clear Hmz]. - destruct mz as [z|]; inversion_clear Hmz; split_and?; auto; + - intros [mc Hmc]. + destruct ma as [a|]; [right|by left]. + destruct mb as [b|]; [exists a, b|destruct mc; inversion_clear Hmc]. + destruct mc as [c|]; inversion_clear Hmc; split_and?; auto; ofe_subst; eauto using cmra_includedN_l. - - intros [->|(x&y&->&->&[Hz|[z Hz]])]. - + exists my. by destruct my. + - intros [->|(a&y&->&->&[Hc|[c Hc]])]. + + exists mb. by destruct mb. + exists None; by constructor. - + exists (Some z); by constructor. + + exists (Some c); by constructor. Qed. Lemma option_cmra_mixin : CmraMixin (option A). Proof. apply cmra_total_mixin. - eauto. - - by intros [x|] n; destruct 1; constructor; ofe_subst. + - by intros [a|] n; destruct 1; constructor; ofe_subst. - destruct 1; by ofe_subst. - by destruct 1; rewrite /validN /option_validN //=; ofe_subst. - - intros [x|]; [apply cmra_valid_validN|done]. - - intros n [x|]; unfold validN, option_validN; eauto using cmra_validN_S. - - intros [x|] [y|] [z|]; constructor; rewrite ?assoc; auto. - - intros [x|] [y|]; constructor; rewrite 1?comm; auto. - - intros [x|]; simpl; auto. - destruct (pcore x) as [cx|] eqn:?; constructor; eauto using cmra_pcore_l. - - intros [x|]; simpl; auto. - destruct (pcore x) as [cx|] eqn:?; simpl; eauto using cmra_pcore_idemp. - - intros mx my; setoid_rewrite option_included. - intros [->|(x&y&->&->&[?|?])]; simpl; eauto. - + destruct (pcore x) as [cx|] eqn:?; eauto. - destruct (cmra_pcore_proper x y cx) as (?&?&?); eauto 10. - + destruct (pcore x) as [cx|] eqn:?; eauto. - destruct (cmra_pcore_mono x y cx) as (?&?&?); eauto 10. - - intros n [x|] [y|]; rewrite /validN /option_validN /=; + - intros [a|]; [apply cmra_valid_validN|done]. + - intros n [a|]; unfold validN, option_validN; eauto using cmra_validN_S. + - intros [a|] [b|] [c|]; constructor; rewrite ?assoc; auto. + - intros [a|] [b|]; constructor; rewrite 1?comm; auto. + - intros [a|]; simpl; auto. + destruct (pcore a) as [ca|] eqn:?; constructor; eauto using cmra_pcore_l. + - intros [a|]; simpl; auto. + destruct (pcore a) as [ca|] eqn:?; simpl; eauto using cmra_pcore_idemp. + - intros ma mb; setoid_rewrite option_included. + intros [->|(a&b&->&->&[?|?])]; simpl; eauto. + + destruct (pcore a) as [ca|] eqn:?; eauto. + destruct (cmra_pcore_proper a b ca) as (?&?&?); eauto 10. + + destruct (pcore a) as [ca|] eqn:?; eauto. + destruct (cmra_pcore_mono a b ca) as (?&?&?); eauto 10. + - intros n [a|] [b|]; rewrite /validN /option_validN /=; eauto using cmra_validN_op_l. - - intros n mx my1 my2. - destruct mx as [x|], my1 as [y1|], my2 as [y2|]; intros Hx Hx'; + - intros n ma mb1 mb2. + destruct ma as [a|], mb1 as [b1|], mb2 as [b2|]; intros Hx Hx'; inversion_clear Hx'; auto. - + destruct (cmra_extend n x y1 y2) as (z1&z2&?&?&?); auto. - by exists (Some z1), (Some z2); repeat constructor. - + by exists (Some x), None; repeat constructor. - + by exists None, (Some x); repeat constructor. + + destruct (cmra_extend n a b1 b2) as (c1&c2&?&?&?); auto. + by exists (Some c1), (Some c2); repeat constructor. + + by exists (Some a), None; repeat constructor. + + by exists None, (Some a); repeat constructor. + exists None, None; repeat constructor. Qed. Canonical Structure optionR := CmraT (option A) option_cmra_mixin. Global Instance option_cmra_discrete : CmraDiscrete A → CmraDiscrete optionR. - Proof. split; [apply _|]. by intros [x|]; [apply (cmra_discrete_valid x)|]. Qed. + Proof. split; [apply _|]. by intros [a|]; [apply (cmra_discrete_valid a)|]. Qed. Instance option_unit : Unit (option A) := None. Lemma option_ucmra_mixin : UcmraMixin optionR. @@ -1324,61 +1329,63 @@ Section option. Canonical Structure optionUR := UcmraT (option A) option_ucmra_mixin. (** Misc *) - Lemma op_None mx my : mx ⋅ my = None ↔ mx = None ∧ my = None. - Proof. destruct mx, my; naive_solver. Qed. - Lemma op_is_Some mx my : is_Some (mx ⋅ my) ↔ is_Some mx ∨ is_Some my. - Proof. rewrite -!not_eq_None_Some op_None. destruct mx, my; naive_solver. Qed. + Lemma op_None ma mb : ma ⋅ mb = None ↔ ma = None ∧ mb = None. + Proof. destruct ma, mb; naive_solver. Qed. + Lemma op_is_Some ma mb : is_Some (ma ⋅ mb) ↔ is_Some ma ∨ is_Some mb. + Proof. rewrite -!not_eq_None_Some op_None. destruct ma, mb; naive_solver. Qed. + + Lemma cmra_opM_assoc' a mb mc : a ⋅? mb ⋅? mc ≡ a ⋅? (mb ⋅ mc). + Proof. destruct mb, mc; by rewrite /= -?assoc. Qed. - Global Instance Some_core_id (x : A) : CoreId x → CoreId (Some x). + Global Instance Some_core_id a : CoreId a → CoreId (Some a). Proof. by constructor. Qed. - Global Instance option_core_id (mx : option A) : - (∀ x : A, CoreId x) → CoreId mx. - Proof. intros. destruct mx; apply _. Qed. - - Lemma exclusiveN_Some_l n x `{!Exclusive x} my : - ✓{n} (Some x ⋅ my) → my = None. - Proof. destruct my. move=> /(exclusiveN_l _ x) []. done. Qed. - Lemma exclusiveN_Some_r n x `{!Exclusive x} my : - ✓{n} (my ⋅ Some x) → my = None. + Global Instance option_core_id ma : (∀ x : A, CoreId x) → CoreId ma. + Proof. intros. destruct ma; apply _. Qed. + + Lemma exclusiveN_Some_l n a `{!Exclusive a} mb : + ✓{n} (Some a ⋅ mb) → mb = None. + Proof. destruct mb. move=> /(exclusiveN_l _ a) []. done. Qed. + Lemma exclusiveN_Some_r n a `{!Exclusive a} mb : + ✓{n} (mb ⋅ Some a) → mb = None. Proof. rewrite comm. by apply exclusiveN_Some_l. Qed. - Lemma exclusive_Some_l x `{!Exclusive x} my : ✓ (Some x ⋅ my) → my = None. - Proof. destruct my. move=> /(exclusive_l x) []. done. Qed. - Lemma exclusive_Some_r x `{!Exclusive x} my : ✓ (my ⋅ Some x) → my = None. + Lemma exclusive_Some_l a `{!Exclusive a} mb : ✓ (Some a ⋅ mb) → mb = None. + Proof. destruct mb. move=> /(exclusive_l a) []. done. Qed. + Lemma exclusive_Some_r a `{!Exclusive a} mb : ✓ (mb ⋅ Some a) → mb = None. Proof. rewrite comm. by apply exclusive_Some_l. Qed. - Lemma Some_includedN n x y : Some x ≼{n} Some y ↔ x ≡{n}≡ y ∨ x ≼{n} y. + Lemma Some_includedN n a b : Some a ≼{n} Some b ↔ a ≡{n}≡ b ∨ a ≼{n} b. Proof. rewrite option_includedN; naive_solver. Qed. - Lemma Some_included x y : Some x ≼ Some y ↔ x ≡ y ∨ x ≼ y. + Lemma Some_included a b : Some a ≼ Some b ↔ a ≡ b ∨ a ≼ b. Proof. rewrite option_included; naive_solver. Qed. - Lemma Some_included_2 x y : x ≼ y → Some x ≼ Some y. + Lemma Some_included_2 a b : a ≼ b → Some a ≼ Some b. Proof. rewrite Some_included; eauto. Qed. - Lemma Some_includedN_total `{CmraTotal A} n x y : Some x ≼{n} Some y ↔ x ≼{n} y. + Lemma Some_includedN_total `{CmraTotal A} n a b : Some a ≼{n} Some b ↔ a ≼{n} b. Proof. rewrite Some_includedN. split. by intros [->|?]. eauto. Qed. - Lemma Some_included_total `{CmraTotal A} x y : Some x ≼ Some y ↔ x ≼ y. + Lemma Some_included_total `{CmraTotal A} a b : Some a ≼ Some b ↔ a ≼ b. Proof. rewrite Some_included. split. by intros [->|?]. eauto. Qed. - Lemma Some_includedN_exclusive n x `{!Exclusive x} y : - Some x ≼{n} Some y → ✓{n} y → x ≡{n}≡ y. + Lemma Some_includedN_exclusive n a `{!Exclusive a} b : + Some a ≼{n} Some b → ✓{n} b → a ≡{n}≡ b. Proof. move=> /Some_includedN [//|/exclusive_includedN]; tauto. Qed. - Lemma Some_included_exclusive x `{!Exclusive x} y : - Some x ≼ Some y → ✓ y → x ≡ y. + Lemma Some_included_exclusive a `{!Exclusive a} b : + Some a ≼ Some b → ✓ b → a ≡ b. Proof. move=> /Some_included [//|/exclusive_included]; tauto. Qed. - Lemma is_Some_includedN n mx my : mx ≼{n} my → is_Some mx → is_Some my. + Lemma is_Some_includedN n ma mb : ma ≼{n} mb → is_Some ma → is_Some mb. Proof. rewrite -!not_eq_None_Some option_includedN. naive_solver. Qed. - Lemma is_Some_included mx my : mx ≼ my → is_Some mx → is_Some my. + Lemma is_Some_included ma mb : ma ≼ mb → is_Some ma → is_Some mb. Proof. rewrite -!not_eq_None_Some option_included. naive_solver. Qed. - Global Instance cancelable_Some x : - IdFree x → Cancelable x → Cancelable (Some x). + Global Instance cancelable_Some a : + IdFree a → Cancelable a → Cancelable (Some a). Proof. - intros Hirr ?? [y|] [z|] ? EQ; inversion_clear EQ. - - constructor. by apply (cancelableN x). - - destruct (Hirr y); [|eauto using dist_le with lia]. - by eapply (cmra_validN_op_l 0 x y), (cmra_validN_le n); last lia. - - destruct (Hirr z); [|symmetry; eauto using dist_le with lia]. + intros Hirr ?? [b|] [c|] ? EQ; inversion_clear EQ. + - constructor. by apply (cancelableN a). + - destruct (Hirr b); [|eauto using dist_le with lia]. + by eapply (cmra_validN_op_l 0 a b), (cmra_validN_le n); last lia. + - destruct (Hirr c); [|symmetry; eauto using dist_le with lia]. by eapply (cmra_validN_le n); last lia. - done. Qed. @@ -1389,35 +1396,37 @@ Arguments optionUR : clear implicits. Section option_prod. Context {A B : cmraT}. + Implicit Types a : A. + Implicit Types b : B. - Lemma Some_pair_includedN n (x1 x2 : A) (y1 y2 : B) : - Some (x1,y1) ≼{n} Some (x2,y2) → Some x1 ≼{n} Some x2 ∧ Some y1 ≼{n} Some y2. + Lemma Some_pair_includedN n a1 a2 b1 b2 : + Some (a1,b1) ≼{n} Some (a2,b2) → Some a1 ≼{n} Some a2 ∧ Some b1 ≼{n} Some b2. Proof. rewrite !Some_includedN. intros [[??]|[??]%prod_includedN]; eauto. Qed. - Lemma Some_pair_includedN_total_1 `{CmraTotal A} n (x1 x2 : A) (y1 y2 : B) : - Some (x1,y1) ≼{n} Some (x2,y2) → x1 ≼{n} x2 ∧ Some y1 ≼{n} Some y2. - Proof. intros ?%Some_pair_includedN. by rewrite -(Some_includedN_total _ x1). Qed. - Lemma Some_pair_includedN_total_2 `{CmraTotal B} n (x1 x2 : A) (y1 y2 : B) : - Some (x1,y1) ≼{n} Some (x2,y2) → Some x1 ≼{n} Some x2 ∧ y1 ≼{n} y2. - Proof. intros ?%Some_pair_includedN. by rewrite -(Some_includedN_total _ y1). Qed. - - Lemma Some_pair_included (x1 x2 : A) (y1 y2 : B) : - Some (x1,y1) ≼ Some (x2,y2) → Some x1 ≼ Some x2 ∧ Some y1 ≼ Some y2. + Lemma Some_pair_includedN_total_1 `{CmraTotal A} n a1 a2 b1 b2 : + Some (a1,b1) ≼{n} Some (a2,b2) → a1 ≼{n} a2 ∧ Some b1 ≼{n} Some b2. + Proof. intros ?%Some_pair_includedN. by rewrite -(Some_includedN_total _ a1). Qed. + Lemma Some_pair_includedN_total_2 `{CmraTotal B} n a1 a2 b1 b2 : + Some (a1,b1) ≼{n} Some (a2,b2) → Some a1 ≼{n} Some a2 ∧ b1 ≼{n} b2. + Proof. intros ?%Some_pair_includedN. by rewrite -(Some_includedN_total _ b1). Qed. + + Lemma Some_pair_included a1 a2 b1 b2 : + Some (a1,b1) ≼ Some (a2,b2) → Some a1 ≼ Some a2 ∧ Some b1 ≼ Some b2. Proof. rewrite !Some_included. intros [[??]|[??]%prod_included]; eauto. Qed. - Lemma Some_pair_included_total_1 `{CmraTotal A} (x1 x2 : A) (y1 y2 : B) : - Some (x1,y1) ≼ Some (x2,y2) → x1 ≼ x2 ∧ Some y1 ≼ Some y2. - Proof. intros ?%Some_pair_included. by rewrite -(Some_included_total x1). Qed. - Lemma Some_pair_included_total_2 `{CmraTotal B} (x1 x2 : A) (y1 y2 : B) : - Some (x1,y1) ≼ Some (x2,y2) → Some x1 ≼ Some x2 ∧ y1 ≼ y2. - Proof. intros ?%Some_pair_included. by rewrite -(Some_included_total y1). Qed. + Lemma Some_pair_included_total_1 `{CmraTotal A} a1 a2 b1 b2 : + Some (a1,b1) ≼ Some (a2,b2) → a1 ≼ a2 ∧ Some b1 ≼ Some b2. + Proof. intros ?%Some_pair_included. by rewrite -(Some_included_total a1). Qed. + Lemma Some_pair_included_total_2 `{CmraTotal B} a1 a2 b1 b2 : + Some (a1,b1) ≼ Some (a2,b2) → Some a1 ≼ Some a2 ∧ b1 ≼ b2. + Proof. intros ?%Some_pair_included. by rewrite -(Some_included_total b1). Qed. End option_prod. Instance option_fmap_cmra_morphism {A B : cmraT} (f: A → B) `{!CmraMorphism f} : CmraMorphism (fmap f : option A → option B). Proof. split; first apply _. - - intros n [x|] ?; rewrite /cmra_validN //=. by apply (cmra_morphism_validN f). - - move=> [x|] //. by apply Some_proper, cmra_morphism_pcore. - - move=> [x|] [y|] //=. by rewrite -(cmra_morphism_op f). + - intros n [a|] ?; rewrite /cmra_validN //=. by apply (cmra_morphism_validN f). + - move=> [a|] //. by apply Some_proper, cmra_morphism_pcore. + - move=> [a|] [b|] //=. by rewrite -(cmra_morphism_op f). Qed. Program Definition optionRF (F : rFunctor) : rFunctor := {| @@ -1464,7 +1473,7 @@ Proof. by intros ? A1 A2 B1 B2 n f g Hfg; apply optionC_map_ne, rFunctor_contractive. Qed. -(* Dependently-typed functions over a finite domain *) +(* Dependently-typed functions over a finite discrete domain *) Section ofe_fun_cmra. Context `{Hfin : Finite A} {B : A → ucmraT}. Implicit Types f g : ofe_fun B. diff --git a/theories/algebra/functions.v b/theories/algebra/functions.v index a4c6a03a727cd2165fb553fb6b0e148c1ad8de33..a0fd519b00d28b13f1a2587cd4b7c4acd91a7cdd 100644 --- a/theories/algebra/functions.v +++ b/theories/algebra/functions.v @@ -25,7 +25,7 @@ Section ofe. by destruct (decide _) as [[]|]. Qed. Global Instance ofe_fun_insert_proper x : - Proper ((≡) ==> (≡) ==> (≡)) (ofe_fun_insert x) := ne_proper_2 _. + Proper ((≡) ==> (≡) ==> (≡)) (ofe_fun_insert (B:=B) x) := ne_proper_2 _. Lemma ofe_fun_lookup_insert f x y : (ofe_fun_insert x y f) x = y. Proof. diff --git a/theories/algebra/gmap.v b/theories/algebra/gmap.v index a09b287e85b6afdfd71b15e2226985ae528e6e50..b9a995537ea553ed15d6c179b48769353d47beb4 100644 --- a/theories/algebra/gmap.v +++ b/theories/algebra/gmap.v @@ -7,6 +7,7 @@ Set Default Proof Using "Type". Section cofe. Context `{Countable K} {A : ofeT}. Implicit Types m : gmap K A. +Implicit Types i : K. Instance gmap_dist : Dist (gmap K A) := λ n m1 m2, ∀ i, m1 !! i ≡{n}≡ m2 !! i. diff --git a/theories/algebra/list.v b/theories/algebra/list.v index ed4736a1875450294db3b1b7474a06c9357e0fe8..67f56c2f782c5a6844f9c9998799824eeb3821f3 100644 --- a/theories/algebra/list.v +++ b/theories/algebra/list.v @@ -6,6 +6,7 @@ Set Default Proof Using "Type". Section cofe. Context {A : ofeT}. +Implicit Types l : list A. Instance list_dist : Dist (list A) := λ n, Forall2 (dist n). diff --git a/theories/algebra/ofe.v b/theories/algebra/ofe.v index 54ca4c7d18a88f295d4e7e80c35522150d2f3166..12ceaeb1d384a9a99976a025713675d318827631 100644 --- a/theories/algebra/ofe.v +++ b/theories/algebra/ofe.v @@ -186,9 +186,7 @@ Section ofe. split; intros; auto. apply (discrete _), dist_le with n; auto with lia. Qed. Lemma discrete_iff_0 n (x : A) `{!Discrete x} y : x ≡{0}≡ y ↔ x ≡{n}≡ y. - Proof. - split=> ?. by apply equiv_dist, (discrete _). eauto using dist_le with lia. - Qed. + Proof. by rewrite -!discrete_iff. Qed. End ofe. (** Contractive functions *) @@ -1176,7 +1174,7 @@ Qed. Notation "T -c> F" := (@ofe_funCF T%type (λ _, F%CF)) : cFunctor_scope. -Instance ofe_funCF_contractive `{Finite C} (F : C → cFunctor) : +Instance ofe_funCF_contractive {C} (F : C → cFunctor) : (∀ c, cFunctorContractive (F c)) → cFunctorContractive (ofe_funCF F). Proof. intros ? A1 A2 B1 B2 n ?? g. diff --git a/theories/algebra/updates.v b/theories/algebra/updates.v index 169b78a66aea71c24160702ae82502477cf9fb16..3721303550b60a3033b1e82ca6cdbe7ef52b203b 100644 --- a/theories/algebra/updates.v +++ b/theories/algebra/updates.v @@ -77,6 +77,12 @@ Lemma cmra_update_op x1 x2 y1 y2 : x1 ~~> y1 → x2 ~~> y2 → x1 ⋅ x2 ~~> y1 Proof. rewrite !cmra_update_updateP; eauto using cmra_updateP_op with congruence. Qed. + +Lemma cmra_update_op_l x y : x ⋅ y ~~> x. +Proof. intros n mz. rewrite comm cmra_opM_assoc. apply cmra_validN_op_r. Qed. +Lemma cmra_update_op_r x y : x ⋅ y ~~> y. +Proof. rewrite comm. apply cmra_update_op_l. Qed. + Lemma cmra_update_valid0 x y : (✓{0} x → x ~~> y) → x ~~> y. Proof. intros H n mz Hmz. apply H, Hmz. diff --git a/theories/base_logic/lib/gen_heap.v b/theories/base_logic/lib/gen_heap.v index c80b066b045d4ae7bce928ff18f2ef98ed8f672a..c37e3b6780f7456a7a85c06c72957bb20c7c513f 100644 --- a/theories/base_logic/lib/gen_heap.v +++ b/theories/base_logic/lib/gen_heap.v @@ -72,6 +72,14 @@ Section to_gen_heap. Proof. by rewrite /to_gen_heap fmap_delete. Qed. End to_gen_heap. +Lemma gen_heap_init `{gen_heapPreG L V Σ} σ : + (|==> ∃ _ : gen_heapG L V Σ, gen_heap_ctx σ)%I. +Proof. + iMod (own_alloc (◠to_gen_heap σ)) as (γ) "Hh". + { apply: auth_auth_valid. exact: to_gen_heap_valid. } + iModIntro. by iExists (GenHeapG L V Σ _ _ _ γ). +Qed. + Section gen_heap. Context `{gen_heapG L V Σ}. Implicit Types P Q : iProp Σ. diff --git a/theories/heap_lang/adequacy.v b/theories/heap_lang/adequacy.v index 135811da52f0c29ecda9cc66eca7b71608fda841..a184a59657dfd639315dd8aa4416f314160e0bd5 100644 --- a/theories/heap_lang/adequacy.v +++ b/theories/heap_lang/adequacy.v @@ -18,10 +18,8 @@ Definition heap_adequacy Σ `{heapPreG Σ} e σ φ : (∀ `{heapG Σ}, WP e {{ v, ⌜φ v⌠}}%I) → adequate e σ φ. Proof. - intros Hwp; eapply (wp_adequacy _ _); iIntros (?). - iMod (own_alloc (◠to_gen_heap σ)) as (γ) "Hh". - { apply: auth_auth_valid. exact: to_gen_heap_valid. } - iModIntro. iExists (λ σ, own γ (◠to_gen_heap σ)); iFrame. - set (Hheap := GenHeapG loc val Σ _ _ _ γ). - by iApply (Hwp (HeapG _ _ _)). + intros Hwp; eapply (wp_adequacy _ _); iIntros (?) "". + iMod (gen_heap_init σ) as (?) "Hh". + iModIntro. iExists gen_heap_ctx. iFrame "Hh". + iApply (Hwp (HeapG _ _ _)). Qed. diff --git a/theories/heap_lang/proofmode.v b/theories/heap_lang/proofmode.v index 2c218e4b7c970b872d70c41920552007f38d1e9a..bc0f293de76332435089b43d57022a2425eb5ee7 100644 --- a/theories/heap_lang/proofmode.v +++ b/theories/heap_lang/proofmode.v @@ -5,6 +5,18 @@ From iris.heap_lang Require Export tactics lifting. Set Default Proof Using "Type". Import uPred. +Lemma tac_wp_expr_eval `{heapG Σ} Δ E Φ e e' : + e = e' → + envs_entails Δ (WP e' @ E {{ Φ }}) → envs_entails Δ (WP e @ E {{ Φ }}). +Proof. by intros ->. Qed. + +Ltac wp_expr_eval t := + try iStartProof; + try (eapply tac_wp_expr_eval; [t; reflexivity|]). + +Ltac wp_expr_simpl := wp_expr_eval simpl. +Ltac wp_expr_simpl_subst := wp_expr_eval simpl_subst. + Lemma tac_wp_pure `{heapG Σ} Δ Δ' E e1 e2 φ Φ : PureExec φ e1 e2 → φ → @@ -34,7 +46,7 @@ Tactic Notation "wp_pure" open_constr(efoc) := [apply _ (* PureExec *) |try fast_done (* The pure condition for PureExec *) |apply _ (* IntoLaters *) - |simpl_subst; try wp_value_head (* new goal *) + |wp_expr_simpl_subst; try wp_value_head (* new goal *) ]) || fail "wp_pure: cannot find" efoc "in" e "or" efoc "is not a reduct" | _ => fail "wp_pure: not a 'wp'" @@ -54,15 +66,16 @@ Tactic Notation "wp_proj" := wp_pure (Fst _) || wp_pure (Snd _). Tactic Notation "wp_case" := wp_pure (Case _ _ _). Tactic Notation "wp_match" := wp_case; wp_let. -Lemma tac_wp_bind `{heapG Σ} K Δ E Φ e : - envs_entails Δ (WP e @ E {{ v, WP fill K (of_val v) @ E {{ Φ }} }})%I → +Lemma tac_wp_bind `{heapG Σ} K Δ E Φ e f : + f = (λ e, fill K e) → (* as an eta expanded hypothesis so that we can `simpl` it *) + envs_entails Δ (WP e @ E {{ v, WP f (of_val v) @ E {{ Φ }} }})%I → envs_entails Δ (WP fill K e @ E {{ Φ }}). -Proof. rewrite /envs_entails=> ->. by apply: wp_bind. Qed. +Proof. rewrite /envs_entails=> -> ->. by apply: wp_bind. Qed. Ltac wp_bind_core K := lazymatch eval hnf in K with | [] => idtac - | _ => apply (tac_wp_bind K); simpl + | _ => eapply (tac_wp_bind K); [simpl; reflexivity|lazy beta] end. Tactic Notation "wp_bind" open_constr(efoc) := @@ -155,7 +168,7 @@ Tactic Notation "wp_apply" open_constr(lem) := lazymatch goal with | |- envs_entails _ (wp ?E ?e ?Q) => reshape_expr e ltac:(fun K e' => - wp_bind_core K; iApplyHyp H; try iNext; simpl) || + wp_bind_core K; iApplyHyp H; try iNext; wp_expr_simpl) || lazymatch iTypeOf H with | Some (_,?P) => fail "wp_apply: cannot apply" P end @@ -174,7 +187,7 @@ Tactic Notation "wp_alloc" ident(l) "as" constr(H) := |first [intros l | fail 1 "wp_alloc:" l "not fresh"]; eexists; split; [env_cbv; reflexivity || fail "wp_alloc:" H "not fresh" - |simpl; try wp_value_head]] + |wp_expr_simpl; try wp_value_head]] | _ => fail "wp_alloc: not a 'wp'" end. @@ -191,7 +204,7 @@ Tactic Notation "wp_load" := [apply _ |let l := match goal with |- _ = Some (_, (?l ↦{_} _)%I) => l end in iAssumptionCore || fail "wp_load: cannot find" l "↦ ?" - |simpl; try wp_value_head] + |wp_expr_simpl; try wp_value_head] | _ => fail "wp_load: not a 'wp'" end. @@ -207,7 +220,7 @@ Tactic Notation "wp_store" := |let l := match goal with |- _ = Some (_, (?l ↦{_} _)%I) => l end in iAssumptionCore || fail "wp_store: cannot find" l "↦ ?" |env_cbv; reflexivity - |simpl; try first [wp_pure (Seq (Lit LitUnit) _)|wp_value_head]] + |wp_expr_simpl; try first [wp_pure (Seq (Lit LitUnit) _)|wp_value_head]] | _ => fail "wp_store: not a 'wp'" end. @@ -223,7 +236,7 @@ Tactic Notation "wp_cas_fail" := |let l := match goal with |- _ = Some (_, (?l ↦{_} _)%I) => l end in iAssumptionCore || fail "wp_cas_fail: cannot find" l "↦ ?" |try congruence - |simpl; try wp_value_head] + |wp_expr_simpl; try wp_value_head] | _ => fail "wp_cas_fail: not a 'wp'" end. @@ -240,6 +253,6 @@ Tactic Notation "wp_cas_suc" := iAssumptionCore || fail "wp_cas_suc: cannot find" l "↦ ?" |try congruence |env_cbv; reflexivity - |simpl; try wp_value_head] + |wp_expr_simpl; try wp_value_head] | _ => fail "wp_cas_suc: not a 'wp'" end. diff --git a/theories/tests/heap_lang.v b/theories/tests/heap_lang.v index 51681a36571459c2906a42b24794d8fbce80cfbf..6c6cb5072e6c79f64f29d69146ded474c0e2c76f 100644 --- a/theories/tests/heap_lang.v +++ b/theories/tests/heap_lang.v @@ -10,6 +10,16 @@ Section LiftingTests. Implicit Types P Q : iProp Σ. Implicit Types Φ : val → iProp Σ. + Definition simpl_test : + ⌜(10 = 4 + 6)%nat⌠-∗ + WP let: "x" := ref #1 in "x" <- !"x";; !"x" {{ v, ⌜v = #1⌠}}. + Proof. + iIntros "?". wp_alloc l. repeat (wp_pure _) || wp_load || wp_store. + match goal with + | |- context [ (10 = 4 + 6)%nat ] => done + end. + Qed. + Definition heap_e : expr := let: "x" := ref #1 in "x" <- !"x" + #1 ;; !"x". diff --git a/theories/tests/tree_sum.v b/theories/tests/tree_sum.v index 28f75f6c8a26e77a3c6ceea613114910dac6c48e..01441c800708b8ba694685b2b7bfc5ddf8646215 100644 --- a/theories/tests/tree_sum.v +++ b/theories/tests/tree_sum.v @@ -40,7 +40,7 @@ Lemma sum_loop_wp `{!heapG Σ} v t l (n : Z) : {{{ RET #(); l ↦ #(sum t + n) ∗ is_tree v t }}}. Proof. iIntros (Φ) "[Hl Ht] HΦ". - iInduction t as [n'|tl ? tr] "IH" forall (v l n Φ); wp_rec; wp_let. + iInduction t as [n'|tl ? tr] "IH" forall (v l n Φ); simpl; wp_rec; wp_let. - iDestruct "Ht" as "%"; subst. wp_match. wp_load. wp_op. wp_store. by iApply ("HΦ" with "[$Hl]").