diff options
author | Rutger Broekhoff | 2025-07-07 21:52:08 +0200 |
---|---|---|
committer | Rutger Broekhoff | 2025-07-07 21:52:08 +0200 |
commit | ba61dfd69504ec6263a9dee9931d93adeb6f3142 (patch) | |
tree | d6c9b78e50eeab24e0c1c09ab45909a6ae3fd5db /theories/nix/interp_proofs.v | |
download | verified-dyn-lang-interp-ba61dfd69504ec6263a9dee9931d93adeb6f3142.tar.gz verified-dyn-lang-interp-ba61dfd69504ec6263a9dee9931d93adeb6f3142.zip |
Initialize repository
Diffstat (limited to 'theories/nix/interp_proofs.v')
-rw-r--r-- | theories/nix/interp_proofs.v | 2690 |
1 files changed, 2690 insertions, 0 deletions
diff --git a/theories/nix/interp_proofs.v b/theories/nix/interp_proofs.v new file mode 100644 index 0000000..5780e48 --- /dev/null +++ b/theories/nix/interp_proofs.v | |||
@@ -0,0 +1,2690 @@ | |||
1 | From Coq Require Import Ascii. | ||
2 | From mininix Require Export nix.interp. | ||
3 | From stdpp Require Import options. | ||
4 | |||
5 | Lemma force_deep_S n : | ||
6 | force_deep (S n) = force_deep1 (force_deep n) (interp_thunk n). | ||
7 | Proof. done. Qed. | ||
8 | Lemma interp_S n : | ||
9 | interp (S n) = interp1 (force_deep n) (interp n) (interp_thunk n) (interp_app n). | ||
10 | Proof. done. Qed. | ||
11 | Lemma interp_thunk_S n : | ||
12 | interp_thunk (S n) = interp_thunk1 (interp n) (interp_thunk n). | ||
13 | Proof. done. Qed. | ||
14 | Lemma interp_app_S n : | ||
15 | interp_app (S n) = interp_app1 (interp n) (interp_thunk n) (interp_app n). | ||
16 | Proof. done. Qed. | ||
17 | |||
18 | Lemma interp_shallow' m E e : interp' m SHALLOW E e = interp m E e. | ||
19 | Proof. rewrite /interp'. by destruct (interp _ _ _) as [[]|]. Qed. | ||
20 | |||
21 | Lemma interp_lit n E bl (Hbl : base_lit_ok bl) : | ||
22 | interp (S n) E (ELit bl) = mret (VLit bl Hbl). | ||
23 | Proof. | ||
24 | rewrite interp_S /=. case_guard; simpl; [|done]. | ||
25 | do 2 f_equal. apply (proof_irrel _). | ||
26 | Qed. | ||
27 | |||
28 | (** Induction *) | ||
29 | Fixpoint val_size (v : val) : nat := | ||
30 | match v with | ||
31 | | VLit _ _ => 1 | ||
32 | | VClo _ E _ | VCloMatch E _ _ _ => S (map_sum_with (thunk_size ∘ snd) E) | ||
33 | | VList ts => S (sum_list_with thunk_size ts) | ||
34 | | VAttr ts => S (map_sum_with thunk_size ts) | ||
35 | end | ||
36 | with thunk_size (t : thunk) : nat := | ||
37 | match t with | ||
38 | | Forced v => S (val_size v) | ||
39 | | Thunk E _ => S (map_sum_with (thunk_size ∘ snd) E) | ||
40 | | Indirect _ E tαs => S (map_sum_with (thunk_size ∘ snd) E + | ||
41 | map_sum_with (from_sum (λ _, 1) thunk_size) tαs) | ||
42 | end. | ||
43 | Notation env_size := (map_sum_with (thunk_size ∘ snd)). | ||
44 | |||
45 | Definition from_thunk {A} (f : val → A) (g : env → expr → A) | ||
46 | (h : string → env → gmap string tattr → A) (t : thunk) : A := | ||
47 | match t with | ||
48 | | Forced v => f v | ||
49 | | Thunk E e => g E e | ||
50 | | Indirect x E tαs => h x E tαs | ||
51 | end. | ||
52 | |||
53 | Lemma env_val_ind (P : env → Prop) (Q : val → Prop) : | ||
54 | (∀ E, | ||
55 | map_Forall (λ _, from_thunk Q (λ E _, P E) (λ _ E _, P E) ∘ snd) E → P E) → | ||
56 | (∀ b Hbl, Q (VLit b Hbl)) → | ||
57 | (∀ x E e, P E → Q (VClo x E e)) → | ||
58 | (∀ E ms strict e, P E → Q (VCloMatch E ms strict e)) → | ||
59 | (∀ ts, Forall (from_thunk Q (λ E _, P E) (λ _ E _, P E)) ts → Q (VList ts)) → | ||
60 | (∀ ts, map_Forall (λ _, from_thunk Q (λ E _, P E) (λ _ E _, P E)) ts → Q (VAttr ts)) → | ||
61 | (∀ E, P E) ∧ (∀ v, Q v). | ||
62 | Proof. | ||
63 | intros Penv Qlit Qclo Qmatch Qlist Qattr. | ||
64 | cut (∀ n, (∀ E, env_size E < n → P E) ∧ (∀ v, val_size v < n → Q v)). | ||
65 | { intros Hhelp; split. | ||
66 | - intros E. apply (Hhelp (S (env_size E))); lia. | ||
67 | - intros v. apply (Hhelp (S (val_size v))); lia. } | ||
68 | intros n. induction n as [|n IH]; [by auto with lia|]. split. | ||
69 | - intros E ?. apply Penv, map_Forall_lookup=> y [k ei] Hy. | ||
70 | apply (map_sum_with_lookup_le (thunk_size ∘ snd)) in Hy; simpl in *. | ||
71 | destruct ei as [v|E' e'|x E' tαs]; simplify_eq/=; try apply IH; eauto with lia. | ||
72 | - intros [] ?; simpl in *. | ||
73 | + apply Qlit. | ||
74 | + apply Qclo, IH. lia. | ||
75 | + apply Qmatch, IH. lia. | ||
76 | + apply Qlist, Forall_forall=> t Hy. | ||
77 | apply (sum_list_with_in _ thunk_size) in Hy. | ||
78 | destruct t; simpl in *; try apply IH; lia. | ||
79 | + apply Qattr, map_Forall_lookup=> y t Hy. | ||
80 | apply (map_sum_with_lookup_le thunk_size) in Hy. | ||
81 | destruct t; simpl in *; try apply IH; lia. | ||
82 | Qed. | ||
83 | |||
84 | Lemma env_ind (P : env → Prop) : | ||
85 | (∀ E, | ||
86 | map_Forall (λ i, from_thunk (λ _, True) (λ E _, P E) (λ _ E _, P E) ∘ snd) E → | ||
87 | P E) → | ||
88 | ∀ E : env, P E. | ||
89 | Proof. intros. apply (env_val_ind P (λ _, True)); auto. Qed. | ||
90 | |||
91 | Lemma val_ind (Q : val → Prop) : | ||
92 | (∀ bl Hbl, Q (VLit bl Hbl)) → | ||
93 | (∀ x E e, Q (VClo x E e)) → | ||
94 | (∀ ms strict E e, Q (VCloMatch ms strict E e)) → | ||
95 | (∀ ts, Forall (from_thunk Q (λ _ _, True) (λ _ _ _, True)) ts → Q (VList ts)) → | ||
96 | (∀ ts, | ||
97 | map_Forall (λ _, from_thunk Q (λ _ _, True) (λ _ _ _, True)) ts → Q (VAttr ts)) → | ||
98 | (∀ v, Q v). | ||
99 | Proof. intros. apply (env_val_ind (λ _, True) Q); auto. Qed. | ||
100 | (** Correspondence to operational semantics *) | ||
101 | Definition subst_env' (thunk_to_expr : thunk → expr) (E : env) : expr → expr := | ||
102 | subst (prod_map id thunk_to_expr <$> E). | ||
103 | |||
104 | Definition tattr_to_attr' | ||
105 | (thunk_to_expr : thunk → expr) (subst_env : env → expr → expr) | ||
106 | (E : env) (α : tattr) : attr := | ||
107 | from_sum (AttrR ∘ subst_env E) (AttrN ∘ thunk_to_expr) α. | ||
108 | |||
109 | Fixpoint thunk_to_expr (t : thunk) : expr := | ||
110 | match t with | ||
111 | | Forced v => val_to_expr v | ||
112 | | Thunk E e => subst_env' thunk_to_expr E e | ||
113 | | Indirect x E tαs => ESelect | ||
114 | (EAttr (tattr_to_attr' thunk_to_expr (subst_env' thunk_to_expr) E <$> tαs)) x | ||
115 | end | ||
116 | with val_to_expr (v : val) : expr := | ||
117 | match v with | ||
118 | | VLit bl _ => ELit bl | ||
119 | | VClo x E e => EAbs x (subst_env' thunk_to_expr E e) | ||
120 | | VCloMatch E ms strict e => EAbsMatch | ||
121 | (fmap (M:=option) (subst_env' thunk_to_expr E) <$> ms) | ||
122 | strict | ||
123 | (subst_env' thunk_to_expr E e) | ||
124 | | VList ts => EList (thunk_to_expr <$> ts) | ||
125 | | VAttr ts => EAttr (AttrN ∘ thunk_to_expr <$> ts) | ||
126 | end. | ||
127 | |||
128 | Notation subst_env := (subst_env' thunk_to_expr). | ||
129 | Notation tattr_to_attr := (tattr_to_attr' thunk_to_expr subst_env). | ||
130 | Notation attr_subst_env E := (attr_map (subst_env E)). | ||
131 | |||
132 | Lemma subst_env_eq e E : | ||
133 | subst_env E e = | ||
134 | match e with | ||
135 | | ELit n => ELit n | ||
136 | | EId x mkd => EId x $ | ||
137 | union_kinded (prod_map id thunk_to_expr <$> E !! x) mkd | ||
138 | | EAbs x e => EAbs x (subst_env E e) | ||
139 | | EAbsMatch ms strict e => | ||
140 | EAbsMatch (fmap (M:=option) (subst_env E) <$> ms) strict (subst_env E e) | ||
141 | | EApp e1 e2 => EApp (subst_env E e1) (subst_env E e2) | ||
142 | | ESeq μ e1 e2 => ESeq μ (subst_env E e1) (subst_env E e2) | ||
143 | | EList es => EList (subst_env E <$> es) | ||
144 | | EAttr αs => EAttr (attr_subst_env E <$> αs) | ||
145 | | ELetAttr k e1 e2 => ELetAttr k (subst_env E e1) (subst_env E e2) | ||
146 | | EBinOp op e1 e2 => EBinOp op (subst_env E e1) (subst_env E e2) | ||
147 | | EIf e1 e2 e3 => EIf (subst_env E e1) (subst_env E e2) (subst_env E e3) | ||
148 | end. | ||
149 | Proof. rewrite /subst_env. destruct e; by rewrite /= ?lookup_fmap. Qed. | ||
150 | |||
151 | Lemma subst_env_alt E e : subst_env E e = subst (prod_map id thunk_to_expr <$> E) e. | ||
152 | Proof. done. Qed. | ||
153 | |||
154 | (* Use the unfolding lemmas, don't rely on conversion *) | ||
155 | Opaque subst_env'. | ||
156 | |||
157 | Lemma subst_env_empty e : subst_env ∅ e = e. | ||
158 | Proof. rewrite subst_env_alt. apply subst_empty. Qed. | ||
159 | |||
160 | Lemma final_val_to_expr v : final SHALLOW (val_to_expr v). | ||
161 | Proof. induction v; simpl; constructor; auto. Qed. | ||
162 | Local Hint Resolve final_val_to_expr | 0 : core. | ||
163 | Lemma step_not_val_to_expr v e : val_to_expr v -{SHALLOW}-> e → False. | ||
164 | Proof. intros []%step_not_final. done. Qed. | ||
165 | |||
166 | Lemma final_force_deep n t v : | ||
167 | force_deep n t = mret v → final DEEP (val_to_expr v). | ||
168 | Proof. | ||
169 | revert t v. induction n as [|n IH]; intros v w; [done|]. | ||
170 | rewrite force_deep_S /=. | ||
171 | intros; destruct v; simplify_res; eauto using final. | ||
172 | + destruct (mapM _ _) as [[vs|]|] eqn:Hmap; simplify_res; eauto. | ||
173 | constructor. revert vs Hmap. | ||
174 | induction ts as [|t ts IHts]; intros; simplify_res; [by constructor|..]. | ||
175 | destruct (interp_thunk _ _) as [[w|]|]; simplify_res. | ||
176 | destruct (force_deep _ _) as [[w'|]|] eqn:?; simplify_res. | ||
177 | destruct (mapM _ _) as [[ws|]|]; simplify_res; eauto. | ||
178 | + destruct (map_mapM_sorted _ _ _) as [[vs|]|] eqn:Hmap; simplify_res. | ||
179 | constructor; [done|]. | ||
180 | revert vs Hmap. induction ts as [|x t ts ?? IHts] | ||
181 | using (map_sorted_ind attr_le); intros ts' Hts. | ||
182 | { rewrite map_mapM_sorted_empty in Hts; simplify_res. done. } | ||
183 | rewrite map_mapM_sorted_insert //= in Hts. | ||
184 | destruct (interp_thunk _ _) as [[w|]|] eqn:?; simplify_res. | ||
185 | destruct (force_deep _ _) as [[w'|]|] eqn:?; simplify_res. | ||
186 | destruct (map_mapM_sorted _ _ _) as [[ws|]|] eqn:Hmap; simplify_res. | ||
187 | rewrite !fmap_insert /=. apply map_Forall_insert_2, IHts; eauto. | ||
188 | Qed. | ||
189 | |||
190 | Lemma interp_bin_op_Some_1 op v1 f : | ||
191 | interp_bin_op op v1 = Some f → | ||
192 | ∃ Φ, sem_bin_op op (val_to_expr v1) Φ. | ||
193 | Proof. | ||
194 | intros Hinterp. unfold interp_bin_op, interp_eq in *. | ||
195 | repeat (case_match || simplify_option_eq); | ||
196 | eexists; by repeat econstructor; eauto using final. | ||
197 | Qed. | ||
198 | |||
199 | Lemma interp_bin_op_Some_2 op v1 Φ : | ||
200 | sem_bin_op op (val_to_expr v1) Φ → | ||
201 | is_Some (interp_bin_op op v1). | ||
202 | Proof. | ||
203 | unfold interp_bin_op; destruct v1; inv 1; | ||
204 | repeat (case_match || simplify_option_eq); eauto. | ||
205 | destruct (option_to_eq_Some _) as [[??]|] eqn:Ho; simplify_eq/=; eauto. | ||
206 | by rewrite H2 in Ho. | ||
207 | Qed. | ||
208 | |||
209 | Lemma interp_eq_list_correct ts1 ts2 : | ||
210 | thunk_to_expr (interp_eq_list ts1 ts2) =D=> | ||
211 | sem_eq_list (thunk_to_expr <$> ts1) (thunk_to_expr <$> ts2). | ||
212 | Proof. | ||
213 | simpl. | ||
214 | remember (kmap (λ n : nat, String "1" (pretty n)) ((ABS,.) <$> map_seq 0 ts1) ∪ | ||
215 | kmap (λ n : nat, String "2" (pretty n)) ((ABS,.) <$> map_seq 0 ts2)) | ||
216 | as E eqn:HE. | ||
217 | assert (∀ (i : nat) t, ts1 !! i = Some t → | ||
218 | E !! String "1" (pretty (i + 0)) = Some (ABS, t)) as Hts1. | ||
219 | { intros x t Hxt. rewrite Nat.add_0_r. | ||
220 | rewrite HE lookup_union (lookup_kmap _) lookup_fmap. | ||
221 | rewrite lookup_map_seq_0 Hxt /= union_Some_l. done. } | ||
222 | assert (∀ (i : nat) t, ts2 !! i = Some t → | ||
223 | E !! String "2" (pretty (i + 0)) = Some (ABS, t)) as Hts2. | ||
224 | { intros x t Hxt. rewrite Nat.add_0_r. | ||
225 | rewrite HE lookup_union_r; last by apply (lookup_kmap_None _). | ||
226 | rewrite (lookup_kmap _) lookup_fmap lookup_map_seq_0 Hxt /=. done. } | ||
227 | clear HE. revert ts2 Hts1 Hts2. generalize 0. | ||
228 | induction ts1 as [|t1 ts1 IH]; intros n [|t2 ts2] Hts1 Hts2; csimpl; [done..|]. | ||
229 | rewrite 4!subst_env_eq /= !(subst_env_eq (ELit _)) /=. rewrite /String.app. | ||
230 | rewrite (Hts1 0 t1) // (Hts2 0 t2) //=. | ||
231 | constructor; [repeat constructor| |done]. | ||
232 | apply IH; intros i t; rewrite Nat.add_succ_r; | ||
233 | [apply (Hts1 (S i))|apply (Hts2 (S i))]. | ||
234 | Qed. | ||
235 | |||
236 | Lemma interp_lt_list_correct ts1 ts2 : | ||
237 | thunk_to_expr (interp_lt_list ts1 ts2) =D=> | ||
238 | sem_lt_list (thunk_to_expr <$> ts1) (thunk_to_expr <$> ts2). | ||
239 | Proof. | ||
240 | simpl. | ||
241 | remember (kmap (λ n : nat, String "1" (pretty n)) ((ABS,.) <$> map_seq 0 ts1) ∪ | ||
242 | kmap (λ n : nat, String "2" (pretty n)) ((ABS,.) <$> map_seq 0 ts2)) | ||
243 | as E eqn:HE. | ||
244 | assert (∀ (i : nat) t, ts1 !! i = Some t → | ||
245 | E !! String "1" (pretty (i + 0)) = Some (ABS, t)) as Hts1. | ||
246 | { intros x t Hxt. rewrite Nat.add_0_r. | ||
247 | rewrite HE lookup_union (lookup_kmap _) lookup_fmap. | ||
248 | rewrite lookup_map_seq_0 Hxt /= union_Some_l. done. } | ||
249 | assert (∀ (i : nat) t, ts2 !! i = Some t → | ||
250 | E !! String "2" (pretty (i + 0)) = Some (ABS, t)) as Hts2. | ||
251 | { intros x t Hxt. rewrite Nat.add_0_r. | ||
252 | rewrite HE lookup_union_r; last by apply (lookup_kmap_None _). | ||
253 | rewrite (lookup_kmap _) lookup_fmap lookup_map_seq_0 Hxt /=. done. } | ||
254 | clear HE. revert ts2 Hts1 Hts2. generalize 0. | ||
255 | induction ts1 as [|t1 ts1 IH]; intros n [|t2 ts2] Hts1 Hts2; csimpl; [done..|]. | ||
256 | rewrite 4!subst_env_eq /= !(subst_env_eq (ELit _)) /=. rewrite /String.app. | ||
257 | rewrite (Hts1 0 t1) // (Hts2 0 t2) //=. | ||
258 | constructor; [repeat constructor..|]. | ||
259 | rewrite 4!subst_env_eq /= !(subst_env_eq (ELit _)) /=. | ||
260 | rewrite (Hts1 0 t1) // (Hts2 0 t2) //=. | ||
261 | constructor; [repeat constructor| |done]. | ||
262 | apply IH; intros i t; rewrite Nat.add_succ_r; | ||
263 | [apply (Hts1 (S i))|apply (Hts2 (S i))]. | ||
264 | Qed. | ||
265 | |||
266 | Lemma interp_eq_attr_correct ts1 ts2 : | ||
267 | dom ts1 = dom ts2 → | ||
268 | thunk_to_expr (interp_eq_attr ts1 ts2) =D=> | ||
269 | sem_eq_attr (AttrN ∘ thunk_to_expr <$> ts1) (AttrN ∘ thunk_to_expr <$> ts2). | ||
270 | Proof. | ||
271 | intros Hdom. simpl. | ||
272 | remember (kmap (String "1") ((ABS,.) <$> ts1) ∪ | ||
273 | kmap (String "2") ((ABS,.) <$> ts2)) as E eqn:HE. | ||
274 | assert (map_Forall (λ x t, E !! String "1" x = Some (ABS, t)) ts1) as Hts1. | ||
275 | { intros x t Hxt. | ||
276 | rewrite HE lookup_union (lookup_kmap (String "1")) lookup_fmap. | ||
277 | by rewrite Hxt /= union_Some_l. } | ||
278 | assert (map_Forall (λ x t, E !! String "2" x = Some (ABS, t)) ts2) as Hts2. | ||
279 | { intros x t Hxt. | ||
280 | rewrite HE lookup_union_r; last by apply (lookup_kmap_None _). | ||
281 | by rewrite (lookup_kmap (String "2")) lookup_fmap Hxt. } | ||
282 | clear HE. revert ts2 Hdom Hts1 Hts2. | ||
283 | induction ts1 as [|x t1 ts1 Hts1x IH] using (map_sorted_ind attr_le); | ||
284 | intros ts2 Hdom Hts1 Hts2. | ||
285 | { apply symmetry, dom_empty_inv_L in Hdom as ->. done. } | ||
286 | rewrite dom_insert_L in Hdom. | ||
287 | assert (is_Some (ts2 !! x)) as [t2 Hxt2] by (apply elem_of_dom; set_solver). | ||
288 | assert (dom ts1 = dom (delete x ts2)). | ||
289 | { rewrite dom_delete_L -Hdom. apply not_elem_of_dom in Hts1x. set_solver. } | ||
290 | rewrite -(insert_delete ts2 x t2) //. rewrite -(insert_delete ts2 x t2) // in Hts2. | ||
291 | apply map_Forall_insert in Hts1 as [Hx1 Hts1]; last done. | ||
292 | apply map_Forall_insert in Hts2 as [Hx2 Hts2]; last by rewrite lookup_delete. | ||
293 | rewrite /sem_eq_attr !fmap_insert /=. erewrite <-insert_merge by done. | ||
294 | rewrite sem_and_attr_insert; first last. | ||
295 | { intros y. rewrite lookup_merge !lookup_fmap /is_Some. | ||
296 | destruct (ts1 !! y) eqn:? , (delete x ts2 !! y); naive_solver. } | ||
297 | { rewrite lookup_merge !lookup_fmap lookup_delete /=. by destruct (ts1 !! x). } | ||
298 | rewrite map_imap_insert sem_and_attr_insert; first last. | ||
299 | { intros y. rewrite map_lookup_imap /is_Some. | ||
300 | destruct (ts1 !! y) eqn:?; naive_solver. } | ||
301 | { by rewrite map_lookup_imap Hts1x. } | ||
302 | rewrite 4!subst_env_eq /= !(subst_env_eq (ELit _)) /= Hx1 Hx2 /=. | ||
303 | constructor; [|apply IHts1; by auto|done]. by do 2 constructor. | ||
304 | Qed. | ||
305 | |||
306 | Lemma interp_bin_op_Some_Some_1 op v1 f Φ v2 t3 : | ||
307 | interp_bin_op op v1 = Some f → | ||
308 | sem_bin_op op (val_to_expr v1) Φ → | ||
309 | f v2 = Some t3 → | ||
310 | ∃ e3, Φ (val_to_expr v2) e3 ∧ thunk_to_expr t3 =D=> e3. | ||
311 | Proof. | ||
312 | unfold interp_bin_op, interp_eq, type_of_val, type_of_expr; | ||
313 | destruct v1, v2; inv 2; intros; | ||
314 | repeat match goal with | ||
315 | | _ => progress simplify_option_eq | ||
316 | | H : _ <$> _ = ∅ |- _ => apply fmap_empty_inv in H | ||
317 | | H : context [dom (_ <$> _)] |- _ => rewrite !dom_fmap_L in H | ||
318 | | H : context [length (_ <$> _)] |- _ => rewrite !length_fmap in H | ||
319 | | _ => case_match | ||
320 | | _ => eexists; split; [done|] | ||
321 | | _ => by apply interp_eq_list_correct | ||
322 | | _ => eexists; split; [|by apply: interp_lt_list_correct] | ||
323 | | _ => by apply: interp_eq_attr_correct | ||
324 | | _ => eexists; split; [|done] | ||
325 | | _ => split; [|done] | ||
326 | | _ => rewrite map_fmap_singleton | ||
327 | | _ => rewrite fmap_delete | ||
328 | | _ => rewrite subst_env_empty | ||
329 | | _ => rewrite fmap_app | ||
330 | | _ => rewrite lookup_fmap | ||
331 | | _ => by constructor | ||
332 | end; eauto using final. | ||
333 | - apply reflexive_eq. f_equal. apply map_eq=> x. | ||
334 | rewrite !lookup_fmap. by destruct (_ !! _) as [[]|]. | ||
335 | - by destruct (ts !! _). | ||
336 | - apply (map_minimal_key_Some _) in H as [[t Hx] ?]. | ||
337 | split; [done|]. right. eexists s, _; split_and!. | ||
338 | + by rewrite lookup_fmap Hx. | ||
339 | + intros y. rewrite lookup_fmap fmap_is_Some. auto. | ||
340 | + rewrite 3!fmap_insert map_fmap_singleton /=. | ||
341 | by rewrite lookup_total_alt Hx fmap_delete. | ||
342 | - apply map_minimal_key_None in H as ->. auto. | ||
343 | - split; [done|]. by rewrite map_fmap_union. | ||
344 | Qed. | ||
345 | |||
346 | Lemma interp_bin_op_Some_Some_2 op v1 f Φ v2 e3 : | ||
347 | interp_bin_op op v1 = Some f → | ||
348 | sem_bin_op op (val_to_expr v1) Φ → | ||
349 | Φ (val_to_expr v2) e3 → | ||
350 | ∃ t3, f v2 = Some t3 ∧ thunk_to_expr t3 =D=> e3. | ||
351 | Proof. | ||
352 | unfold interp_bin_op, interp_eq; destruct v1; inv 2; intros; | ||
353 | repeat match goal with | ||
354 | | H : ∃ _, _ |- _ => destruct H | ||
355 | | H : _ ∧ _ |- _ => destruct H | ||
356 | | H : _ <$> _ = ∅ |- _ => apply fmap_empty_inv in H | ||
357 | | H : context [(_ <$> _) !! _ = _] |- _ => rewrite lookup_fmap in H | ||
358 | | H : context [dom (_ <$> _)] |- _ => rewrite !dom_fmap_L in H | ||
359 | | H : context [length (_ <$> _)] |- _ => rewrite !length_fmap in H | ||
360 | | _ => progress simplify_option_eq | ||
361 | | H : val_to_expr ?v2 = _ |- _ => destruct v2 | ||
362 | | _ => case_match | ||
363 | | _ => eexists; split; [|by apply interp_eq_attr_correct] | ||
364 | | _ => eexists; split; [|by apply interp_eq_list_correct] | ||
365 | | _ => eexists; split; [|by apply interp_lt_list_correct] | ||
366 | | _ => eexists; split; [done|] | ||
367 | | _ => rewrite map_fmap_singleton | ||
368 | | _ => rewrite fmap_delete | ||
369 | | _ => rewrite subst_env_empty | ||
370 | | _ => rewrite fmap_app | ||
371 | | _ => rewrite map_fmap_union | ||
372 | end; eauto. | ||
373 | - rewrite (option_to_eq_Some_Some _ _ H1) /=. by eexists. | ||
374 | - apply reflexive_eq. f_equal. apply map_eq=> x. | ||
375 | rewrite !lookup_fmap. by destruct (_ !! _) as [[]|]. | ||
376 | - rewrite lookup_fmap. by destruct (_ !! _). | ||
377 | - destruct H1 as [[Hemp _]|(x & e' & Hx & Hleast & ->)]. | ||
378 | { by apply fmap_empty_inv in Hemp as ->. } | ||
379 | rewrite lookup_fmap fmap_Some in Hx. destruct Hx as (t & Hx & [= ->]). | ||
380 | setoid_rewrite lookup_fmap in Hleast. setoid_rewrite fmap_is_Some in Hleast. | ||
381 | apply (map_minimal_key_Some _) in H as [??]. | ||
382 | assert (s = x) as -> by (apply (anti_symm attr_le); naive_solver). | ||
383 | rewrite 3!fmap_insert map_fmap_singleton /= fmap_delete. | ||
384 | rewrite lookup_total_alt Hx. done. | ||
385 | - apply map_minimal_key_None in H as ->. naive_solver. | ||
386 | Qed. | ||
387 | |||
388 | Lemma interp_match_subst E ts ms strict : | ||
389 | interp_match ts (fmap (M:=option) (subst_env E) <$> ms) strict = | ||
390 | fmap (M:=gmap string) (sum_map (subst_env E) id) <$> interp_match ts ms strict. | ||
391 | Proof. | ||
392 | unfold interp_match. set (f mt mme := match mt with _ => _ end). | ||
393 | revert ts. induction ms as [|x mt ms Hmsx IH] using map_ind; intros ts. | ||
394 | { rewrite fmap_empty merge_empty_r. | ||
395 | induction ts as [|x t ts Hmsx IH] using map_ind; [done|]. | ||
396 | rewrite omap_insert /=. destruct strict; simplify_eq/=. | ||
397 | { rewrite map_mapM_insert_option //= lookup_omap Hmsx. done. } | ||
398 | rewrite -omap_delete delete_notin //. } | ||
399 | destruct (ts !! x) as [t|] eqn:Htsx. | ||
400 | { rewrite -(insert_delete ts x t) // fmap_insert. | ||
401 | rewrite -!(insert_merge _ _ _ _ (Some (inr t))) //. | ||
402 | rewrite !map_mapM_insert_option /=; | ||
403 | [|by rewrite lookup_merge lookup_delete ?lookup_fmap Hmsx..]. | ||
404 | rewrite IH. destruct (map_mapM id _); rewrite /= ?fmap_insert //. } | ||
405 | rewrite -(insert_merge_r _ _ _ _ (inl <$> mt)) /=; last first. | ||
406 | { rewrite Htsx /=. by destruct mt. } | ||
407 | rewrite fmap_insert. | ||
408 | rewrite -(insert_merge_r _ _ _ _ (inl <$> (subst_env E <$> mt))) /=; last first. | ||
409 | { rewrite Htsx /=. by destruct mt. } | ||
410 | rewrite !map_mapM_insert_option /=; | ||
411 | [|by rewrite lookup_merge ?lookup_fmap Htsx Hmsx..]. | ||
412 | rewrite IH. destruct mt, (map_mapM id _); rewrite /= ?fmap_insert //. | ||
413 | Qed. | ||
414 | |||
415 | Lemma interp_match_Some_1 ts ms strict tαs : | ||
416 | interp_match ts ms strict = Some tαs → | ||
417 | matches (thunk_to_expr <$> ts) ms strict (tattr_to_attr ∅ <$> tαs). | ||
418 | Proof. | ||
419 | unfold interp_match. set (f mt mme := match mt with _ => _ end). | ||
420 | revert ts tαs. | ||
421 | induction ms as [|x mt ms Hmsx IH] using map_ind; intros ts αs Hmatch. | ||
422 | { rewrite merge_empty_r in Hmatch. revert αs Hmatch. | ||
423 | induction ts as [|x t ts Hmsx IH] using map_ind; intros ts' Hmatch. | ||
424 | { rewrite omap_empty map_mapM_empty in Hmatch. injection Hmatch as <-. | ||
425 | rewrite !fmap_empty. constructor. } | ||
426 | rewrite omap_insert /= in Hmatch. destruct strict; simplify_eq/=. | ||
427 | { rewrite map_mapM_insert_option //= in Hmatch. by rewrite lookup_omap Hmsx. } | ||
428 | rewrite fmap_insert. | ||
429 | rewrite -omap_delete delete_notin // in Hmatch. apply IH in Hmatch. | ||
430 | apply matches_strict; rewrite ?lookup_fmap ?Hmsx; eauto. } | ||
431 | destruct (ts !! x) as [t|] eqn:Htsx. | ||
432 | { rewrite -(insert_delete ts x t) //. | ||
433 | rewrite -(insert_delete ts x t) // in Hmatch. | ||
434 | rewrite -(insert_merge _ _ _ _ (Some (inr t))) // in Hmatch. | ||
435 | rewrite map_mapM_insert_option /= in Hmatch; | ||
436 | last (by rewrite lookup_merge lookup_delete Hmsx). | ||
437 | destruct (map_mapM id _) as [E''|] eqn:?; simplify_eq/=. | ||
438 | injection Hmatch as <-. | ||
439 | rewrite !fmap_insert /=. constructor. | ||
440 | - by rewrite lookup_fmap lookup_delete. | ||
441 | - done. | ||
442 | - by apply IH. } | ||
443 | rewrite -(insert_merge_r _ _ _ _ (inl <$> mt)) /= in Hmatch; last first. | ||
444 | { rewrite Htsx /=. by destruct mt. } | ||
445 | rewrite map_mapM_insert_option /= in Hmatch; | ||
446 | last (by rewrite lookup_merge Htsx Hmsx). | ||
447 | destruct mt as [t|]; simplify_eq/=. | ||
448 | destruct (map_mapM id _) as [E''|] eqn:?; simplify_eq/=. | ||
449 | injection Hmatch as <-. rewrite !fmap_insert /= subst_env_empty. constructor. | ||
450 | - by rewrite lookup_fmap Htsx. | ||
451 | - done. | ||
452 | - by apply IH. | ||
453 | Qed. | ||
454 | |||
455 | Lemma interp_match_Some_2 es ms strict αs : | ||
456 | matches es ms strict αs → | ||
457 | interp_match (Thunk ∅ <$> es) ms strict = Some (attr_to_tattr ∅ <$> αs). | ||
458 | Proof. | ||
459 | unfold interp_match. set (f mt mme := match mt with _ => _ end). | ||
460 | induction 1; [done|..]. | ||
461 | - rewrite fmap_empty merge_empty_r. | ||
462 | induction es as [|x e es ? IH] using map_ind; [done|]. | ||
463 | rewrite fmap_insert omap_insert /= -omap_delete -fmap_delete delete_notin //. | ||
464 | - rewrite !fmap_insert /=. | ||
465 | rewrite -(insert_merge _ _ _ _ (Some (inr (Thunk ∅ e)))) //. | ||
466 | rewrite map_mapM_insert_option /=; last first. | ||
467 | { by rewrite lookup_merge !lookup_fmap H H0. } | ||
468 | by rewrite IHmatches. | ||
469 | - rewrite !fmap_insert /=. | ||
470 | rewrite -(insert_merge_r _ _ _ _ (Some (inl d))) /=; last first. | ||
471 | { by rewrite lookup_fmap H. } | ||
472 | rewrite map_mapM_insert_option /=; last first. | ||
473 | { by rewrite lookup_merge !lookup_fmap H H0. } | ||
474 | by rewrite IHmatches /=. | ||
475 | Qed. | ||
476 | |||
477 | Lemma force_deep_le {n1 n2 v mv} : | ||
478 | force_deep n1 v = Res mv → n1 ≤ n2 → force_deep n2 v = Res mv | ||
479 | with interp_le {n1 n2 E e mv} : | ||
480 | interp n1 E e = Res mv → n1 ≤ n2 → interp n2 E e = Res mv | ||
481 | with interp_thunk_le {n1 n2 t mvs} : | ||
482 | interp_thunk n1 t = Res mvs → n1 ≤ n2 → interp_thunk n2 t = Res mvs | ||
483 | with interp_app_le {n1 n2 v t mv} : | ||
484 | interp_app n1 v t = Res mv → n1 ≤ n2 → interp_app n2 v t = Res mv. | ||
485 | Proof. | ||
486 | - destruct n1 as [|n1], n2 as [|n2]; intros Ht ?; [done || lia..|]. | ||
487 | rewrite force_deep_S in Ht; rewrite force_deep_S; simpl in *. | ||
488 | destruct v as []; simplify_res; try done. | ||
489 | + destruct (mapM _ _) as [mvs|] eqn:Hmap; simplify_res. | ||
490 | erewrite mapM_Res_impl; [done..|]. intros t mw Hinterp; simpl in *. | ||
491 | destruct (interp_thunk n1 _) as [mw'|] eqn:Hinterp'; simplify_res. | ||
492 | rewrite (interp_thunk_le _ _ _ _ Hinterp') /=; last lia. | ||
493 | destruct mw'; simplify_res; eauto with lia. | ||
494 | + destruct (map_mapM_sorted _ _ _) eqn:?; simplify_res. | ||
495 | erewrite (map_mapM_sorted_Res_impl attr_le); [done..|]. | ||
496 | clear dependent ts. intros t mw Hinterp; simpl in *. | ||
497 | destruct (interp_thunk n1 _) as [mw'|] eqn:Hinterp'; simplify_res. | ||
498 | rewrite (interp_thunk_le _ _ _ _ Hinterp') /=; last lia. | ||
499 | destruct mw'; simplify_res; eauto with lia. | ||
500 | - destruct n1 as [|n1], n2 as [|n2]; intros He ?; [done || lia..|]. | ||
501 | rewrite interp_S in He; rewrite interp_S; destruct e; | ||
502 | repeat match goal with | ||
503 | | _ => case_match | ||
504 | | H : context [(_ <$> ?mx)] |- _ => destruct mx eqn:?; simplify_res | ||
505 | | H : ?r ≫= _ = _ |- _ => destruct r as [[]|] eqn:?; simplify_res | ||
506 | | H : _ <$> ?r = _ |- _ => destruct r as [[]|] eqn:?; simplify_res | ||
507 | | H : interp ?n' _ _ = Res ?mv |- interp ?n ?E ?e ≫= _ = _ => | ||
508 | rewrite (interp_le n' n E e mv); [|done || lia..] | ||
509 | | H : interp_app ?n' _ _ = Res ?mv |- interp_app ?n ?E ?e ≫= _ = _ => | ||
510 | rewrite (interp_app_le n' n E e mv); [|done || lia..] | ||
511 | | H : force_deep ?n' _ = Res ?mv |- force_deep ?n ?t ≫= _ = _ => | ||
512 | rewrite (force_deep_le n' n t mv); [|done || lia..] | ||
513 | | _ => progress simplify_res | ||
514 | | _ => progress simplify_option_eq | ||
515 | end; eauto with lia. | ||
516 | - destruct n1 as [|n1], n2 as [|n2]; intros He ?; [by (done || lia)..|]. | ||
517 | rewrite interp_thunk_S in He. rewrite interp_thunk_S. | ||
518 | destruct t; repeat (case_match || destruct (_ !! _) | ||
519 | || simplify_res); eauto with lia. | ||
520 | - destruct n1 as [|n1], n2 as [|n2]; intros He ?; [by (done || lia)..|]. | ||
521 | rewrite interp_app_S /= in He; rewrite interp_app_S /=. | ||
522 | destruct v; simplify_res; eauto with lia. | ||
523 | + destruct (interp_thunk n1 t) as [mw|] eqn:?; simplify_res. | ||
524 | erewrite interp_thunk_le by eauto with lia. simpl. | ||
525 | destruct mw as [w|]; simplify_res; [|done]. | ||
526 | destruct (maybe VAttr w) as [ts|]; simplify_res; [|done]. | ||
527 | destruct (interp_match _ _ _); simplify_res; eauto with lia. | ||
528 | + destruct (_ !! "__functor") as [tf|]; simplify_res; [|done]. | ||
529 | destruct (interp_thunk n1 tf) as [mw|] eqn:?; simplify_res. | ||
530 | erewrite interp_thunk_le by eauto with lia. simpl. | ||
531 | destruct mw as [w|]; simplify_res; [|done]. | ||
532 | destruct (interp_app n1 _ _) as [mw|] eqn:?; simplify_res. | ||
533 | erewrite interp_app_le by eauto with lia; simpl. | ||
534 | destruct mw; simplify_res; eauto with lia. | ||
535 | Qed. | ||
536 | |||
537 | Lemma mapM_interp_le {n1 n2 ts mvs} : | ||
538 | mapM (mbind (force_deep n1) ∘ interp_thunk n1) ts = Res mvs → | ||
539 | n1 ≤ n2 → | ||
540 | mapM (mbind (force_deep n2) ∘ interp_thunk n2) ts = Res mvs. | ||
541 | Proof. | ||
542 | intros. eapply mapM_Res_impl; [done|]; simpl; intros t mv ?. | ||
543 | destruct (interp_thunk _ _) as [mw|] eqn:Hthunk; simplify_res. | ||
544 | rewrite (interp_thunk_le Hthunk) //=. | ||
545 | destruct mw; simplify_res; eauto using force_deep_le. | ||
546 | Qed. | ||
547 | Lemma map_mapM_interp_le {n1 n2 ts mvs} : | ||
548 | map_mapM_sorted attr_le (mbind (force_deep n1) ∘ interp_thunk n1) ts = Res mvs → | ||
549 | n1 ≤ n2 → | ||
550 | map_mapM_sorted attr_le (mbind (force_deep n2) ∘ interp_thunk n2) ts = Res mvs. | ||
551 | Proof. | ||
552 | intros. eapply (map_mapM_sorted_Res_impl attr_le); [done|]; simpl. | ||
553 | intros t mv ?. destruct (interp_thunk _ _) as [mw|] eqn:Hthunk; simplify_res. | ||
554 | rewrite (interp_thunk_le Hthunk) //=. | ||
555 | destruct mw; simplify_res; eauto using force_deep_le. | ||
556 | Qed. | ||
557 | |||
558 | Lemma interp_agree {n1 n2 E e mv1 mv2} : | ||
559 | interp n1 E e = Res mv1 → interp n2 E e = Res mv2 → mv1 = mv2. | ||
560 | Proof. | ||
561 | intros He1 He2. apply (inj Res). destruct (total (≤) n1 n2). | ||
562 | - rewrite -He2. symmetry. eauto using interp_le. | ||
563 | - rewrite -He1. eauto using interp_le. | ||
564 | Qed. | ||
565 | |||
566 | Lemma subst_env_union E1 E2 e : | ||
567 | subst_env (union_kinded E1 E2) e = subst_env E1 (subst_env E2 e). | ||
568 | Proof. | ||
569 | rewrite !subst_env_alt -subst_union. f_equal. apply map_eq=> x. | ||
570 | rewrite lookup_union_with !lookup_fmap lookup_union_with. | ||
571 | by repeat destruct (_ !! _) as [[[]]|]. | ||
572 | Qed. | ||
573 | |||
574 | Lemma union_kinded_union {A} (E1 E2 : gmap string (kind * A)) : | ||
575 | map_Forall (λ _ ka, ka.1 = ABS) E1 → union_kinded E1 E2 = E1 ∪ E2. | ||
576 | Proof. | ||
577 | rewrite map_Forall_lookup; intros. | ||
578 | apply map_eq=> x. rewrite lookup_union_with lookup_union. | ||
579 | destruct (E1 !! x) as [[[] a]|] eqn:?; naive_solver. | ||
580 | Qed. | ||
581 | |||
582 | Lemma subst_abs_env_insert E x e t : | ||
583 | subst_env (<[x:=(ABS, t)]> E) e | ||
584 | = subst {[x:=(ABS, thunk_to_expr t)]} (subst_env E e). | ||
585 | Proof. | ||
586 | assert (<[x:=(ABS, t)]> E = | ||
587 | union_kinded {[x:=(ABS, t)]} E) as ->. | ||
588 | { apply map_eq=> y. rewrite lookup_union_with. | ||
589 | destruct (decide (x = y)) as [->|]. | ||
590 | - rewrite lookup_insert lookup_singleton /=. by destruct (_ !! _). | ||
591 | - rewrite lookup_insert_ne // lookup_singleton_ne //. by destruct (_ !! _). } | ||
592 | rewrite subst_env_union subst_env_alt. by rewrite map_fmap_singleton. | ||
593 | Qed. | ||
594 | |||
595 | Lemma subst_abs_as_subst_env x e1 e2 : | ||
596 | subst {[x:=(ABS, e2)]} e1 = subst_env (<[x:=(ABS, Thunk ∅ e2)]> ∅) e1. | ||
597 | Proof. rewrite subst_abs_env_insert //= !subst_env_empty //. Qed. | ||
598 | |||
599 | Lemma subst_env_insert_proper e1 e2 E1 E2 x t1 t2 : | ||
600 | subst_env E1 e1 = subst_env E2 e2 → | ||
601 | thunk_to_expr t1 = thunk_to_expr t2 → | ||
602 | subst_env (<[x:=(ABS, t1)]> E1) e1 = subst_env (<[x:=(ABS, t2)]> E2) e2. | ||
603 | Proof. rewrite !subst_abs_env_insert //. auto with f_equal. Qed. | ||
604 | |||
605 | Lemma subst_env_insert_proper' e1 e2 E1 E2 x E1' E2' e1' e2' : | ||
606 | subst_env E1 e1 = subst_env E2 e2 → | ||
607 | subst_env E1' e1' = subst_env E2' e2' → | ||
608 | subst_env (<[x:=(ABS, Thunk E1' e1')]> E1) e1 | ||
609 | = subst_env (<[x:=(ABS, Thunk E2' e2')]> E2) e2. | ||
610 | Proof. intros. by apply subst_env_insert_proper. Qed. | ||
611 | |||
612 | Lemma subst_env_union_fmap_proper k e1 e2 E1 E2 ts1 ts2 : | ||
613 | subst_env E1 e1 = subst_env E2 e2 → | ||
614 | AttrN ∘ thunk_to_expr <$> ts1 = AttrN ∘ thunk_to_expr <$> ts2 → | ||
615 | subst_env (union_kinded ((k,.) <$> ts1) E1) e1 | ||
616 | = subst_env (union_kinded ((k,.) <$> ts2) E2) e2. | ||
617 | Proof. | ||
618 | intros He Hes. rewrite !subst_env_union; [|by apply env_unionable_with..]. | ||
619 | rewrite He !subst_env_alt /=. f_equal. | ||
620 | apply map_eq=> x. rewrite !lookup_fmap. | ||
621 | apply (f_equal (.!! x)) in Hes. rewrite !lookup_fmap in Hes. | ||
622 | destruct (ts1 !! x), (ts2 !! x); simplify_eq/=; auto with f_equal. | ||
623 | Qed. | ||
624 | |||
625 | Lemma subst_env_fmap_proper k e ts1 ts2 : | ||
626 | AttrN ∘ thunk_to_expr <$> ts1 = AttrN ∘ thunk_to_expr <$> ts2 → | ||
627 | subst_env ((k,.) <$> ts1) e = subst_env ((k,.) <$> ts2) e. | ||
628 | Proof. | ||
629 | intros. rewrite -(right_id_L ∅ (union_kinded) (_ <$> ts1)) | ||
630 | -(right_id_L ∅ (union_kinded) (_ <$> ts2)). | ||
631 | by apply subst_env_union_fmap_proper. | ||
632 | Qed. | ||
633 | |||
634 | Lemma tattr_to_attr_from_attr E (αs : gmap string attr) : | ||
635 | tattr_to_attr E <$> (attr_to_tattr E <$> αs) = attr_subst_env E <$> αs. | ||
636 | Proof. | ||
637 | apply map_eq=> x. rewrite /tattr_to_attr !lookup_fmap. | ||
638 | destruct (αs !! x) as [[[] ]|] eqn:?; auto. | ||
639 | Qed. | ||
640 | |||
641 | Lemma tattr_to_attr_from_attr_empty (αs : gmap string attr) : | ||
642 | tattr_to_attr ∅ <$> (attr_to_tattr ∅ <$> αs) = αs. | ||
643 | Proof. | ||
644 | rewrite tattr_to_attr_from_attr. apply map_eq=> x. rewrite !lookup_fmap. | ||
645 | destruct (αs !! x) as [[[] ]|] eqn:?; f_equal/=; by rewrite subst_env_empty. | ||
646 | Qed. | ||
647 | |||
648 | Lemma indirects_env_proper E1 E2 tαs1 tαs2 e1 e2 : | ||
649 | tattr_to_attr E1 <$> tαs1 = tattr_to_attr E2 <$> tαs2 → | ||
650 | subst_env E1 e1 = subst_env E2 e2 → | ||
651 | subst_env (indirects_env E1 tαs1) e1 = subst_env (indirects_env E2 tαs2) e2. | ||
652 | Proof. | ||
653 | intros Htαs HE. rewrite /indirects_env -!union_kinded_union; | ||
654 | [|intros ??; rewrite map_lookup_imap=> ?; by simplify_option_eq..]. | ||
655 | rewrite !subst_env_union HE !subst_env_alt. f_equal. | ||
656 | apply map_eq=> x. rewrite !lookup_fmap !map_lookup_imap. | ||
657 | pose proof (f_equal (.!! x) Htαs) as Hx. rewrite !lookup_fmap in Hx. | ||
658 | repeat destruct (_ !! x) as [[]|]; simplify_eq/=; auto with f_equal. | ||
659 | Qed. | ||
660 | |||
661 | Lemma subst_env_indirects_env E tαs e : | ||
662 | subst_env (indirects_env E tαs) e | ||
663 | = subst_env (indirects_env ∅ (attr_to_tattr ∅ <$> (tattr_to_attr E <$> tαs))) | ||
664 | (subst_env E e). | ||
665 | Proof. | ||
666 | rewrite /indirects_env -!union_kinded_union; | ||
667 | [|intros ??; rewrite map_lookup_imap=> ?; by simplify_option_eq..]. | ||
668 | rewrite !subst_env_union subst_env_empty !subst_env_alt. | ||
669 | f_equal. apply map_eq=> x. rewrite !lookup_fmap !map_lookup_imap !lookup_fmap. | ||
670 | destruct (_ !! _) as [[]|]; | ||
671 | do 4 f_equal/=; auto using tattr_to_attr_from_attr_empty. | ||
672 | Qed. | ||
673 | |||
674 | Lemma subst_env_indirects_env_attr_to_tattr E αs e : | ||
675 | subst_env (indirects_env E (attr_to_tattr E <$> αs)) e | ||
676 | = subst (indirects (attr_subst_env E <$> αs)) (subst_env E e). | ||
677 | Proof. | ||
678 | rewrite /indirects_env -!union_kinded_union; | ||
679 | [|intros ??; rewrite map_lookup_imap=> ?; by simplify_option_eq..]. | ||
680 | rewrite subst_env_union !subst_env_alt. f_equal. | ||
681 | apply map_eq=> x. rewrite !lookup_fmap !map_lookup_imap !lookup_fmap. | ||
682 | repeat destruct (_ !! x) as [[]|]; simplify_eq/=; do 4 f_equal/=. | ||
683 | by rewrite tattr_to_attr_from_attr. | ||
684 | Qed. | ||
685 | |||
686 | Lemma subst_env_indirects_env_attr_to_tattr_empty αs e : | ||
687 | subst_env (indirects_env ∅ (attr_to_tattr ∅ <$> αs)) e = | ||
688 | subst (indirects αs) e. | ||
689 | Proof. | ||
690 | rewrite subst_env_indirects_env_attr_to_tattr subst_env_empty. do 3 f_equal. | ||
691 | apply map_eq=> x. rewrite !lookup_fmap. | ||
692 | destruct (_ !! x) as [[]|]; do 2 f_equal/=; auto using subst_env_empty. | ||
693 | Qed. | ||
694 | |||
695 | Lemma interp_val_to_expr E e v : | ||
696 | subst_env E e = val_to_expr v → | ||
697 | ∃ w m, interp m E e = mret w ∧ val_to_expr v = val_to_expr w. | ||
698 | Proof. | ||
699 | revert v. induction e; intros []; | ||
700 | rewrite subst_env_eq; intros; simplify_eq/=. | ||
701 | - eexists (VLit _ ltac:(done)), 1. split; [|done]. by rewrite interp_lit. | ||
702 | - eexists (VClo _ _ _), 1. rewrite interp_S /=. auto with f_equal. | ||
703 | - eexists (VCloMatch _ _ _ _), 1. rewrite interp_S /=. auto with f_equal. | ||
704 | - eexists (VList _), 1. rewrite interp_S /=. split; [done|]. | ||
705 | f_equal. rewrite -H0. clear. | ||
706 | induction es; f_equal/=; auto. | ||
707 | - eexists (VAttr _), 1. rewrite interp_S /=. split; [done|]. | ||
708 | assert (no_recs αs) as Hrecs. | ||
709 | { intros y α Hy. | ||
710 | apply (f_equal (.!! y)) in H0. rewrite !lookup_fmap Hy /= in H0. | ||
711 | destruct (ts !! y), α; by simplify_eq/=. } | ||
712 | rewrite from_attr_no_recs // -H0. | ||
713 | f_equal. apply map_eq=> y. | ||
714 | rewrite !lookup_fmap. destruct (αs !! y) as [[]|] eqn:?; do 2 f_equal/=. | ||
715 | eauto using no_recs_lookup. | ||
716 | Qed. | ||
717 | |||
718 | Lemma interp_val_to_expr_Res m E e v mw : | ||
719 | subst_env E e = val_to_expr v → | ||
720 | interp m E e = Res mw → | ||
721 | Some (val_to_expr v) = val_to_expr <$> mw. | ||
722 | Proof. | ||
723 | intros (mw' & m' & Hinterp' & ->)%interp_val_to_expr Hinterp. | ||
724 | by assert (mw = Some mw') as -> by eauto using interp_agree. | ||
725 | Qed. | ||
726 | |||
727 | Lemma interp_empty_val_to_expr v : | ||
728 | ∃ w m, interp m ∅ (val_to_expr v) = mret w ∧ val_to_expr v = val_to_expr w. | ||
729 | Proof. apply interp_val_to_expr. by rewrite subst_env_empty. Qed. | ||
730 | |||
731 | Lemma interp_empty_val_to_expr_Res m v mw : | ||
732 | interp m ∅ (val_to_expr v) = Res mw → | ||
733 | Some (val_to_expr v) = val_to_expr <$> mw. | ||
734 | Proof. apply interp_val_to_expr_Res. by rewrite subst_env_empty. Qed. | ||
735 | |||
736 | Lemma interp_eq_list_proper ts1 ts2 ts1' ts2' : | ||
737 | thunk_to_expr <$> ts1 = thunk_to_expr <$> ts1' → | ||
738 | thunk_to_expr <$> ts2 = thunk_to_expr <$> ts2' → | ||
739 | thunk_to_expr (interp_eq_list ts1 ts2) | ||
740 | = thunk_to_expr (interp_eq_list ts1' ts2'). | ||
741 | Proof. | ||
742 | intros Hts1 Hts2. rewrite /= !subst_env_alt. | ||
743 | f_equal; last first. | ||
744 | { revert ts1' ts2 ts2' Hts1 Hts2. generalize 0. | ||
745 | induction ts1; intros ? [] [] [] ??; simplify_eq/=; auto with f_equal. } | ||
746 | rewrite !map_fmap_union. f_equal; apply map_eq=> y; rewrite !lookup_fmap. | ||
747 | - destruct (kmap _ _ !! y) as [[k e]|] eqn:Hy; simplify_eq/=. | ||
748 | + apply (lookup_kmap_Some _) in Hy as (y' & -> & Hy). | ||
749 | rewrite (lookup_kmap _) lookup_fmap lookup_map_seq_0. | ||
750 | rewrite lookup_fmap lookup_map_seq_0 in Hy. | ||
751 | apply (f_equal (.!! y')) in Hts1. rewrite !list_lookup_fmap in Hts1. | ||
752 | repeat destruct (_ !! _); simplify_eq/=; auto with f_equal. | ||
753 | + rewrite lookup_kmap_None in Hy. | ||
754 | apply symmetry, fmap_None, (lookup_kmap_None _). | ||
755 | intros y' ->. generalize (Hy _ eq_refl). | ||
756 | rewrite !lookup_fmap !lookup_map_seq_0. | ||
757 | apply (f_equal (.!! y')) in Hts1. rewrite !list_lookup_fmap in Hts1. | ||
758 | intros. repeat destruct (_ !! _); by simplify_eq/=. | ||
759 | - destruct (kmap _ _ !! y) as [[k e]|] eqn:Hy; simplify_eq/=. | ||
760 | + apply (lookup_kmap_Some _) in Hy as (y' & -> & Hy). | ||
761 | rewrite (lookup_kmap _) lookup_fmap lookup_map_seq_0. | ||
762 | rewrite lookup_fmap lookup_map_seq_0 in Hy. | ||
763 | apply (f_equal (.!! y')) in Hts2. rewrite !list_lookup_fmap in Hts2. | ||
764 | repeat destruct (_ !! _); simplify_eq/=; auto with f_equal. | ||
765 | + rewrite lookup_kmap_None in Hy. | ||
766 | apply symmetry, fmap_None, (lookup_kmap_None _). | ||
767 | intros y' ->. generalize (Hy _ eq_refl). | ||
768 | rewrite !lookup_fmap !lookup_map_seq_0. | ||
769 | apply (f_equal (.!! y')) in Hts2. rewrite !list_lookup_fmap in Hts2. | ||
770 | intros. repeat destruct (_ !! _); by simplify_eq/=. | ||
771 | Qed. | ||
772 | |||
773 | Lemma interp_lt_list_proper ts1 ts2 ts1' ts2' : | ||
774 | thunk_to_expr <$> ts1 = thunk_to_expr <$> ts1' → | ||
775 | thunk_to_expr <$> ts2 = thunk_to_expr <$> ts2' → | ||
776 | thunk_to_expr (interp_lt_list ts1 ts2) | ||
777 | = thunk_to_expr (interp_lt_list ts1' ts2'). | ||
778 | Proof. | ||
779 | intros Hts1 Hts2. rewrite /= !subst_env_alt. | ||
780 | f_equal; last first. | ||
781 | { revert ts1' ts2 ts2' Hts1 Hts2. generalize 0. | ||
782 | induction ts1; intros ? [] [] [] ??; simplify_eq/=; auto with f_equal. } | ||
783 | rewrite !map_fmap_union. f_equal; apply map_eq=> y; rewrite !lookup_fmap. | ||
784 | - destruct (kmap _ _ !! y) as [[k e]|] eqn:Hy; simplify_eq/=. | ||
785 | + apply (lookup_kmap_Some _) in Hy as (y' & -> & Hy). | ||
786 | rewrite (lookup_kmap _) lookup_fmap lookup_map_seq_0. | ||
787 | rewrite lookup_fmap lookup_map_seq_0 in Hy. | ||
788 | apply (f_equal (.!! y')) in Hts1. rewrite !list_lookup_fmap in Hts1. | ||
789 | repeat destruct (_ !! _); simplify_eq/=; auto with f_equal. | ||
790 | + rewrite lookup_kmap_None in Hy. | ||
791 | apply symmetry, fmap_None, (lookup_kmap_None _). | ||
792 | intros y' ->. generalize (Hy _ eq_refl). | ||
793 | rewrite !lookup_fmap !lookup_map_seq_0. | ||
794 | apply (f_equal (.!! y')) in Hts1. rewrite !list_lookup_fmap in Hts1. | ||
795 | intros. repeat destruct (_ !! _); by simplify_eq/=. | ||
796 | - destruct (kmap _ _ !! y) as [[k e]|] eqn:Hy; simplify_eq/=. | ||
797 | + apply (lookup_kmap_Some _) in Hy as (y' & -> & Hy). | ||
798 | rewrite (lookup_kmap _) lookup_fmap lookup_map_seq_0. | ||
799 | rewrite lookup_fmap lookup_map_seq_0 in Hy. | ||
800 | apply (f_equal (.!! y')) in Hts2. rewrite !list_lookup_fmap in Hts2. | ||
801 | repeat destruct (_ !! _); simplify_eq/=; auto with f_equal. | ||
802 | + rewrite lookup_kmap_None in Hy. | ||
803 | apply symmetry, fmap_None, (lookup_kmap_None _). | ||
804 | intros y' ->. generalize (Hy _ eq_refl). | ||
805 | rewrite !lookup_fmap !lookup_map_seq_0. | ||
806 | apply (f_equal (.!! y')) in Hts2. rewrite !list_lookup_fmap in Hts2. | ||
807 | intros. repeat destruct (_ !! _); by simplify_eq/=. | ||
808 | Qed. | ||
809 | |||
810 | Lemma interp_eq_attr_proper ts1 ts2 ts1' ts2' : | ||
811 | thunk_to_expr <$> ts1 = thunk_to_expr <$> ts1' → | ||
812 | thunk_to_expr <$> ts2 = thunk_to_expr <$> ts2' → | ||
813 | thunk_to_expr (interp_eq_attr ts1 ts2) | ||
814 | = thunk_to_expr (interp_eq_attr ts1' ts2'). | ||
815 | Proof. | ||
816 | intros Hts1 Hts2. rewrite /= !subst_env_alt. | ||
817 | f_equal; last first. | ||
818 | { clear Hts2. f_equal. apply map_eq=> y. | ||
819 | rewrite !map_lookup_imap. apply (f_equal (.!! y)) in Hts1. | ||
820 | rewrite !lookup_fmap in Hts1. by repeat destruct (_ !! _). } | ||
821 | rewrite !map_fmap_union. f_equal; apply map_eq=> y; rewrite !lookup_fmap. | ||
822 | - destruct (kmap _ _ !! y) as [[k e]|] eqn:Hy; simplify_eq/=. | ||
823 | + apply (lookup_kmap_Some _) in Hy as (y' & -> & Hy). | ||
824 | rewrite (lookup_kmap (String "1")) lookup_fmap. | ||
825 | rewrite lookup_fmap in Hy. | ||
826 | apply (f_equal (.!! y')) in Hts1. rewrite !lookup_fmap in Hts1. | ||
827 | repeat destruct (_ !! _); simplify_eq/=; auto with f_equal. | ||
828 | + rewrite lookup_kmap_None in Hy. | ||
829 | apply symmetry, fmap_None, (lookup_kmap_None _). | ||
830 | intros y' ->. generalize (Hy _ eq_refl). rewrite !lookup_fmap. | ||
831 | apply (f_equal (.!! y')) in Hts1. rewrite !lookup_fmap in Hts1. | ||
832 | intros. repeat destruct (_ !! _); by simplify_eq/=. | ||
833 | - destruct (kmap _ _ !! y) as [[k e]|] eqn:Hy; simplify_eq/=. | ||
834 | + apply (lookup_kmap_Some _) in Hy as (y' & -> & Hy). | ||
835 | rewrite (lookup_kmap (String "2")) lookup_fmap. | ||
836 | rewrite lookup_fmap in Hy. | ||
837 | apply (f_equal (.!! y')) in Hts2. rewrite !lookup_fmap in Hts2. | ||
838 | repeat destruct (_ !! _); simplify_eq/=; auto with f_equal. | ||
839 | + rewrite lookup_kmap_None in Hy. | ||
840 | apply symmetry, fmap_None, (lookup_kmap_None _). | ||
841 | intros y' ->. generalize (Hy _ eq_refl). rewrite !lookup_fmap. | ||
842 | apply (f_equal (.!! y')) in Hts2. rewrite !lookup_fmap in Hts2. | ||
843 | intros. repeat destruct (_ !! _); by simplify_eq/=. | ||
844 | Qed. | ||
845 | |||
846 | Opaque interp_eq_list interp_lt_list interp_eq_attr. | ||
847 | |||
848 | Lemma interp_bin_op_proper op v1 v2 : | ||
849 | val_to_expr v1 = val_to_expr v2 → | ||
850 | match interp_bin_op op v1, interp_bin_op op v2 with | ||
851 | | None, None => True | ||
852 | | Some f1, Some f2 => ∀ v1' v2', | ||
853 | val_to_expr v1' = val_to_expr v2' → | ||
854 | thunk_to_expr <$> f1 v1' = thunk_to_expr <$> f2 v2' | ||
855 | | _, _ => False | ||
856 | end. | ||
857 | Proof. | ||
858 | intros. unfold interp_bin_op, interp_eq; | ||
859 | repeat (done || case_match || simplify_eq/= || | ||
860 | destruct (option_to_eq_Some _) as [[]|]); | ||
861 | intros [] [] ?; simplify_eq/=; | ||
862 | repeat match goal with | ||
863 | | _ => done | ||
864 | | _ => progress simplify_option_eq | ||
865 | | _ => rewrite map_fmap_singleton | ||
866 | | _ => rewrite map_fmap_union | ||
867 | | _ => case_match | ||
868 | | |- context[ maybe _ ?x ] => is_var x; destruct x | ||
869 | end; auto with congruence. | ||
870 | - f_equal. by apply interp_eq_list_proper. | ||
871 | - apply (f_equal length) in H, H0. rewrite !length_fmap in H H0. congruence. | ||
872 | - apply (f_equal length) in H, H0. rewrite !length_fmap in H H0. congruence. | ||
873 | - f_equal. apply interp_eq_attr_proper. | ||
874 | + rewrite 2!map_fmap_compose in H. by simplify_eq. | ||
875 | + rewrite 2!map_fmap_compose in H0. by simplify_eq. | ||
876 | - apply (f_equal dom) in H, H0. rewrite !dom_fmap_L in H H0. congruence. | ||
877 | - apply (f_equal dom) in H, H0. rewrite !dom_fmap_L in H H0. congruence. | ||
878 | - destruct v1, v2; by simplify_eq/=. | ||
879 | - repeat destruct (option_to_eq_Some _) as [[]|]; simplify_eq/=; auto. | ||
880 | - do 3 f_equal. apply map_eq=> y. rewrite !lookup_fmap. | ||
881 | apply (f_equal (.!! y)) in H. rewrite !lookup_fmap in H. | ||
882 | repeat destruct (_ !! _) as [[]|]; naive_solver. | ||
883 | - f_equal. by apply interp_lt_list_proper. | ||
884 | - rewrite !fmap_insert /=. auto 10 with f_equal. | ||
885 | - by rewrite !fmap_app H0 H. | ||
886 | - apply (f_equal (.!! s)) in H. rewrite !lookup_fmap in H. | ||
887 | repeat destruct (_ !! _); simplify_eq/=; by f_equal. | ||
888 | - apply (f_equal (.!! s)) in H. rewrite !lookup_fmap in H. | ||
889 | repeat destruct (_ !! _); simplify_eq/=; by f_equal. | ||
890 | - rewrite !fmap_delete. congruence. | ||
891 | - assert (∀ y, is_Some (ts !! y) ↔ is_Some (ts0 !! y)) as Hx. | ||
892 | { intros y. rewrite -!(fmap_is_Some (AttrN ∘ thunk_to_expr)) -!lookup_fmap. | ||
893 | by rewrite H. } | ||
894 | apply (map_minimal_key_Some _) in H5 as [[t1 Hx1] ?], H8 as [[t2 Hx2] ?]. | ||
895 | assert (s0 = s) as -> by (apply (anti_symm attr_le); naive_solver). | ||
896 | pose proof (f_equal (.!! s) H) as Hs. rewrite !lookup_fmap in Hs. | ||
897 | rewrite !fmap_insert !fmap_empty /= !lookup_total_alt Hx1 Hx2 /=. | ||
898 | rewrite Hx1 Hx2 /= in Hs. simplify_eq/=. rewrite Hs !fmap_delete H. done. | ||
899 | - apply map_minimal_key_None in H8 as ->. | ||
900 | rewrite fmap_empty in H. by apply fmap_empty_inv in H as ->. | ||
901 | - apply map_minimal_key_None in H5 as ->. | ||
902 | rewrite fmap_empty in H. by apply symmetry, fmap_empty_inv in H as ->. | ||
903 | Qed. | ||
904 | |||
905 | Lemma interp_match_proper E1 E2 ts1 ts2 ms1 ms2 strict : | ||
906 | thunk_to_expr <$> ts1 = thunk_to_expr <$> ts2 → | ||
907 | fmap (M:=option) (subst_env E1) <$> ms1 = fmap (subst_env E2) <$> ms2 → | ||
908 | fmap (M:=gmap string) (tattr_to_attr E1) <$> interp_match ts1 ms1 strict | ||
909 | = fmap (tattr_to_attr E2) <$> interp_match ts2 ms2 strict. | ||
910 | Proof. | ||
911 | revert ms2 ts1 ts2. | ||
912 | induction ms1 as [|x m1 ms1 Hmsx IH] using map_ind; intros ms2 ts1 ts2 Hts Hms. | ||
913 | { rewrite fmap_empty in Hms. apply symmetry, fmap_empty_inv in Hms as ->. | ||
914 | rewrite /interp_match !merge_empty_r. revert ts2 Hts. | ||
915 | induction ts1 as [|x t1 ts1 Htsx IH] using map_ind; intros ts2 Hts. | ||
916 | { rewrite fmap_empty in Hts. by apply symmetry, fmap_empty_inv in Hts as ->. } | ||
917 | rewrite fmap_insert in Hts. | ||
918 | apply symmetry, fmap_insert_inv in Hts as (t2&ts2'&?&Htsx2&->&Hts); | ||
919 | last by rewrite lookup_fmap Htsx. | ||
920 | rewrite !omap_insert /=. destruct strict; simpl; | ||
921 | rewrite ?map_mapM_insert_option ?delete_notin //= ?lookup_omap ?Htsx ?Htsx2; | ||
922 | auto. } | ||
923 | rewrite fmap_insert in Hms. | ||
924 | apply symmetry, fmap_insert_inv in Hms as (m2&ms2'&?&Hmsx2&->&Hms); | ||
925 | last by rewrite lookup_fmap Hmsx. | ||
926 | pose proof (f_equal (.!! x) Hts) as Hx. rewrite !lookup_fmap in Hx. | ||
927 | destruct (ts1 !! x) as [t1|] eqn:Hts1x, (ts2 !! x) as [t2|] eqn:Hts2x; simplify_eq/=. | ||
928 | - rewrite -(insert_delete ts1 x t1) // -(insert_delete ts2 x t2) //. | ||
929 | rewrite /interp_match. erewrite <-!insert_merge by done. | ||
930 | rewrite !map_mapM_insert_option ?lookup_merge ?lookup_delete ?Hmsx ?Hmsx2 //=. | ||
931 | apply (f_equal (delete x)) in Hts. rewrite -!fmap_delete in Hts. | ||
932 | eapply IH in Hms; [|done]. rewrite /interp_match in Hms. | ||
933 | repeat destruct (map_mapM id _); simplify_eq/=; [|done..]. | ||
934 | rewrite !fmap_insert /=. auto with f_equal. | ||
935 | - rewrite /interp_match. | ||
936 | rewrite -!(insert_merge_r _ ts1 _ _ (inl <$> m1)); | ||
937 | last (rewrite Hts1x; by destruct m1). | ||
938 | rewrite -!(insert_merge_r _ ts2 _ _ (inl <$> m2)); | ||
939 | last (rewrite Hts2x; by destruct m2). | ||
940 | rewrite !map_mapM_insert_option ?lookup_merge ?Hts1x ?Hts2x ?Hmsx ?Hmsx2 //. | ||
941 | eapply IH in Hms; [|done]. rewrite /interp_match in Hms. | ||
942 | destruct m1, m2; simplify_eq/=; auto. | ||
943 | repeat destruct (map_mapM id _); simplify_eq/=; [|done..]. | ||
944 | rewrite !fmap_insert /=. auto with f_equal. | ||
945 | Qed. | ||
946 | |||
947 | Lemma mapM_interp_proper' n ts1 ts2 mvs : | ||
948 | (∀ v1 v2 mv, | ||
949 | val_to_expr v1 = val_to_expr v2 → | ||
950 | force_deep n v1 = Res mv → | ||
951 | ∃ mw m, force_deep m v2 = Res mw ∧ val_to_expr <$> mv = val_to_expr <$> mw) → | ||
952 | (∀ t1 t2 mv, | ||
953 | thunk_to_expr t1 = thunk_to_expr t2 → | ||
954 | interp_thunk n t1 = Res mv → | ||
955 | ∃ mw m, interp_thunk m t2 = Res mw ∧ val_to_expr <$> mv = val_to_expr <$> mw) → | ||
956 | thunk_to_expr <$> ts1 = thunk_to_expr <$> ts2 → | ||
957 | mapM (mbind (force_deep n) ∘ interp_thunk n) ts1 = Res mvs → | ||
958 | ∃ mws m, mapM (mbind (force_deep m) ∘ interp_thunk m) ts2 = Res mws ∧ | ||
959 | fmap (M:=list) val_to_expr <$> mvs = fmap (M:=list) val_to_expr <$> mws. | ||
960 | Proof. | ||
961 | intros force_deep_proper interp_thunk_proper Hts. | ||
962 | revert mvs. rewrite list_eq_Forall2 Forall2_fmap in Hts. | ||
963 | induction Hts as [|t1 t2 ts1 ts2 ?? IH]; intros mvs ?; simplify_res. | ||
964 | { by exists (Some []), 0. } | ||
965 | destruct (interp_thunk _ _) as [mv|] eqn:Hinterp'; simplify_res. | ||
966 | eapply interp_thunk_proper in Hinterp' | ||
967 | as (mw & m1 & Hinterp1 & Hw); [|by eauto..]. | ||
968 | destruct mv as [v|], mw as [w|]; simplify_res; last first. | ||
969 | { exists None, m1. by rewrite /= Hinterp1. } | ||
970 | destruct (force_deep _ _) as [mv'|] eqn:Hforce; simplify_res. | ||
971 | eapply force_deep_proper in Hforce as (mw' & m2 & Hforce2 & Hw'); last done. | ||
972 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
973 | { exists None, (m1 `max` m2). | ||
974 | rewrite (interp_thunk_le Hinterp1) /=; last lia. | ||
975 | rewrite (force_deep_le Hforce2) /=; last lia. done. } | ||
976 | destruct (mapM _ _) as [mvs'|] eqn:?; simplify_res. | ||
977 | destruct (IH _ eq_refl) as (mws & m3 & Hmap3 & ?). | ||
978 | exists ((w' ::.) <$> mws), (S (m1 `max` m2 `max` m3)). | ||
979 | rewrite (interp_thunk_le Hinterp1) /=; last lia. | ||
980 | rewrite (force_deep_le Hforce2) /=; last lia. | ||
981 | rewrite (mapM_interp_le Hmap3) /=; last lia. split; [by destruct mws|]. | ||
982 | destruct mvs', mws; simplify_res; auto 10 with f_equal. | ||
983 | Qed. | ||
984 | |||
985 | Lemma force_deep_proper n v1 v2 mv : | ||
986 | val_to_expr v1 = val_to_expr v2 → | ||
987 | force_deep n v1 = Res mv → | ||
988 | ∃ mw m, force_deep m v2 = Res mw ∧ val_to_expr <$> mv = val_to_expr <$> mw | ||
989 | with interp_proper n E1 E2 e1 e2 mv : | ||
990 | subst_env E1 e1 = subst_env E2 e2 → | ||
991 | interp n E1 e1 = Res mv → | ||
992 | ∃ mw m, interp m E2 e2 = Res mw ∧ val_to_expr <$> mv = val_to_expr <$> mw | ||
993 | with interp_thunk_proper n t1 t2 mv : | ||
994 | thunk_to_expr t1 = thunk_to_expr t2 → | ||
995 | interp_thunk n t1 = Res mv → | ||
996 | ∃ mw m, interp_thunk m t2 = Res mw ∧ val_to_expr <$> mv = val_to_expr <$> mw | ||
997 | with interp_app_proper n v1 v2 t1' t2' mv : | ||
998 | val_to_expr v1 = val_to_expr v2 → | ||
999 | thunk_to_expr t1' = thunk_to_expr t2' → | ||
1000 | interp_app n v1 t1' = Res mv → | ||
1001 | ∃ mw m, interp_app m v2 t2' = Res mw ∧ val_to_expr <$> mv = val_to_expr <$> mw. | ||
1002 | Proof. | ||
1003 | (* force_deep_proper *) | ||
1004 | - destruct n as [|n]; [done|]. | ||
1005 | intros Hv Hinterp. rewrite force_deep_S /force_deep1 in Hinterp. | ||
1006 | destruct v1 as [| | |ts1|ts1], v2 as [| | |ts2|ts2]; simplify_res. | ||
1007 | { eexists _, 1; split; [by rewrite force_deep_S|]. done. } | ||
1008 | { eexists _, 1; split; [by rewrite force_deep_S|]. simpl. auto with f_equal. } | ||
1009 | { eexists _, 1; split; [by rewrite force_deep_S|]. simpl. auto with f_equal. } | ||
1010 | { destruct (mapM _ _) as [mvs|] eqn:Hmap; simplify_res. | ||
1011 | eapply mapM_interp_proper' in Hmap as (mws & m & Hmap & Hmvs); [|by eauto..]. | ||
1012 | exists (VList ∘ fmap Forced <$> mws), (S m). | ||
1013 | rewrite force_deep_S /= Hmap. split; [done|]. | ||
1014 | destruct mvs, mws; simplify_eq/=; do 2 f_equal. | ||
1015 | rewrite list_eq_Forall2 Forall2_fmap in Hmvs. | ||
1016 | by rewrite list_eq_Forall2 !Forall2_fmap. } | ||
1017 | destruct (map_mapM_sorted _ _ _) as [mvs|] eqn:Hmap; simplify_res. | ||
1018 | assert (∃ mws m, | ||
1019 | map_mapM_sorted attr_le | ||
1020 | (mbind (force_deep m) ∘ interp_thunk m) ts2 = Res mws ∧ | ||
1021 | fmap (M:=gmap _) val_to_expr <$> mvs = fmap (M:=gmap _) val_to_expr <$> mws) | ||
1022 | as (mws & m & Hmap' & Hmvs); last first. | ||
1023 | { exists (VAttr ∘ fmap Forced <$> mws), (S m). | ||
1024 | rewrite force_deep_S /= Hmap'. split; [done|]. | ||
1025 | destruct mvs, mws; simplify_eq/=; do 2 f_equal. | ||
1026 | apply map_eq=> x. rewrite !lookup_fmap. | ||
1027 | apply (f_equal (.!! x)) in Hmvs. rewrite !lookup_fmap in Hmvs. | ||
1028 | repeat destruct (_ !! x); simplify_res; auto with f_equal. } | ||
1029 | revert ts2 mvs Hmap Hv. induction ts1 as [|x t1 ts1 Hx1 ? IH] | ||
1030 | using (map_sorted_ind attr_le); intros ts2' mvs Hmap Hts. | ||
1031 | { exists (Some ∅), 0. rewrite fmap_empty in Hts. | ||
1032 | apply symmetry, fmap_empty_inv in Hts as ->. | ||
1033 | rewrite map_mapM_sorted_empty in Hmap; simplify_res. | ||
1034 | by rewrite map_mapM_sorted_empty. } | ||
1035 | rewrite map_mapM_sorted_insert //= in Hmap. rewrite fmap_insert in Hts. | ||
1036 | apply symmetry, fmap_insert_inv in Hts as (t2 & ts2 & Ht & ? & -> & Hts); | ||
1037 | simplify_eq/=; last by rewrite lookup_fmap Hx1. | ||
1038 | assert (∀ j, is_Some (ts2 !! j) → attr_le x j). | ||
1039 | { intros j. rewrite -(fmap_is_Some (AttrN ∘ thunk_to_expr)). | ||
1040 | rewrite -lookup_fmap -Hts lookup_fmap fmap_is_Some. auto. } | ||
1041 | destruct (interp_thunk _ _) as [mv|] eqn:Hinterp'; simplify_res. | ||
1042 | eapply interp_thunk_proper in Hinterp' | ||
1043 | as (mw & m1 & Hinterp1 & Hw); [|by eauto..]. | ||
1044 | destruct mv as [v|], mw as [w|]; simplify_res; last first. | ||
1045 | { exists None, m1. by rewrite map_mapM_sorted_insert //= Hinterp1. } | ||
1046 | destruct (force_deep _ _) as [mv'|] eqn:Hforce; simplify_res. | ||
1047 | eapply force_deep_proper in Hforce as (mw' & m2 & Hforce2 & Hw'); last done. | ||
1048 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
1049 | { exists None, (m1 `max` m2). rewrite map_mapM_sorted_insert //=. | ||
1050 | rewrite (interp_thunk_le Hinterp1) /=; last lia. | ||
1051 | rewrite (force_deep_le Hforce2) /=; last lia. done. } | ||
1052 | destruct (map_mapM_sorted _ _ _) as [mvs'|] eqn:?; simplify_res. | ||
1053 | eapply IH in Hts as (mws & m3 & Hmap3 & ?); last done. | ||
1054 | exists (<[x:=w']> <$> mws), (S (m1 `max` m2 `max` m3)). | ||
1055 | rewrite map_mapM_sorted_insert //=. | ||
1056 | rewrite (interp_thunk_le Hinterp1) /=; last lia. | ||
1057 | rewrite (force_deep_le Hforce2) /=; last lia. | ||
1058 | rewrite (map_mapM_interp_le Hmap3) /=; last lia. | ||
1059 | destruct mvs' as [vs'|], mws as [ws'|]; simplify_res; last done. | ||
1060 | split; [done|]. rewrite !fmap_insert. auto 10 with f_equal. | ||
1061 | (* interp_proper *) | ||
1062 | - destruct n as [|n]; [done|]. intros Hsubst Hinterp. | ||
1063 | rewrite 2!subst_env_eq in Hsubst. | ||
1064 | rewrite interp_S in Hinterp. destruct e1, e2; simplify_res; try done. | ||
1065 | + (* ELit *) | ||
1066 | case_guard; simplify_res. | ||
1067 | * eexists (Some (VLit _ ltac:(done))), 1. by rewrite interp_lit. | ||
1068 | * exists None, 1. split; [|done]. rewrite interp_S /=. by case_guard. | ||
1069 | + (* EId *) | ||
1070 | assert (∀ (mke : option (kind * expr)) (E : env) x, | ||
1071 | prod_map id thunk_to_expr <$> | ||
1072 | union_kinded (E !! x) (prod_map id (Thunk ∅) <$> mke) | ||
1073 | = union_kinded (prod_map id thunk_to_expr <$> E !! x) mke) as HE. | ||
1074 | { intros mke' E x. destruct (E !! _) as [[[] ?]|], mke' as [[[] ?]|]; | ||
1075 | simplify_eq/=; rewrite ?subst_env_empty //. } | ||
1076 | rewrite -!HE {HE} in H. | ||
1077 | destruct (union_kinded (E1 !! _) _) as [[k1 t1]|], | ||
1078 | (union_kinded (E2 !! _) _) as [[k2 t2]|] eqn:HE2; simplify_res; last first. | ||
1079 | { exists None, (S n). rewrite interp_S /=. by rewrite HE2. } | ||
1080 | eapply interp_thunk_proper | ||
1081 | in Hinterp as (mw & m & Hinterp & ?); [|by eauto..]. | ||
1082 | exists mw, (S (n `max` m)). split; [|done]. rewrite interp_S /= HE2 /=. | ||
1083 | eauto using interp_thunk_le with lia. | ||
1084 | + (* EAbs *) eexists (Some (VClo _ _ _)), 1; split; [by rewrite interp_S|]. | ||
1085 | simpl. auto with f_equal. | ||
1086 | + (* EAbsMatch *) | ||
1087 | eexists (Some (VCloMatch _ _ _ _)), 1; split; [by rewrite interp_S|]. | ||
1088 | simpl. auto with f_equal. | ||
1089 | + (* EApp *) | ||
1090 | destruct (interp n _ e1_1) as [mv1|] eqn:Hinterp'; simplify_eq/=. | ||
1091 | eapply interp_proper in Hinterp' as (mw1 & m1 & Hinterp1 & ?); last done. | ||
1092 | destruct mv1 as [v1|], mw1 as [w1|]; simplify_res; last first. | ||
1093 | { exists None, (S m1). by rewrite interp_S /= Hinterp1. } | ||
1094 | destruct (interp_app n _ _) as [mv'|] eqn:Hinterp'; simplify_res. | ||
1095 | eapply (interp_app_proper _ _ _ _ (Thunk _ _)) in Hinterp' | ||
1096 | as (mw & m2 & Hinterp2 & ?); [|done..]. | ||
1097 | exists mw, (S (m1 `max` m2)). rewrite interp_S /=. | ||
1098 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1099 | rewrite (interp_app_le Hinterp2) /=; last lia. done. | ||
1100 | + (* ESeq *) | ||
1101 | destruct (interp n _ e1_1) as [mv1|] eqn:Hinterp'; simplify_eq/=. | ||
1102 | eapply interp_proper in Hinterp' as (mw1 & m1 & Hinterp1 & ?); last done. | ||
1103 | destruct mv1 as [v1|], mw1 as [w1|]; simplify_res; last first. | ||
1104 | { exists None, (S m1). by rewrite interp_S /= Hinterp1. } | ||
1105 | destruct μ0; simplify_res. | ||
1106 | { eapply interp_proper in Hinterp as (w2 & m2 & Hinterp2 & ?); last done. | ||
1107 | exists w2, (S (m1 `max` m2)). rewrite interp_S /=. | ||
1108 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1109 | rewrite (interp_le Hinterp2) /=; last lia. done. } | ||
1110 | destruct (force_deep _ _) as [mv'|] eqn:Hforce; simplify_res. | ||
1111 | eapply force_deep_proper in Hforce as (mw' & m2 & Hforce & ?); last done. | ||
1112 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
1113 | { exists None, (S (m1 `max` m2)). rewrite interp_S /=. | ||
1114 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1115 | rewrite (force_deep_le Hforce) /=; last lia. done. } | ||
1116 | eapply interp_proper in Hinterp as (w2 & m3 & Hinterp3 & ?); last done. | ||
1117 | exists w2, (S (m1 `max` m2 `max` m3)). rewrite interp_S /=. | ||
1118 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1119 | rewrite (force_deep_le Hforce) /=; last lia. | ||
1120 | rewrite (interp_le Hinterp3) /=; last lia. done. | ||
1121 | + (* EList *) | ||
1122 | eexists (Some (VList _)), 1; rewrite interp_S /=; split; [done|]. | ||
1123 | do 2 f_equal. revert es0 Hsubst. | ||
1124 | induction es; intros [] ?; simplify_eq/=; f_equal/=; auto. | ||
1125 | + (* EAttr *) | ||
1126 | eexists (Some (VAttr _)), 1; rewrite interp_S /=; split; [done|]. | ||
1127 | do 2 f_equal. apply map_eq=> x. rewrite !lookup_fmap. | ||
1128 | pose proof (f_equal (.!! x) Hsubst) as Hx. rewrite !lookup_fmap in Hx. | ||
1129 | destruct (αs !! x) as [[[]]|], (αs0 !! x) as [[[]]|]; | ||
1130 | simplify_eq/=; do 2 f_equal; auto. | ||
1131 | apply indirects_env_proper, Hx. by rewrite !tattr_to_attr_from_attr. | ||
1132 | + (* ELetAttr *) | ||
1133 | destruct (interp n _ _) as [mv'|] eqn:Hinterp'; simplify_eq/=. | ||
1134 | eapply interp_proper in Hinterp' as (mw' & m1 & Hinterp1 & ?); last done. | ||
1135 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
1136 | { exists None, (S m1). by rewrite interp_S /= Hinterp1. } | ||
1137 | destruct (maybe VAttr _) eqn:Hattr; simplify_res; last first. | ||
1138 | { exists None, (S m1). rewrite interp_S /= Hinterp1 /=. | ||
1139 | by assert (maybe VAttr w' = None) as -> by (by destruct v', w'). } | ||
1140 | destruct v', w'; simplify_res. | ||
1141 | eapply interp_proper in Hinterp as (mw & m2 & Hinterp2 & ?); | ||
1142 | [|by apply subst_env_union_fmap_proper]. | ||
1143 | exists mw, (S (m1 `max` m2)). rewrite interp_S /=. | ||
1144 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1145 | rewrite (interp_le Hinterp2) /=; last lia. done. | ||
1146 | + (* EBinOp *) | ||
1147 | destruct (interp n _ e1_1) as [mv1|] eqn:Hinterp1; simplify_res. | ||
1148 | eapply interp_proper in Hinterp1 as (mw1 & m1 & Hinterp1 & Hw1); last done. | ||
1149 | destruct mv1 as [v1|], mw1 as [w1|]; simplify_res; last first. | ||
1150 | { exists None. exists (S m1). by rewrite interp_S /= Hinterp1. } | ||
1151 | apply (interp_bin_op_proper op0) in Hw1. | ||
1152 | destruct (interp_bin_op _ v1) as [f|] eqn:Hop1, | ||
1153 | (interp_bin_op _ w1) as [g|] eqn:Hop2; simplify_res; try done; last first. | ||
1154 | { exists None. exists (S m1). by rewrite interp_S /= Hinterp1 /= Hop2. } | ||
1155 | destruct (interp n _ e1_2) as [mv2|] eqn:Hinterp2; simplify_res. | ||
1156 | eapply interp_proper in Hinterp2 as (mw2 & m2 & Hinterp2 & Hw2); last done. | ||
1157 | destruct mv2 as [v2|], mw2 as [w2|]; simplify_res; last first. | ||
1158 | { exists None. exists (S (m1 `max` m2)). rewrite interp_S /=. | ||
1159 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1160 | rewrite Hop2 /= (interp_le Hinterp2) /=; last lia. done. } | ||
1161 | apply Hw1 in Hw2. | ||
1162 | destruct (f v2) as [t|] eqn:Hf, | ||
1163 | (g w2) as [t'|] eqn:Hg; simplify_res; last first. | ||
1164 | { exists None. exists (S (m1 `max` m2)). rewrite interp_S /=. | ||
1165 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1166 | rewrite Hop2 /= (interp_le Hinterp2) /=; last lia. by rewrite Hg. } | ||
1167 | eapply interp_thunk_proper in Hinterp | ||
1168 | as (mw & m3 & Hforce3 & Hw); [|by eauto..]. | ||
1169 | exists mw, (S (m1 `max` m2 `max` m3)). rewrite interp_S /=. split; [|done]. | ||
1170 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1171 | rewrite Hop2 /= (interp_le Hinterp2) /=; last lia. | ||
1172 | rewrite Hg /=. eauto using interp_thunk_le with lia. | ||
1173 | + (* EIf *) | ||
1174 | destruct (interp n _ e1_1) as [mv1|] eqn:Hinterp1; simplify_res. | ||
1175 | eapply interp_proper in Hinterp1 as (mw1 & m1 & Hinterp1 & Hw1); last done. | ||
1176 | destruct mv1 as [v1|], mw1 as [w1|]; simplify_res; last first. | ||
1177 | { exists None. exists (S m1). by rewrite interp_S /= Hinterp1. } | ||
1178 | destruct (maybe_VLit _ ≫= maybe LitBool) as [b|] eqn:Hbool; | ||
1179 | simplify_res; last first. | ||
1180 | { exists None. exists (S m1). rewrite interp_S /= Hinterp1 /=. | ||
1181 | destruct v1, w1; repeat destruct select base_lit; naive_solver. } | ||
1182 | eapply (interp_proper _ _ _ _ (if b then _ else _)) in Hinterp | ||
1183 | as (mw & m2 & Hinterp & Hw); last by destruct b. | ||
1184 | exists mw, (S (m1 `max` m2)). split; [|done]. rewrite interp_S /=. | ||
1185 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1186 | assert (maybe_VLit w1 ≫= maybe LitBool = Some b) as ->. | ||
1187 | { destruct v1, w1; repeat destruct select base_lit; naive_solver. } | ||
1188 | rewrite /=. eauto using interp_le with lia. | ||
1189 | (* interp_thunk_proper *) | ||
1190 | - destruct n as [|n]; [done|]. | ||
1191 | intros Ht Hinterp. rewrite interp_thunk_S in Hinterp. | ||
1192 | destruct t1 as [v1|E1 e1|x1 E1 tαs1], t2 as [v2|E2 e2|x2 E2 tαs2]; simplify_res. | ||
1193 | + exists (Some v2), 1. rewrite interp_thunk_S /=. auto with f_equal. | ||
1194 | + destruct (interp_val_to_expr E2 e2 v1) as (w & m & ? & ?); first done. | ||
1195 | exists (Some w), (S m); simpl; auto with f_equal. | ||
1196 | + by destruct v1. | ||
1197 | + exists (Some v2), 1; split; [done|]; simpl. | ||
1198 | symmetry. eauto using interp_val_to_expr_Res. | ||
1199 | + eapply interp_proper in Hinterp as (mw & m & ? & ?); eauto. | ||
1200 | exists mw, (S m). eauto. | ||
1201 | + assert (∃ αs1, e1 = ESelect (EAttr αs1) x2 ∧ | ||
1202 | attr_subst_env E1 <$> αs1 = tattr_to_attr E2 <$> tαs2) as (αs1 & -> & Hαs). | ||
1203 | { repeat match goal with | ||
1204 | | H : subst_env _ ?e = _ |- _ => | ||
1205 | rewrite subst_env_eq in H; destruct e; simplify_eq; [] | ||
1206 | end; eauto. } | ||
1207 | clear Ht. destruct n as [|n]; [done|]. | ||
1208 | rewrite !interp_S /= in Hinterp. | ||
1209 | (* without [in Hinterp at 2 3] the termination checker loops *) | ||
1210 | destruct n as [|n'] in Hinterp at 2 3; [done|]. | ||
1211 | rewrite !interp_S /= lookup_fmap in Hinterp. | ||
1212 | pose proof (f_equal (.!! x2) Hαs) as Hx. rewrite !lookup_fmap in Hx. | ||
1213 | destruct (αs1 !! x2) as [[[] e1]|], | ||
1214 | (tαs2 !! x2) as [[e2|t2]|] eqn:Hx2; simplify_res. | ||
1215 | * rewrite -tattr_to_attr_from_attr in Hαs. | ||
1216 | destruct n as [|n]; [done|]. rewrite interp_thunk_S in Hinterp. | ||
1217 | eapply interp_proper in Hinterp as (mw & m & Hinterp & ?); | ||
1218 | last by apply indirects_env_proper. | ||
1219 | exists mw, (S m). by rewrite interp_thunk_S /= Hx2. | ||
1220 | * eapply interp_thunk_proper in Hinterp | ||
1221 | as (mw & m & Hinterp & ?); last done. | ||
1222 | exists mw, (S m). rewrite interp_thunk_S /= Hx2. done. | ||
1223 | * exists None, (S n). by rewrite interp_thunk_S /= Hx2. | ||
1224 | + by destruct v2. | ||
1225 | + assert (∃ αs2, e2 = ESelect (EAttr αs2) x1 ∧ | ||
1226 | attr_subst_env E2 <$> αs2 = tattr_to_attr E1 <$> tαs1) as (αs2 & -> & Hαs). | ||
1227 | { repeat match goal with | ||
1228 | | H : _ = subst_env _ ?e |- _ => | ||
1229 | rewrite subst_env_eq in H; destruct e; simplify_eq; [] | ||
1230 | end; eauto. } | ||
1231 | clear Ht. | ||
1232 | pose proof (f_equal (.!! x1) Hαs) as Hx. rewrite !lookup_fmap in Hx. | ||
1233 | destruct (tαs1 !! x1) as [[e1|t1]|], | ||
1234 | (αs2 !! x1) as [[[] e2]|] eqn:Hx2; simplify_res. | ||
1235 | * rewrite -tattr_to_attr_from_attr in Hαs. | ||
1236 | eapply interp_proper in Hinterp as (mw & m & Hinterp & ?); | ||
1237 | last by apply indirects_env_proper. | ||
1238 | exists mw, (S (S (S m))). rewrite interp_thunk_S /= !interp_S /=. | ||
1239 | rewrite lookup_fmap Hx2 /= interp_thunk_S /=. done. | ||
1240 | * apply (interp_thunk_proper _ _ (Thunk E2 e2)) | ||
1241 | in Hinterp as (mw & m & Hinterp & ?); last done. | ||
1242 | destruct m as [|m]; [done|]. | ||
1243 | exists mw, (S (S (S m))). rewrite interp_thunk_S /= !interp_S /=. | ||
1244 | rewrite lookup_fmap Hx2 /= interp_thunk_S /=. done. | ||
1245 | * exists None, (S (S (S n))). rewrite interp_thunk_S /= !interp_S /=. | ||
1246 | rewrite lookup_fmap Hx2 /=. done. | ||
1247 | + pose proof (f_equal (.!! x2) Ht) as Hx. rewrite !lookup_fmap in Hx. | ||
1248 | destruct (tαs1 !! x2) as [[e1|t1]|] eqn:Hx1, | ||
1249 | (tαs2 !! _) as [[e2|t2]|] eqn:Hx2; simplify_res. | ||
1250 | * eapply interp_proper in Hinterp | ||
1251 | as (mw & m & Hinterp & ?); [|by apply indirects_env_proper]. | ||
1252 | exists mw, (S m). rewrite interp_thunk_S /= Hx2. done. | ||
1253 | * eapply interp_thunk_proper in Hinterp as (mw & m & Hinterp & ?); [|done]. | ||
1254 | exists mw, (S m). rewrite interp_thunk_S /= Hx2. done. | ||
1255 | * exists None, 1. by rewrite interp_thunk_S /= Hx2. | ||
1256 | (* interp_app_proper *) | ||
1257 | - destruct n as [|n]; [done|]. | ||
1258 | intros Hv Ht Hinterp. rewrite interp_app_S /= in Hinterp. | ||
1259 | destruct v1, v2; simplify_res. | ||
1260 | + (* VLit *) by eexists None, 1. | ||
1261 | + (* VClo *) | ||
1262 | eapply interp_proper in Hinterp as (mw & m & Hinterp' & ?); | ||
1263 | last by eapply subst_env_insert_proper. | ||
1264 | eexists _, (S m). rewrite interp_app_S /= Hinterp'. done. | ||
1265 | + (* VCloMatch *) | ||
1266 | destruct (interp_thunk n t1') as [mv1|] eqn:Hthunk; simplify_res. | ||
1267 | eapply interp_thunk_proper in Hthunk as (mw1 & m1 & Hthunk & Hw); [|by eauto..]. | ||
1268 | destruct mv1 as [v1|], mw1 as [w1|]; simplify_res; last first. | ||
1269 | { exists None, (S m1). split; [|done]. | ||
1270 | rewrite interp_app_S /= Hthunk /=. done. } | ||
1271 | destruct (maybe VAttr v1) as [ts1|] eqn:?; simplify_res; last first. | ||
1272 | { exists None, (S m1). split; [|done]. | ||
1273 | rewrite interp_app_S /= Hthunk /=. destruct v1, w1; naive_solver. } | ||
1274 | destruct v1, w1; simplify_eq/=. | ||
1275 | rewrite 2!map_fmap_compose in Hw. apply (inj _) in Hw. | ||
1276 | eapply (interp_match_proper _ _ _ _ _ _ strict0) in Hw; last done. | ||
1277 | destruct (interp_match ts1 _ _) as [tαs1|] eqn:Hmatch1, | ||
1278 | (interp_match ts0 _ _) as [tαs2|] eqn:Hmatch2; | ||
1279 | simplify_res; try done; last first. | ||
1280 | { exists None, (S m1). split; [|done]. | ||
1281 | rewrite interp_app_S /= Hthunk /= Hmatch2. done. } | ||
1282 | eapply interp_proper in Hinterp as (mw & m2 & Hinterp & ?); last first. | ||
1283 | { by apply indirects_env_proper. } | ||
1284 | exists mw, (S (m1 `max` m2)). split; [|done]. | ||
1285 | rewrite interp_app_S /=. | ||
1286 | rewrite (interp_thunk_le Hthunk) /=; last lia. | ||
1287 | rewrite Hmatch2 /=. eauto using interp_le with lia. | ||
1288 | + (* VList *) by eexists None, 1. | ||
1289 | + (* VAttr *) | ||
1290 | pose proof (f_equal (.!! "__functor") Hv) as Htf. | ||
1291 | rewrite !lookup_fmap /= in Htf. | ||
1292 | destruct (ts !! _) as [e|] eqn:Hfunc, (ts0 !! _) as [e'|] eqn:Hfunc'; | ||
1293 | simplify_res; last first. | ||
1294 | { exists None, 1. by rewrite interp_app_S /= Hfunc'. } | ||
1295 | destruct (interp_thunk _ _) as [mv'|] eqn:Hinterp'; simplify_res. | ||
1296 | eapply interp_thunk_proper in Hinterp' | ||
1297 | as (mw' & m1 & Hinterp1 & Hw'); [|by eauto..]. | ||
1298 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
1299 | { exists None, (S m1). by rewrite interp_app_S /= Hfunc' /= Hinterp1. } | ||
1300 | destruct (interp_app _ _ _) as [mv'|] eqn:Happ; simplify_res. | ||
1301 | eapply (interp_app_proper _ _ _ _ (Forced (VAttr _))) in Happ | ||
1302 | as (mw' & m2 & Happ2 & ?); [|done|by rewrite /= Hv]. | ||
1303 | destruct mv', mw'; simplify_res; last first. | ||
1304 | { exists None, (S (m1 `max` m2)). rewrite interp_app_S /= Hfunc' /=. | ||
1305 | rewrite (interp_thunk_le Hinterp1) /=; last lia. | ||
1306 | rewrite (interp_app_le Happ2) /=; last lia. done. } | ||
1307 | eapply interp_app_proper in Hinterp as (mw' & m3 & Happ3 & ?); [|done..]. | ||
1308 | exists mw', (S (m1 `max` m2 `max` m3)). rewrite interp_app_S /= Hfunc' /=. | ||
1309 | rewrite (interp_thunk_le Hinterp1) /=; last lia. | ||
1310 | rewrite (interp_app_le Happ2) /=; last lia. | ||
1311 | rewrite (interp_app_le Happ3) /=; last lia. done. | ||
1312 | Qed. | ||
1313 | |||
1314 | Lemma mapM_interp_proper n ts1 ts2 mvs : | ||
1315 | thunk_to_expr <$> ts1 = thunk_to_expr <$> ts2 → | ||
1316 | mapM (mbind (force_deep n) ∘ interp_thunk n) ts1 = Res mvs → | ||
1317 | ∃ mws m, mapM (mbind (force_deep m) ∘ interp_thunk m) ts2 = Res mws ∧ | ||
1318 | fmap (M:=list) val_to_expr <$> mvs = fmap (M:=list) val_to_expr <$> mws. | ||
1319 | Proof. eauto using mapM_interp_proper', force_deep_proper, interp_thunk_proper. Qed. | ||
1320 | |||
1321 | Lemma interp_thunk_as_interp n t mv : | ||
1322 | interp_thunk n t = Res mv → | ||
1323 | ∃ mw m, interp m ∅ (thunk_to_expr t) = Res mw ∧ | ||
1324 | val_to_expr <$> mv = val_to_expr <$> mw. | ||
1325 | Proof. | ||
1326 | revert t mv. induction n as [|n IH]; intros t mv Hinterp; [done|]. | ||
1327 | rewrite interp_thunk_S in Hinterp. destruct t as [v|E e|x E tαs]; simplify_res. | ||
1328 | { destruct (interp_empty_val_to_expr v) as (w & m & Hinterp & ?). | ||
1329 | exists (Some w), m; simpl; auto using f_equal. } | ||
1330 | { eapply interp_proper, Hinterp. by rewrite subst_env_empty. } | ||
1331 | destruct (tαs !! x) as [[e|t]|] eqn:Hx; simplify_res. | ||
1332 | - eapply interp_proper in Hinterp as (mw & m & Hinterp & ?); | ||
1333 | last apply subst_env_indirects_env. | ||
1334 | exists mw, (S (S m)). rewrite !interp_S /=. | ||
1335 | rewrite !lookup_fmap Hx /= interp_thunk_S /=. done. | ||
1336 | - apply IH in Hinterp as (mw & m & Hinterp & ?). | ||
1337 | exists mw, (S (S m)). rewrite !interp_S /=. | ||
1338 | rewrite !lookup_fmap Hx /= interp_thunk_S //=. | ||
1339 | - exists None, (S (S n)). rewrite !interp_S /=. | ||
1340 | by rewrite !lookup_fmap Hx /=. | ||
1341 | Qed. | ||
1342 | |||
1343 | Lemma interp_as_interp_thunk n t mv : | ||
1344 | interp n ∅ (thunk_to_expr t) = Res mv → | ||
1345 | ∃ mw m, interp_thunk m t = Res mw ∧ | ||
1346 | val_to_expr <$> mv = val_to_expr <$> mw. | ||
1347 | Proof. | ||
1348 | revert t mv. induction (lt_wf n) as [[|n] _ IH]; intros t mv Hinterp; [done|]. | ||
1349 | destruct t as [v|E e|x E tαs]; simplify_res. | ||
1350 | { apply interp_empty_val_to_expr_Res in Hinterp. by exists (Some v), 1. } | ||
1351 | { eapply (interp_proper _ _ E) in Hinterp as (mw & m & Hinterp & ?); | ||
1352 | [|by rewrite subst_env_empty]. | ||
1353 | exists mw, (S m). by rewrite interp_thunk_S /=. } | ||
1354 | destruct n as [|n]; [done|]. rewrite !interp_S /= in Hinterp. | ||
1355 | rewrite !lookup_fmap in Hinterp. | ||
1356 | destruct (tαs !! x) as [[e|t]|] eqn:Hx; simplify_res. | ||
1357 | - rewrite interp_thunk_S /= in Hinterp. | ||
1358 | eapply interp_proper in Hinterp as (mw & m & Hinterp & ?); | ||
1359 | last apply symmetry, subst_env_indirects_env. | ||
1360 | exists mw, (S m). rewrite interp_thunk_S /= Hx. done. | ||
1361 | - rewrite interp_thunk_S /= in Hinterp. | ||
1362 | eapply IH in Hinterp as (mw & m & Hinterp & ?); last lia. | ||
1363 | exists mw, (S m). rewrite !interp_thunk_S /= Hx. done. | ||
1364 | - exists None, (S n). rewrite !interp_thunk_S /= Hx. done. | ||
1365 | Qed. | ||
1366 | |||
1367 | Lemma delayed_interp n e e' mv : | ||
1368 | interp n ∅ e' = Res mv → | ||
1369 | e =D=> e' → | ||
1370 | ∃ m, interp m ∅ e = Res mv. | ||
1371 | Proof. | ||
1372 | intros Hinterp Hdel. revert n mv Hinterp. induction Hdel; intros n mv Hinterp. | ||
1373 | - by eauto. | ||
1374 | - apply IHHdel in Hinterp as [m Hinterp]. | ||
1375 | exists (S (S m)). rewrite interp_S /= lookup_empty left_id_L /=. | ||
1376 | by rewrite interp_thunk_S /=. | ||
1377 | - destruct n as [|n]; [done|]. rewrite interp_S /= in Hinterp. | ||
1378 | destruct (interp _ _ e1') as [mv1|] eqn:Hinterp1; simplify_res. | ||
1379 | apply IHHdel1 in Hinterp1 as [m1 Hinterp1]. | ||
1380 | destruct mv1 as [v1|]; simplify_res; last first. | ||
1381 | { exists (S m1). by rewrite interp_S /= Hinterp1. } | ||
1382 | destruct (interp_bin_op op v1) as [f|] eqn:Hf; simplify_res; last first. | ||
1383 | { exists (S m1). by rewrite interp_S /= Hinterp1 /= Hf. } | ||
1384 | destruct (interp _ _ e2') as [mv2|] eqn:Hinterp2; simplify_res. | ||
1385 | apply IHHdel2 in Hinterp2 as [m2 Hinterp2]. exists (S (n `max` m1 `max` m2)). | ||
1386 | rewrite interp_S /= (interp_le Hinterp1); last lia. | ||
1387 | rewrite /= Hf /= (interp_le Hinterp2); last lia. | ||
1388 | destruct mv2; simplify_res; [|done]. | ||
1389 | destruct (f _); simplify_res; [|done]. | ||
1390 | eauto using interp_thunk_le with lia. | ||
1391 | - destruct n as [|n]; [done|]. rewrite interp_S /= in Hinterp. | ||
1392 | destruct (interp _ _ e1') as [mv1|] eqn:Hinterp1; simplify_res. | ||
1393 | apply IHHdel1 in Hinterp1 as [m1 Hinterp1]. | ||
1394 | destruct mv1 as [v1|]; simplify_res; last first. | ||
1395 | { exists (S m1). by rewrite interp_S /= Hinterp1. } | ||
1396 | destruct (maybe_VLit v1 ≫= maybe LitBool) as [[]|] eqn: Hbool; simplify_res. | ||
1397 | + apply IHHdel2 in Hinterp as [m2 Hinterp2]. exists (S (m1 `max` m2)). | ||
1398 | rewrite interp_S /= (interp_le Hinterp1); last lia. | ||
1399 | rewrite /= Hbool /=. eauto using interp_le with lia. | ||
1400 | + apply IHHdel3 in Hinterp as [m3 Hinterp3]. exists (S (m1 `max` m3)). | ||
1401 | rewrite interp_S /= (interp_le Hinterp1); last lia. | ||
1402 | rewrite /= Hbool /=. eauto using interp_le with lia. | ||
1403 | + exists (S m1). rewrite interp_S /= Hinterp1 /= Hbool. done. | ||
1404 | Qed. | ||
1405 | |||
1406 | Lemma interp_subst_abs n x e1 e2 mv : | ||
1407 | interp n ∅ (subst {[x:=(ABS, e2)]} e1) = Res mv → | ||
1408 | ∃ mw m, interp m (<[x:=(ABS, Thunk ∅ e2)]> ∅) e1 = Res mw ∧ | ||
1409 | val_to_expr <$> mv = val_to_expr <$> mw. | ||
1410 | Proof. | ||
1411 | apply interp_proper. by rewrite subst_env_empty subst_abs_as_subst_env. | ||
1412 | Qed. | ||
1413 | |||
1414 | Lemma interp_subst_indirects n e αs mv : | ||
1415 | interp n ∅ (subst (indirects αs) e) = Res mv → | ||
1416 | ∃ mw m, | ||
1417 | interp m (indirects_env ∅ (attr_to_tattr ∅ <$> αs)) e = Res mw ∧ | ||
1418 | val_to_expr <$> mv = val_to_expr <$> mw. | ||
1419 | Proof. | ||
1420 | apply interp_proper. rewrite subst_env_empty. rewrite subst_env_alt. | ||
1421 | f_equal. apply map_eq=> x. rewrite !lookup_fmap. | ||
1422 | destruct (αs !! x) eqn:?; do 2 f_equal/=; | ||
1423 | rewrite /indirects /indirects_env right_id_L !map_lookup_imap | ||
1424 | !lookup_fmap !Heqo //=. | ||
1425 | rewrite tattr_to_attr_from_attr_empty //. | ||
1426 | Qed. | ||
1427 | |||
1428 | Lemma interp_subst_fmap k n e es mv : | ||
1429 | interp n ∅ (subst ((k,.) <$> es) e) = Res mv → | ||
1430 | ∃ mw m, interp m ((k,.) ∘ Thunk ∅ <$> es) e = Res mw ∧ | ||
1431 | val_to_expr <$> mv = val_to_expr <$> mw. | ||
1432 | Proof. | ||
1433 | apply interp_proper. rewrite subst_env_empty. rewrite subst_env_alt. | ||
1434 | f_equal. apply map_eq=> x. rewrite !lookup_fmap. | ||
1435 | destruct (es !! x) as [d|]; do 2 f_equal/=. by rewrite subst_env_empty. | ||
1436 | Qed. | ||
1437 | |||
1438 | Lemma final_interp μ e : | ||
1439 | final μ e → | ||
1440 | ∃ w m, interp m ∅ e = mret w ∧ e = val_to_expr w. | ||
1441 | Proof. | ||
1442 | revert μ. induction e; intros μ'; intros Hfinal; try by inv Hfinal. | ||
1443 | - inv Hfinal. eexists (VLit _ _), 1. by rewrite interp_lit /=. | ||
1444 | - eexists (VClo _ _ _), 1. rewrite interp_S /=. split; [done|]. | ||
1445 | by rewrite /= subst_env_empty. | ||
1446 | - eexists (VCloMatch _ _ _ _), 1. rewrite interp_S /=. split; [done|]. | ||
1447 | rewrite /= subst_env_empty. f_equal. | ||
1448 | apply map_eq=> x. rewrite lookup_fmap. | ||
1449 | destruct (ms !! x) as [[]|]; do 2 f_equal/=. by rewrite subst_env_empty. | ||
1450 | - eexists (VList _), 1. rewrite interp_S /=. split; [done|]. f_equal. clear. | ||
1451 | induction es; f_equal/=; [|done]. | ||
1452 | by rewrite /= subst_env_empty. | ||
1453 | - eexists (VAttr _), 1. rewrite interp_S /=. split; [done|]. | ||
1454 | f_equal. apply map_eq=> x. | ||
1455 | assert (no_recs αs) by (by inv Hfinal). | ||
1456 | rewrite from_attr_no_recs // !lookup_fmap. | ||
1457 | destruct (_ !! _) as [[]|] eqn:?; f_equal/=. | ||
1458 | f_equal; eauto using no_recs_lookup, subst_env_empty. | ||
1459 | Qed. | ||
1460 | |||
1461 | Lemma final_force_deep' v : | ||
1462 | final DEEP (val_to_expr v) → | ||
1463 | ∃ w m, force_deep m v = mret w ∧ val_to_expr v = val_to_expr w. | ||
1464 | Proof. | ||
1465 | intros Hfinal. remember (val_to_expr v) as e eqn:He. | ||
1466 | revert v He. induction e; intros [] ?; simplify_eq/=; inv Hfinal. | ||
1467 | - (* VLit *) eexists (VLit _ _), 1. by rewrite force_deep_S. | ||
1468 | - (* VClo *) | ||
1469 | eexists (VClo _ _ _), 1. by rewrite force_deep_S. | ||
1470 | - (* VCloMatch *) | ||
1471 | eexists (VCloMatch _ _ _ _), 1. by rewrite force_deep_S. | ||
1472 | - (* VList *) | ||
1473 | assert (∃ vs m, mapM (mbind (force_deep m) ∘ interp_thunk m) ts = mret vs ∧ | ||
1474 | val_to_expr <$> vs = thunk_to_expr <$> ts) | ||
1475 | as (vs & m & Hmap & Hvs); last first. | ||
1476 | { exists (VList (Forced <$> vs)), (S m). rewrite force_deep_S /= Hmap /=. | ||
1477 | split; [done|]. f_equal. rewrite -Hvs. | ||
1478 | clear. by induction vs; by f_equal/=. } | ||
1479 | rewrite Forall_fmap in H1. induction H1 as [|t ts Ht ? IH]; simplify_eq/=. | ||
1480 | { by exists [], 0. } | ||
1481 | apply Forall_cons in H as [IHt IHts]. | ||
1482 | destruct IH as (ws & m1 & Hinterp1 & ?); simplify_eq/=; [done|]. clear IHts. | ||
1483 | destruct (final_interp DEEP (thunk_to_expr t)) | ||
1484 | as (v' & m & Hinterp & ?); [done|]. | ||
1485 | apply interp_as_interp_thunk in Hinterp | ||
1486 | as ([v''|] & m' & Hinterp & ?); simplify_res. | ||
1487 | destruct (IHt Ht v'') as (w & m'' & Hforce & ?); [congruence|]. | ||
1488 | exists (w :: ws), (m1 `max` m' `max` m''); csimpl. | ||
1489 | rewrite (interp_thunk_le Hinterp) /=; last lia. | ||
1490 | rewrite (force_deep_le Hforce) /=; last lia. | ||
1491 | rewrite (mapM_interp_le Hinterp1) /=; last lia. auto with f_equal. | ||
1492 | - (* VAttr *) clear H1. assert (∃ vs m, | ||
1493 | map_mapM_sorted attr_le | ||
1494 | (mbind (force_deep m) ∘ interp_thunk m) ts = mret vs ∧ | ||
1495 | val_to_expr <$> vs = thunk_to_expr <$> ts) | ||
1496 | as (vs & m & Hmap & Hvs); last first. | ||
1497 | { exists (VAttr (Forced <$> vs)), (S m). rewrite force_deep_S /= Hmap /=. | ||
1498 | split; [done|]. rewrite 2!map_fmap_compose -Hvs. f_equal. | ||
1499 | apply map_eq=> x. rewrite !lookup_fmap. by destruct (vs !! x). } | ||
1500 | induction ts as [|x t ts Hx ? IH] using (map_sorted_ind attr_le). | ||
1501 | { exists ∅, 0. by rewrite map_mapM_sorted_empty. } | ||
1502 | rewrite fmap_insert /= in H, H2. | ||
1503 | apply map_Forall_insert in H as [IHt IHts]; last by rewrite lookup_fmap Hx. | ||
1504 | apply map_Forall_insert in H2 as [Ht Hts]; last by rewrite lookup_fmap Hx. | ||
1505 | apply IH in IHts as (ws & m1 & Hinterp1 & ?); clear IH; simplify_eq/=; last done. | ||
1506 | destruct (final_interp DEEP (thunk_to_expr t)) | ||
1507 | as (v' & m & Hinterp & ?); [done|]. | ||
1508 | apply interp_as_interp_thunk in Hinterp | ||
1509 | as ([v''|] & m' & Hinterp & ?); simplify_res. | ||
1510 | destruct (IHt Ht v'') as (w & m'' & Hforce & ?); [congruence|]. | ||
1511 | exists (<[x:=w]> ws), (m1 `max` m' `max` m''). | ||
1512 | rewrite fmap_insert map_mapM_sorted_insert //=. | ||
1513 | rewrite (interp_thunk_le Hinterp) /=; last lia. | ||
1514 | rewrite (force_deep_le Hforce) /=; last lia. | ||
1515 | rewrite (map_mapM_interp_le Hinterp1) /=; last lia. | ||
1516 | rewrite fmap_insert. auto with f_equal. | ||
1517 | Qed. | ||
1518 | |||
1519 | Lemma interp_step μ e1 e2 : | ||
1520 | e1 -{μ}-> e2 → | ||
1521 | (∀ n mv, | ||
1522 | ¬final SHALLOW e1 → | ||
1523 | interp n ∅ e2 = Res mv → | ||
1524 | exists mw m, interp m ∅ e1 = Res mw ∧ val_to_expr <$> mv = val_to_expr <$> mw) ∧ | ||
1525 | (∀ n v1 v2 mv, | ||
1526 | μ = DEEP → | ||
1527 | e1 = val_to_expr v1 → | ||
1528 | e2 = val_to_expr v2 → | ||
1529 | force_deep n v2 = Res mv → | ||
1530 | exists mw m, force_deep m v1 = Res mw ∧ val_to_expr <$> mv = val_to_expr <$> mw). | ||
1531 | Proof. | ||
1532 | intros Hstep. induction Hstep; inv_step. | ||
1533 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1534 | apply interp_subst_abs in Hinterp as (mw & [|m] & Hinterp & Hv); simplify_eq/=. | ||
1535 | exists mw, (S (S (S m))). split; [|done]. | ||
1536 | rewrite interp_S /= interp_app_S /= /= !interp_S /=. | ||
1537 | rewrite -!interp_S /=. rewrite (interp_le Hinterp); last lia. done. | ||
1538 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1539 | destruct n as [|n]; simplify_eq/=. apply interp_match_Some_2 in H0. | ||
1540 | apply interp_subst_indirects in Hinterp as (mw & m & Hinterp & ?). | ||
1541 | exists mw, (S (S (S (S m)))); split; [|done]. | ||
1542 | rewrite !interp_S /= interp_app_S /= interp_thunk_S /= (interp_S m) /=. | ||
1543 | rewrite from_attr_no_recs // map_fmap_compose H0 /=. | ||
1544 | eauto using interp_le with lia. | ||
1545 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1546 | destruct n as [|[|[|n]]]; simplify_eq/=. | ||
1547 | rewrite !interp_S /= -!interp_S in Hinterp. | ||
1548 | destruct (interp _ _ e1) as [mw|] eqn:Hinterp'; simplify_res. | ||
1549 | destruct mw as [w|]; simplify_res; last first. | ||
1550 | { exists None, (S (S (S (S n)))). split; [|done]. | ||
1551 | rewrite 2!interp_S /= interp_app_S /=. | ||
1552 | rewrite from_attr_no_recs // lookup_fmap H0 /=. | ||
1553 | rewrite interp_thunk_S /= Hinterp'. done. } | ||
1554 | destruct (interp_app _ _ _) as [mv'|] eqn:Happ; simplify_res. | ||
1555 | eapply (interp_app_proper _ _ _ _ | ||
1556 | (Forced (VAttr (Thunk ∅ ∘ attr_expr <$> αs)))) | ||
1557 | in Happ as (mw' & m1 & Happ1 & Hw); [|done|]; last first. | ||
1558 | { rewrite /= subst_env_eq /=. f_equal. | ||
1559 | apply map_eq=> y. rewrite !lookup_fmap. | ||
1560 | destruct (αs !! y) as [[]|] eqn:?; do 2 f_equal/=; eauto using no_recs_lookup. } | ||
1561 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
1562 | { exists None, (S (S (S (S (n `max` m1))))). split; [|done]. | ||
1563 | rewrite 2!interp_S /= interp_app_S /=. | ||
1564 | rewrite from_attr_no_recs // lookup_fmap H0 /=. | ||
1565 | rewrite interp_thunk_S /= (interp_le Hinterp') /=; last lia. | ||
1566 | rewrite (interp_app_le Happ1); last lia. done. } | ||
1567 | eapply interp_app_proper in Hinterp as (mw & m2 & ? & Hinterp); [|done..]. | ||
1568 | exists mw, (S (S (S (S (n `max` m1 `max` m2))))). split; [|done]. | ||
1569 | rewrite !interp_S /= interp_app_S /=. | ||
1570 | rewrite from_attr_no_recs // lookup_fmap H0 /=. | ||
1571 | rewrite interp_thunk_S /= (interp_le Hinterp') /=; last lia. | ||
1572 | rewrite (interp_app_le Happ1) /=; last lia. | ||
1573 | eauto using interp_app_le with lia. | ||
1574 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1575 | destruct (final_interp μ' e1) as (v & m & Hinterp' & ->); first done. | ||
1576 | destruct μ'. | ||
1577 | { exists mv, (S (n `max` m)). rewrite interp_S /=. | ||
1578 | rewrite (interp_le Hinterp) /=; last lia. | ||
1579 | by rewrite (interp_le Hinterp') /=; last lia. } | ||
1580 | destruct (final_force_deep' v) as (w & m' & Hforce & ?); first done. | ||
1581 | exists mv, (S (n `max` m `max` m')). rewrite interp_S /=. | ||
1582 | rewrite (interp_le Hinterp) /=; last lia. | ||
1583 | rewrite (interp_le Hinterp') /=; last lia. | ||
1584 | by rewrite (force_deep_le Hforce) /=; last lia. | ||
1585 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1586 | rewrite map_fmap_compose in Hinterp. | ||
1587 | apply interp_subst_fmap in Hinterp as (mw & [|m] & Hinterp & Hv); simplify_eq/=. | ||
1588 | rewrite map_fmap_compose in Hinterp. | ||
1589 | exists mw, (S (S m)). rewrite !interp_S /= -interp_S. | ||
1590 | rewrite from_attr_no_recs // right_id_L map_fmap_compose. done. | ||
1591 | - split; last first. | ||
1592 | { intros n [] v2 mv _ Hαs; simplify_eq/=. by destruct H. } | ||
1593 | intros n mv _ Hinterp. destruct n as [|n]; [done|]. | ||
1594 | rewrite interp_S /= in Hinterp; simplify_res. | ||
1595 | eexists _, 1; split; [by rewrite interp_S|]. | ||
1596 | do 2 f_equal/=. apply map_eq=> x /=. rewrite !lookup_fmap. | ||
1597 | destruct (αs !! x) as [[[] ?]|]; do 2 f_equal/=. | ||
1598 | by rewrite subst_env_indirects_env_attr_to_tattr_empty subst_env_empty. | ||
1599 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1600 | apply final_interp in H as (v1 & m1 & Hinterp1 & ->). | ||
1601 | pose proof H1 as Hsem. apply interp_bin_op_Some_2 in H1 as [f Hf]. | ||
1602 | eapply final_interp in H0 as (v2 & m2 & Hinterp2 & ->). | ||
1603 | eapply interp_bin_op_Some_Some_2 in H2 as (t3 & Hfv & Hdel); [|done..]. | ||
1604 | eapply delayed_interp in Hinterp as (m3 & Hinterp); [|done]. | ||
1605 | apply interp_as_interp_thunk in Hinterp as (mw & m & Hinterp3 & ?). | ||
1606 | exists mw, (S (m `max` m1 `max` m2)). split; [|done]. rewrite interp_S /=. | ||
1607 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1608 | rewrite Hf /= (interp_le Hinterp2) /=; last lia. | ||
1609 | rewrite Hfv /= (interp_thunk_le Hinterp3); last lia. done. | ||
1610 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1611 | exists mv, (S (S n)). rewrite !interp_S /= -interp_S. | ||
1612 | eauto using interp_le with lia. | ||
1613 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1614 | exists mv, (S (S n)). rewrite !interp_S /= lookup_empty /=. done. | ||
1615 | - split; [intros ?? []; constructor; by eauto|]. | ||
1616 | intros n [] [] mv _ Hts Hts' Hforce; simplify_eq. | ||
1617 | destruct n as [|n]; [done|rewrite force_deep_S /= in Hforce]. | ||
1618 | destruct (mapM _ _) as [mvs|] eqn:Hmap; simplify_eq/=. | ||
1619 | destruct IHHstep as [IH1 IH2]. | ||
1620 | apply symmetry, fmap_app_inv in Hts | ||
1621 | as (ts1 & [|t1 ts1'] & ? & ? & ?); simplify_eq/=. | ||
1622 | apply symmetry, fmap_app_inv in Hts' | ||
1623 | as (ts2 & [|t2 ts2'] & Hts & ? & ?); simplify_eq/=. | ||
1624 | assert (∃ mws m, | ||
1625 | mapM (mbind (force_deep m) ∘ interp_thunk m) (ts1 ++ t1 :: ts1') = Res mws ∧ | ||
1626 | fmap (M:=list) val_to_expr <$> mvs = fmap (M:=list) val_to_expr <$> mws) | ||
1627 | as (mws & m & Hmap' & Hmvs); last first. | ||
1628 | { exists (VList ∘ fmap Forced <$> mws), (S m). rewrite force_deep_S /= Hmap'. | ||
1629 | split; [done|]. | ||
1630 | destruct mvs as [vs|], mws as [ws|]; simplify_eq/=; do 2 f_equal. | ||
1631 | rewrite list_eq_Forall2 Forall2_fmap in Hmvs. | ||
1632 | by rewrite list_eq_Forall2 !Forall2_fmap. } | ||
1633 | rewrite mapM_res_app in Hmap. | ||
1634 | destruct (mapM _ ts2) as [mvs1|] eqn:Hmap1; simplify_res. | ||
1635 | eapply mapM_interp_proper in Hmap1 as (mws1 & m1 & Hmap1 & ?); [|done]. | ||
1636 | destruct mvs1 as [vs1|], mws1 as [ws1|]; simplify_res; last first. | ||
1637 | { exists None, m1. by rewrite mapM_res_app Hmap1. } | ||
1638 | destruct (interp_thunk n t2) as [mw|] eqn:Hinterp; simplify_res. | ||
1639 | apply interp_thunk_as_interp in Hinterp as (mw' & m & Hinterp & Hmw'). | ||
1640 | destruct (default mfail (force_deep n <$> mw)) | ||
1641 | as [mu|] eqn:Hforce; simplify_res. | ||
1642 | destruct (step_any_shallow _ _ _ Hstep) as [|Hfinal1]. | ||
1643 | + (* SHALLOW *) | ||
1644 | apply IH1 in Hinterp as (mw'' & m' & Hinterp & Hmw''); | ||
1645 | [|by eauto using step_not_final]. | ||
1646 | apply interp_as_interp_thunk in Hinterp as (mw''' & m2 & Hinterp & ?). | ||
1647 | destruct mw as [w|], mw', mw'', mw''' as [w'''|]; simplify_res; last first. | ||
1648 | { exists None, (m1 `max` m2). rewrite mapM_res_app. | ||
1649 | rewrite (mapM_interp_le Hmap1) /=; last lia. | ||
1650 | rewrite (interp_thunk_le Hinterp) /=; last lia. done. } | ||
1651 | eapply (force_deep_proper _ _ w''') | ||
1652 | in Hforce as (mu' & m3 & Hforce & ?); last congruence. | ||
1653 | destruct mu as [u|], mu' as [u'|]; simplify_res; last first. | ||
1654 | { exists None, (m1 `max` m2 `max` m3). rewrite mapM_res_app. | ||
1655 | rewrite (mapM_interp_le Hmap1) /=; last lia. | ||
1656 | rewrite (interp_thunk_le Hinterp) /=; last lia. | ||
1657 | rewrite (force_deep_le Hforce) /=; last lia. done. } | ||
1658 | destruct (mapM _ ts2') as [mvs2|] eqn:Hmap2; simplify_res. | ||
1659 | eapply mapM_interp_proper in Hmap2 as (mws2 & m4 & Hmap2 & ?); [|done]. | ||
1660 | exists ((ws1 ++.) ∘ (u' ::.) <$> mws2), (m1 `max` m2 `max` m3 `max` m4). | ||
1661 | rewrite mapM_res_app. | ||
1662 | rewrite (mapM_interp_le Hmap1) /=; last lia. | ||
1663 | rewrite (interp_thunk_le Hinterp) /=; last lia. | ||
1664 | rewrite (force_deep_le Hforce) /=; last lia. | ||
1665 | rewrite (mapM_interp_le Hmap2) /=; last lia. split; [by destruct mws2|]. | ||
1666 | destruct mvs2, mws2; simplify_res; f_equal. rewrite !fmap_app !fmap_cons. | ||
1667 | congruence. | ||
1668 | + (* DEEP *) | ||
1669 | apply step_final_shallow in Hstep as Hfinal2; last done. | ||
1670 | apply final_interp in Hfinal1 as (w1 & m2 & Hinterpt1 & ?). | ||
1671 | apply interp_as_interp_thunk in Hinterpt1 as (mw'' & m3 & Hinterpt1 & ?). | ||
1672 | apply final_interp in Hfinal2 as (w2' & m4 & Hinterpt2 & ?). | ||
1673 | eapply interp_agree in Hinterp; last apply Hinterpt2. | ||
1674 | destruct mw as [w2|], mw'' as [w2''|]; simplify_res. | ||
1675 | eapply IH2 in Hforce as (mu' & m5 & Hforce & ?); [|by auto with congruence..]. | ||
1676 | eapply (force_deep_proper _ _ w2'') | ||
1677 | in Hforce as (mu'' & m6 & Hforce & ?); last congruence. | ||
1678 | destruct mu as [u|], mu' as [u'|], mu'' as [u''|]; simplify_res; last first. | ||
1679 | { exists None, (m1 `max` m3 `max` m6). rewrite mapM_res_app. | ||
1680 | rewrite (mapM_interp_le Hmap1) /=; last lia. | ||
1681 | rewrite (interp_thunk_le Hinterpt1) /=; last lia. | ||
1682 | rewrite (force_deep_le Hforce) /=; last lia. done. } | ||
1683 | destruct (mapM _ ts2') as [mvs2|] eqn:Hmap2; simplify_res. | ||
1684 | eapply mapM_interp_proper in Hmap2 as (mws2 & m7 & Hmap2 & ?); [|done]. | ||
1685 | exists ((ws1 ++.) ∘ (u'' ::.) <$> mws2), (m1 `max` m3 `max` m6 `max` m7). | ||
1686 | rewrite mapM_res_app. | ||
1687 | rewrite (mapM_interp_le Hmap1) /=; last lia. | ||
1688 | rewrite (interp_thunk_le Hinterpt1) /=; last lia. | ||
1689 | rewrite (force_deep_le Hforce) /=; last lia. | ||
1690 | rewrite (mapM_interp_le Hmap2) /=; last lia. split; [by destruct mws2|]. | ||
1691 | destruct mvs2, mws2; simplify_res; f_equal. rewrite !fmap_app !fmap_cons. | ||
1692 | congruence. | ||
1693 | - split; [intros ?? []; constructor; by eauto using no_recs_insert|]. | ||
1694 | intros n [] [] mv _ Hts Hts' Hforce; simplify_eq. | ||
1695 | destruct n as [|n]; [done|rewrite force_deep_S /= in Hforce]. | ||
1696 | destruct (map_mapM_sorted _ _ _) as [mvs|] eqn:Hmap; simplify_eq/=. | ||
1697 | destruct IHHstep as [IH1 IH2]. | ||
1698 | apply symmetry, fmap_insert_inv in Hts | ||
1699 | as (t1 & ts1 & ? & Hx1 & ? & ?); simplify_eq/=; last done. | ||
1700 | apply symmetry, fmap_insert_inv in Hts' as (t2 & ts2 & ? & Hx2 & ? & Hts); | ||
1701 | simplify_eq/=; last by rewrite lookup_fmap Hx1. | ||
1702 | assert (∃ mws m, | ||
1703 | map_mapM_sorted attr_le (mbind (force_deep m) ∘ interp_thunk m) | ||
1704 | (<[x:=t1]> ts1) = Res mws ∧ | ||
1705 | fmap (M:=gmap _) val_to_expr <$> mvs = fmap (M:=gmap _) val_to_expr <$> mws) | ||
1706 | as (mws & m & Hmap' & Hmvs); last first. | ||
1707 | { exists (VAttr ∘ fmap Forced <$> mws), (S m). rewrite force_deep_S /= Hmap'. | ||
1708 | split; [done|]. | ||
1709 | destruct mvs as [vs|], mws as [ws|]; simplify_eq/=; do 2 f_equal. | ||
1710 | apply map_eq=> y. rewrite !lookup_fmap. | ||
1711 | apply (f_equal (.!! y)) in Hmvs. rewrite !lookup_fmap in Hmvs. | ||
1712 | destruct (vs !! _), (ws !! _); simplify_eq/=; auto with f_equal. } | ||
1713 | destruct (step_any_shallow _ _ _ Hstep) as [|Hfinal]. | ||
1714 | + (* SHALLOW *) assert (map_Forall2 (λ _ t1 t2, ∀ n mv, | ||
1715 | interp n ∅ (thunk_to_expr t2) = Res mv → | ||
1716 | ∃ mw m, interp m ∅ (thunk_to_expr t1) = Res mw ∧ | ||
1717 | val_to_expr <$> mv = val_to_expr <$> mw) | ||
1718 | (<[x:=t1]> ts1) (<[x:=t2]> ts2)) as IHts. | ||
1719 | { apply map_Forall2_insert_2; first by eauto using step_not_final. | ||
1720 | intros y. apply (f_equal (.!! y)) in Hts. rewrite !lookup_fmap in Hts. | ||
1721 | destruct (ts1 !! y), (ts2 !! y); simplify_eq/=; constructor. | ||
1722 | rewrite -Hts; eauto. } | ||
1723 | revert IHts Hmap. generalize (<[x:=t1]> ts1) (<[x:=t2]> ts2). clear. | ||
1724 | intros ts1. revert n mvs. | ||
1725 | induction ts1 as [|x t1 ts1 ?? IH] using (map_sorted_ind attr_le); | ||
1726 | intros n mvs ts2' IHts Hmap. | ||
1727 | { apply map_Forall2_empty_inv_l in IHts as ->. | ||
1728 | rewrite map_mapM_sorted_empty in Hmap; simplify_res. | ||
1729 | by exists (Some ∅), 1. } | ||
1730 | apply map_Forall2_insert_inv_l in IHts | ||
1731 | as (t2 & ts2 & -> & ? & IHt & IHts); simplify_eq/=; last done. | ||
1732 | assert (∀ j, is_Some (ts2 !! j) → attr_le x j). | ||
1733 | { apply map_Forall2_dom_L in IHts. intros j. | ||
1734 | rewrite -elem_of_dom -IHts elem_of_dom. auto. } | ||
1735 | rewrite map_mapM_sorted_insert //= in Hmap. | ||
1736 | destruct (interp_thunk _ _) as [mv|] eqn:Hinterp; simplify_res. | ||
1737 | assert (∃ mw m, interp_thunk m t1 = Res mw ∧ | ||
1738 | val_to_expr <$> mv = val_to_expr <$> mw) as (mw & m1 & Hinterp1 & ?). | ||
1739 | { apply interp_thunk_as_interp in Hinterp as (mw & m & Hinterp & ?). | ||
1740 | apply IHt in Hinterp as (mw' & m' & Hinterp & ?). | ||
1741 | eapply interp_as_interp_thunk in Hinterp as (mw'' & m'' & Hinterp & ?). | ||
1742 | exists mw'', m''. eauto with congruence. } | ||
1743 | destruct mv as [v|], mw as [w|]; simplify_res; last first. | ||
1744 | { exists None, m1. split; [|done]. rewrite map_mapM_sorted_insert //=. | ||
1745 | by rewrite Hinterp1. } | ||
1746 | destruct (force_deep _ _) as [mv|] eqn:Hforce; simplify_res. | ||
1747 | eapply force_deep_proper in Hforce as (mw & m2 & Hforce' & ?); last done. | ||
1748 | destruct mv as [v'|], mw as [w'|]; simplify_res; last first. | ||
1749 | { exists None, (m1 `max` m2). split; [|done]. | ||
1750 | rewrite map_mapM_sorted_insert //=. | ||
1751 | rewrite (interp_thunk_le Hinterp1) /=; last lia. | ||
1752 | rewrite (force_deep_le Hforce') /=; last lia. done. } | ||
1753 | destruct (map_mapM_sorted _ _ _) as [mvs'|] eqn:Hmap'; simplify_res. | ||
1754 | apply IH in Hmap' as (mws & m3 & Hmap3 & ?); last done. | ||
1755 | exists (fmap <[x:=w']> mws), (m1 `max` m2 `max` m3). | ||
1756 | rewrite map_mapM_sorted_insert //=. | ||
1757 | rewrite (interp_thunk_le Hinterp1) /=; last lia. | ||
1758 | rewrite (force_deep_le Hforce') /=; last lia. | ||
1759 | rewrite (map_mapM_interp_le Hmap3) /=; last lia. | ||
1760 | destruct mvs', mws; simplify_res; last done. | ||
1761 | rewrite !fmap_insert. auto with f_equal. | ||
1762 | + (* DEEP *) | ||
1763 | assert (map_Forall2 (λ _ t1 t2, | ||
1764 | thunk_to_expr t1 = thunk_to_expr t2 ∨ | ||
1765 | ∃ v1 v2, | ||
1766 | thunk_to_expr t1 = val_to_expr v1 ∧ | ||
1767 | thunk_to_expr t2 = val_to_expr v2 ∧ | ||
1768 | ∀ n mv, | ||
1769 | force_deep n v2 = Res mv → | ||
1770 | ∃ mw m, force_deep m v1 = Res mw ∧ val_to_expr <$> mv = val_to_expr <$> mw) | ||
1771 | (<[x:=t1]> ts1) (<[x:=t2]> ts2)) as IHts. | ||
1772 | { apply map_Forall2_insert_2; last first. | ||
1773 | { intros y. apply (f_equal (.!! y)) in Hts. rewrite !lookup_fmap in Hts. | ||
1774 | destruct (ts1 !! y), (ts2 !! y); simplify_eq/=; constructor; eauto. } | ||
1775 | assert (final SHALLOW (thunk_to_expr t2)) | ||
1776 | as (v2 & m2 & Hinterp2 & Ht2)%final_interp | ||
1777 | by eauto using step_final_shallow. | ||
1778 | apply final_interp in Hfinal as (v1 & m1 & Hinterp1 & Ht1); eauto 10. } | ||
1779 | revert IHts Hmap. generalize (<[x:=t1]> ts1) (<[x:=t2]> ts2). clear. | ||
1780 | intros ts1. revert n mvs. | ||
1781 | induction ts1 as [|x t1 ts1 ?? IH] using (map_sorted_ind attr_le); | ||
1782 | intros n mvs ts2' IHts Hmap. | ||
1783 | { apply map_Forall2_empty_inv_l in IHts as ->. | ||
1784 | rewrite map_mapM_sorted_empty in Hmap; simplify_res. | ||
1785 | by exists (Some ∅), 1. } | ||
1786 | apply map_Forall2_insert_inv_l in IHts | ||
1787 | as (t2 & ts2 & -> & ? & IHt & IHts); simplify_eq/=; last done. | ||
1788 | assert (∀ j, is_Some (ts2 !! j) → attr_le x j). | ||
1789 | { apply map_Forall2_dom_L in IHts. intros j. | ||
1790 | rewrite -elem_of_dom -IHts elem_of_dom. auto. } | ||
1791 | rewrite map_mapM_sorted_insert //= in Hmap. | ||
1792 | destruct (interp_thunk n t2 ≫= force_deep n) | ||
1793 | as [mv|] eqn:Hinterp; simplify_res. | ||
1794 | assert (∃ mw m, interp_thunk m t1 ≫= force_deep m = Res mw ∧ | ||
1795 | val_to_expr <$> mv = val_to_expr <$> mw) as (mw & m1 & Hinterp1 & ?). | ||
1796 | { destruct (interp_thunk _ _) as [mv'|] eqn:Hthunk; simplify_res. | ||
1797 | destruct IHt as [|(v1 & v2 & Ht1 & Ht2 & IHt)]. | ||
1798 | * eapply interp_thunk_proper in Hthunk | ||
1799 | as (mw' & m1 & Hthunk1 & ?); last done. | ||
1800 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
1801 | { exists None, m1. by rewrite Hthunk1. } | ||
1802 | eapply force_deep_proper in Hinterp | ||
1803 | as (mw & m2 & Hforce2 & ?); last done. | ||
1804 | exists mw, (m1 `max` m2). split; [|done]. | ||
1805 | rewrite (interp_thunk_le Hthunk1) /=; last lia. | ||
1806 | eauto using force_deep_le with lia. | ||
1807 | * destruct (interp_empty_val_to_expr v1) as (v1' & m1 & Hinterp1 & ?). | ||
1808 | rewrite -Ht1 in Hinterp1. | ||
1809 | eapply interp_as_interp_thunk in Hinterp1 | ||
1810 | as ([v1''|] & m1' & Hthunk1 & ?); simplify_res. | ||
1811 | eapply (interp_thunk_proper _ _ (Forced v2)) in Hthunk | ||
1812 | as (mw2 & m2 & Hthunk2 & ?); simplify_res; [|done]. | ||
1813 | destruct m2 as [|m2]; [done|]. | ||
1814 | rewrite interp_thunk_S in Hthunk2; simplify_res. | ||
1815 | destruct mv' as [v2'|]; simplify_res. | ||
1816 | eapply force_deep_proper in Hinterp | ||
1817 | as (mv' & m2' & Hforce2 & ?); last done. | ||
1818 | eapply IHt in Hforce2 as (mw' & m2'' & Hforce2 & ?). | ||
1819 | eapply (force_deep_proper _ _ v1'') in Hforce2 | ||
1820 | as (mw'' & m2''' & Hforce2 & ?); last congruence. | ||
1821 | exists mw'', (m1' `max` m2'''). | ||
1822 | rewrite (interp_thunk_le Hthunk1) /=; last lia. | ||
1823 | rewrite (force_deep_le Hforce2) /=; last lia. auto with congruence. } | ||
1824 | destruct mv as [v|], mw as [w|]; simplify_res; last first. | ||
1825 | { exists None, m1. split; [|done]. rewrite map_mapM_sorted_insert //=. | ||
1826 | by rewrite Hinterp1. } | ||
1827 | destruct (map_mapM_sorted _ _ _) as [mvs'|] eqn:Hmap'; simplify_res. | ||
1828 | apply IH in Hmap' as (mws & m2 & Hmap2 & ?); last done. | ||
1829 | exists (fmap <[x:=w]> mws), (m1 `max` m2). | ||
1830 | rewrite map_mapM_sorted_insert //=. | ||
1831 | destruct (interp_thunk m1 t1) as [[]|] eqn:Hinterp'; simplify_res. | ||
1832 | rewrite (interp_thunk_le Hinterp') /=; last lia. | ||
1833 | rewrite (force_deep_le Hinterp1) /=; last lia. | ||
1834 | rewrite (map_mapM_interp_le Hmap2) /=; last lia. | ||
1835 | destruct mvs', mws; simplify_res; last done. | ||
1836 | rewrite !fmap_insert. auto with f_equal. | ||
1837 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1838 | destruct n as [|n]; simplify_eq/=. | ||
1839 | rewrite interp_S /= in Hinterp. | ||
1840 | destruct (interp n ∅ e') as [mv'|] eqn:Hinterp'; simplify_res. | ||
1841 | apply IHHstep in Hinterp' | ||
1842 | as (mw' & m1 & Hinterp1 & ?); last by eauto using step_not_final. | ||
1843 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
1844 | { exists None, (S m1). split; [|done]. by rewrite interp_S /= Hinterp1. } | ||
1845 | eapply interp_app_proper in Hinterp as (mw & m2 & Happ2 & ?); [|done..]. | ||
1846 | exists mw, (S (m1 `max` m2)). rewrite interp_S /=. | ||
1847 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1848 | rewrite (interp_app_le Happ2) /=; last lia. done. | ||
1849 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1850 | destruct n as [|[|[|n]]]; simplify_eq/=. | ||
1851 | rewrite !interp_S /= interp_app_S /= interp_thunk_S /= in Hinterp. | ||
1852 | destruct (interp n ∅ e') as [mv'|] eqn:Hinterp'; simplify_res. | ||
1853 | apply IHHstep in Hinterp' | ||
1854 | as (mw' & m1 & Hinterp1 & Hw'); last by eauto using step_not_final. | ||
1855 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
1856 | { exists None, (S (S (S m1))). split; [|done]. | ||
1857 | rewrite !interp_S /= interp_app_S /= interp_thunk_S /=. | ||
1858 | by rewrite Hinterp1. } | ||
1859 | destruct (maybe VAttr v') as [ts|] eqn:?; simplify_res; last first. | ||
1860 | { exists None, (S (S (S m1))). split; [|done]. | ||
1861 | rewrite !interp_S /= interp_app_S /= interp_thunk_S /= Hinterp1 /=. | ||
1862 | assert (maybe VAttr w' = None) as ->; [|done]. | ||
1863 | destruct v', w'; naive_solver. } | ||
1864 | destruct v', w'; simplify_eq/=. | ||
1865 | rewrite 2!map_fmap_compose in Hw'. apply (inj _) in Hw'. | ||
1866 | eapply (interp_match_proper ∅ ∅ _ _ ms ms strict) in Hw'; [|done]. | ||
1867 | destruct (interp_match ts _ strict) as [tαs1|] eqn:Hmatch1, | ||
1868 | (interp_match ts1 _ strict) as [tαs2|] eqn:Hmatch2; | ||
1869 | simplify_res; try done; last first. | ||
1870 | { exists None, (S (S (S m1))). split; [|done]. | ||
1871 | rewrite !interp_S /= interp_app_S /= interp_thunk_S /=. | ||
1872 | rewrite Hinterp1 /= Hmatch2. done. } | ||
1873 | eapply interp_proper in Hinterp | ||
1874 | as (mw & m2 & Hinterp & ?); last first. | ||
1875 | { by apply indirects_env_proper. } | ||
1876 | exists mw, (S (S (S (m1 `max` m2)))). split; [|done]. | ||
1877 | rewrite !interp_S /= interp_app_S /= interp_thunk_S /=. | ||
1878 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1879 | rewrite Hmatch2 /=. eauto using interp_le with lia. | ||
1880 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1881 | destruct n as [|n]; [done|rewrite interp_S /= in Hinterp]. | ||
1882 | destruct (interp n _ e') as [mv'|] eqn:Hinterp'; simplify_eq/=. | ||
1883 | destruct (step_any_shallow μ e e') as [|Hfinal]; first done. | ||
1884 | + apply IHHstep in Hinterp' | ||
1885 | as (mw' & m & Hinterp' & Hw); last by eauto using step_not_final. | ||
1886 | destruct mv' as [v|], mw' as [w'|]; simplify_res; last first. | ||
1887 | { exists None, (S m). by rewrite interp_S /= Hinterp'. } | ||
1888 | destruct μ; simplify_res. | ||
1889 | { exists mv, (S (n `max` m)). rewrite interp_S /=. | ||
1890 | rewrite (interp_le Hinterp') /=; last lia. | ||
1891 | rewrite (interp_le Hinterp) /=; last lia. done. } | ||
1892 | destruct (force_deep n v) as [mv'|] eqn:Hforce; simplify_res. | ||
1893 | eapply force_deep_proper | ||
1894 | in Hforce as (mw' & m2 & Hforce2 & ?); last done. | ||
1895 | exists mv, (S (n `max` m `max` m2)). split; [|done]. rewrite interp_S /=. | ||
1896 | rewrite (interp_le Hinterp') /=; last lia. | ||
1897 | rewrite (force_deep_le Hforce2) /=; last lia. | ||
1898 | destruct mv', mw'; simplify_res; eauto using interp_le with lia. | ||
1899 | + destruct μ; [by odestruct step_not_final|]. | ||
1900 | assert (final SHALLOW e') as (w & m & Hinterp'' & ->)%final_interp | ||
1901 | by eauto using step_final_shallow. | ||
1902 | apply interp_empty_val_to_expr_Res in Hinterp'. | ||
1903 | destruct mv' as [v|]; simplify_res. | ||
1904 | destruct (force_deep n v) as [mv'|] eqn:Hforce; simplify_res. | ||
1905 | apply final_interp in Hfinal as (w' & m' & Hinterp''' & ->). | ||
1906 | eapply IHHstep in Hforce as (mw' & m'' & Hforce' & ?); [|done..]. | ||
1907 | exists mv, (S (n `max` m' `max` m'')). rewrite interp_S /=. | ||
1908 | rewrite (interp_le Hinterp''') /=; last lia. | ||
1909 | rewrite (force_deep_le Hforce') /=; last lia. | ||
1910 | destruct mv', mw'; simplify_res; eauto using interp_le with lia. | ||
1911 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1912 | destruct n as [|n]; [done|rewrite interp_S /= in Hinterp]. | ||
1913 | destruct (interp n _ _) as [mv'|] eqn:Hinterp'; simplify_eq/=. | ||
1914 | apply IHHstep in Hinterp' | ||
1915 | as (mw' & m1 & Hinterp1 & Hw); last by eauto using step_not_final. | ||
1916 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
1917 | { exists None, (S m1). by rewrite interp_S /= Hinterp1. } | ||
1918 | destruct (maybe VAttr _) eqn:Hattr; simplify_res; last first. | ||
1919 | { exists None, (S m1). rewrite interp_S /= Hinterp1 /=. | ||
1920 | by assert (maybe VAttr w' = None) as -> by (by destruct v', w'). } | ||
1921 | destruct v', w'; simplify_res. | ||
1922 | rewrite right_id_L in Hinterp. | ||
1923 | eapply interp_proper in Hinterp as (mw & m2 & Hinterp2 & ?); | ||
1924 | last by apply subst_env_fmap_proper. | ||
1925 | exists mw, (S (m1 `max` m2)). rewrite !interp_S /=. | ||
1926 | rewrite (interp_le Hinterp1) /=; last lia. rewrite right_id_L. | ||
1927 | by rewrite (interp_le Hinterp2) /=; last lia. | ||
1928 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1929 | destruct n as [|n]; [done|rewrite interp_S /= in Hinterp]. | ||
1930 | destruct (interp n _ e') as [mv1|] eqn:Hinterp1; simplify_eq/=. | ||
1931 | apply IHHstep in Hinterp1 as (mw1 & m & Hinterp1 & Hw1); | ||
1932 | last by eauto using step_not_final. | ||
1933 | destruct mv1 as [v1|], mw1 as [w1|]; simplify_res; last first. | ||
1934 | { exists None, (S m). by rewrite interp_S /= Hinterp1. } | ||
1935 | apply (interp_bin_op_proper op) in Hw1. | ||
1936 | destruct (interp_bin_op _ v1) as [f|] eqn:Hopf; simplify_res; last first. | ||
1937 | { exists None, (S m). rewrite interp_S /= Hinterp1 /=. | ||
1938 | by destruct (interp_bin_op _ w1). } | ||
1939 | destruct (interp_bin_op _ w1) as [g|] eqn:Hopg; simplify_res; [|done]. | ||
1940 | destruct (interp n _ e2) as [mv2|] eqn:Hinterp2; simplify_res. | ||
1941 | destruct mv2 as [v2|]; simplify_res; last first. | ||
1942 | { exists None, (S (n `max` m)). split; [|done]. rewrite interp_S /=. | ||
1943 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1944 | rewrite (interp_le Hinterp2) /=; last lia. by rewrite Hopg. } | ||
1945 | specialize (Hw1 v2 _ eq_refl). | ||
1946 | destruct (f v2) as [t2|], (g v2) as [t2'|] eqn:Hg; simplify_res; last first. | ||
1947 | { exists None, (S (n `max` m)). split; [|done]. rewrite interp_S /=. | ||
1948 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1949 | rewrite (interp_le Hinterp2) /=; last lia. by rewrite Hopg /= Hg. } | ||
1950 | eapply interp_thunk_proper in Hinterp as (mw & m' & Hthunk & ?); last done. | ||
1951 | exists mw, (S (n `max` m `max` m')). split; [|done]. rewrite interp_S /=. | ||
1952 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1953 | rewrite (interp_le Hinterp2) /=; last lia. rewrite Hopg /= Hg /=. | ||
1954 | rewrite (interp_thunk_le Hthunk) /=; last lia. done. | ||
1955 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1956 | destruct n as [|n]; [done|rewrite interp_S /= in Hinterp]. | ||
1957 | destruct (interp n ∅ e1) as [mw1|] eqn:Hinterp1; simplify_res. | ||
1958 | apply final_interp in H0 as (v1 & m1 & Hinterp1' & ->). | ||
1959 | apply interp_bin_op_Some_2 in H1 as [f Hop]. | ||
1960 | assert (mw1 = Some v1) as -> by eauto using interp_agree. | ||
1961 | rewrite /= Hop /= in Hinterp. | ||
1962 | destruct (interp _ _ e') as [mv2|] eqn:Hinterp2; simplify_res; last first. | ||
1963 | apply IHHstep in Hinterp2 as (mw2 & m & Hinterp2 & Hw); | ||
1964 | last by eauto using step_not_final. | ||
1965 | destruct mv2 as [v2|], mw2 as [w2|]; simplify_res; last first. | ||
1966 | { exists None, (S (n `max` m)). split; [|done]. rewrite interp_S /=. | ||
1967 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1968 | rewrite (interp_le Hinterp2) /=; last lia. by rewrite Hop. } | ||
1969 | pose proof @eq_refl as Hf%(interp_bin_op_proper op v1). rewrite !Hop in Hf. | ||
1970 | apply Hf in Hw; clear Hf. | ||
1971 | destruct (f v2) as [t|] eqn:Hf, | ||
1972 | (f w2) as [t'|] eqn:Hf'; simplify_res; last first. | ||
1973 | { exists None, (S (n `max` m)). split; [|done]. rewrite interp_S /=. | ||
1974 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1975 | rewrite (interp_le Hinterp2) /=; last lia. by rewrite Hop /= Hf'. } | ||
1976 | eapply interp_thunk_proper in Hinterp as (mw & m' & Hthunk & ?); last done. | ||
1977 | exists mw, (S (n `max` m `max` m')). split; [|done]. rewrite interp_S /=. | ||
1978 | rewrite (interp_le Hinterp1) /=; last lia. | ||
1979 | rewrite (interp_le Hinterp2) /=; last lia. rewrite Hop /= Hf' /=. | ||
1980 | eauto using interp_thunk_le with lia. | ||
1981 | - split; [|by intros ? []]. intros n mv _ Hinterp. | ||
1982 | destruct n as [|n]; [done|rewrite interp_S /= in Hinterp]. | ||
1983 | destruct (interp n _ e') as [mv1|] eqn:Hinterp1; simplify_eq/=. | ||
1984 | apply IHHstep in Hinterp1 as (mw1 & m & Hinterp1 & Hw1); | ||
1985 | last by eauto using step_not_final. | ||
1986 | destruct mv1 as [v1|], mw1 as [w1|]; simplify_res; last first. | ||
1987 | { exists None, (S m). by rewrite interp_S /= Hinterp1. } | ||
1988 | exists mv, (S (n `max` m)). split; [|done]. | ||
1989 | rewrite interp_S /= (interp_le Hinterp1) /=; last lia. | ||
1990 | assert (maybe_VLit w1 ≫= maybe LitBool = maybe_VLit v1 ≫= maybe LitBool) as ->. | ||
1991 | { destruct v1, w1; repeat destruct select base_lit; naive_solver. } | ||
1992 | destruct (maybe_VLit v1 ≫= maybe LitBool); simplify_res; [|done]. | ||
1993 | eauto using interp_le with lia. | ||
1994 | Qed. | ||
1995 | |||
1996 | Lemma final_interp' μ e : | ||
1997 | final μ e → | ||
1998 | ∃ w m, interp' m μ ∅ e = mret w ∧ e = val_to_expr w. | ||
1999 | Proof. | ||
2000 | intros Hfinal. destruct (final_interp _ _ Hfinal) as (w & m & Hinterp & ->). | ||
2001 | destruct μ. | ||
2002 | { exists w, m. by rewrite interp_shallow'. } | ||
2003 | apply final_force_deep' in Hfinal as (w' & m' & Hforce & ?). | ||
2004 | exists w', (m `max` m'); split; [|done]. rewrite /interp'. | ||
2005 | rewrite (interp_le Hinterp) /=; last lia. eauto using force_deep_le with lia. | ||
2006 | Qed. | ||
2007 | |||
2008 | Lemma force_deep_le' {n1 n2 μ v mv} : | ||
2009 | force_deep' n1 μ v = Res mv → n1 ≤ n2 → force_deep' n2 μ v = Res mv. | ||
2010 | Proof. destruct μ; eauto using force_deep_le. Qed. | ||
2011 | |||
2012 | Lemma interp_le' {n1 n2 μ E e mv} : | ||
2013 | interp' n1 μ E e = Res mv → n1 ≤ n2 → interp' n2 μ E e = Res mv. | ||
2014 | Proof. | ||
2015 | rewrite /interp'. intros. | ||
2016 | destruct (interp n1 _ _) as [mw|] eqn:Hinterp; simplify_res. | ||
2017 | rewrite (interp_le Hinterp); last lia. | ||
2018 | destruct mw; simplify_res; eauto using force_deep_le'. | ||
2019 | Qed. | ||
2020 | |||
2021 | Lemma interp_agree' {n1 n2 μ E e mv1 mv2} : | ||
2022 | interp' n1 μ E e = Res mv1 → interp' n2 μ E e = Res mv2 → mv1 = mv2. | ||
2023 | Proof. | ||
2024 | intros He1 He2. apply (inj Res). destruct (total (≤) n1 n2). | ||
2025 | - rewrite -He2. symmetry. eauto using interp_le'. | ||
2026 | - rewrite -He1. eauto using interp_le'. | ||
2027 | Qed. | ||
2028 | |||
2029 | Lemma interp_step' n μ e1 e2 mv : | ||
2030 | e1 -{μ}-> e2 → | ||
2031 | interp' n μ ∅ e2 = Res mv → | ||
2032 | ∃ mw m, interp' m μ ∅ e1 = Res mw ∧ val_to_expr <$> mv = val_to_expr <$> mw. | ||
2033 | Proof. | ||
2034 | intros Hstep. destruct μ. | ||
2035 | { setoid_rewrite interp_shallow'. | ||
2036 | eapply interp_step; eauto using step_not_final. } | ||
2037 | intros Hinterp. rewrite /interp' in Hinterp. | ||
2038 | destruct (interp n ∅ e2) as [mv'|] eqn:Hinterp'; simplify_res. | ||
2039 | destruct (step_any_shallow _ _ _ Hstep) as [|Hfinal]. | ||
2040 | - eapply interp_step in Hinterp' as (mw' & m & Hinterp' & ?); | ||
2041 | [|by eauto using step_not_final..]. | ||
2042 | destruct mv' as [v'|], mw' as [w'|]; simplify_res; last first. | ||
2043 | { exists None, m. by rewrite /interp' Hinterp'. } | ||
2044 | eapply force_deep_proper in Hinterp as (mw' & m' & Hforce & ?); last done. | ||
2045 | exists mw', (m `max` m'). rewrite /interp'. | ||
2046 | rewrite (interp_le Hinterp') /=; last lia. | ||
2047 | eauto using force_deep_le with lia. | ||
2048 | - assert (final SHALLOW e2) | ||
2049 | as (w2 & m2 & Hinterpw2 & ->)%final_interp by eauto using step_final_shallow. | ||
2050 | apply final_interp in Hfinal as (w1 & m1 & Hinterpw1 & ->). | ||
2051 | apply interp_empty_val_to_expr_Res in Hinterp'; destruct mv'; simplify_res. | ||
2052 | eapply interp_step in Hstep as [_ Hstep]. | ||
2053 | eapply Hstep in Hinterp as (mw & m & Hforce & ?); [|done..]. | ||
2054 | exists mw, (m `max` m1). split; [|done]. rewrite /interp'. | ||
2055 | rewrite (interp_le Hinterpw1) /=; last lia. | ||
2056 | eauto using force_deep_le with lia. | ||
2057 | Qed. | ||
2058 | |||
2059 | Lemma final_val_to_expr' n μ E e v : | ||
2060 | interp' n μ E e = mret v → final μ (val_to_expr v). | ||
2061 | Proof. | ||
2062 | rewrite /interp'. intros Hinterp. | ||
2063 | destruct (interp _ _ e) as [[w|]|] eqn:Hinterp'; simplify_res. | ||
2064 | destruct μ; simplify_res; eauto using final_force_deep. | ||
2065 | Qed. | ||
2066 | |||
2067 | Lemma red_final_interp μ e : | ||
2068 | red (step μ) e ∨ final μ e ∨ ∃ m, interp' m μ ∅ e = mfail. | ||
2069 | Proof. | ||
2070 | revert μ. induction e; intros μ'. | ||
2071 | - (* ELit *) | ||
2072 | destruct (decide (base_lit_ok b)). | ||
2073 | + right; left. by constructor. | ||
2074 | + do 2 right. exists 1. rewrite /interp' interp_S /=. by case_guard. | ||
2075 | - (* EId *) destruct mkd as [[k d]|]. | ||
2076 | + left. eexists; constructor. | ||
2077 | + do 2 right. by exists 1. | ||
2078 | - (* EAbs *) right; left. constructor. | ||
2079 | - (* EAbsMatch *) right; left. constructor. | ||
2080 | - (* EApp *) destruct (IHe1 SHALLOW) as [[??]|[Hfinal|[m Hinterp]]]. | ||
2081 | + left. eexists. by eapply SAppL. | ||
2082 | + apply final_interp in Hfinal as ([] & m & _ & ->); simplify_res. | ||
2083 | { do 2 right. exists 3. rewrite /interp' interp_S /= interp_lit //. } | ||
2084 | { left. by repeat econstructor. } | ||
2085 | { destruct (IHe2 SHALLOW) as [[??]|[Hfinal|[m2 Hinterp2]]]. | ||
2086 | * left. by repeat econstructor. | ||
2087 | * apply final_interp in Hfinal as (w2 & m2 & Hinterp2 & ->). | ||
2088 | destruct (maybe VAttr w2) as [ts|] eqn:Hw2; last first. | ||
2089 | { do 2 right. exists (S (S (S m2))). | ||
2090 | rewrite /interp' !interp_S /= interp_app_S /= interp_thunk_S /=. | ||
2091 | rewrite Hinterp2 /= Hw2. done. } | ||
2092 | destruct w2; simplify_eq/=. | ||
2093 | destruct (interp_match ts (fmap (M:=option) (subst_env E) <$> ms) strict) | ||
2094 | as [E'|] eqn:Hmatch; last first. | ||
2095 | { do 2 right. exists (S (S (S m2))). | ||
2096 | rewrite /interp' !interp_S /= interp_app_S /= interp_thunk_S /=. | ||
2097 | rewrite Hinterp2 /= Hmatch. done. } | ||
2098 | apply interp_match_Some_1 in Hmatch. | ||
2099 | left. repeat econstructor; [done|]. | ||
2100 | by rewrite map_fmap_compose fmap_attr_expr_Attr. | ||
2101 | * rewrite interp_shallow' in Hinterp2. | ||
2102 | do 2 right. exists (S (S (S m2))). | ||
2103 | rewrite /interp' !interp_S /= interp_app_S /= interp_thunk_S /=. | ||
2104 | by rewrite Hinterp2. } | ||
2105 | { do 2 right. by exists 3. } | ||
2106 | destruct (ts !! "__functor") as [e|] eqn:Hfunc. | ||
2107 | { left. repeat econstructor; by simplify_map_eq. } | ||
2108 | do 2 right. exists (S (S m)). rewrite /interp' !interp_S /=. | ||
2109 | rewrite interp_app_S /= !lookup_fmap Hfunc. done. | ||
2110 | + rewrite interp_shallow' in Hinterp. | ||
2111 | do 2 right. exists (S m). by rewrite /interp' interp_S /= Hinterp. | ||
2112 | - (* ESeq *) destruct (IHe1 μ) as [[??]|[Hfinal|[m Hinterp]]]. | ||
2113 | + left. eexists. by eapply SSeq. | ||
2114 | + left. by repeat econstructor. | ||
2115 | + do 2 right. exists (S m). rewrite /interp' interp_S /=. | ||
2116 | rewrite /interp' in Hinterp. | ||
2117 | destruct (interp _ _ e1) as [[]|], μ; simplify_res; [|done..]. | ||
2118 | by rewrite Hinterp. | ||
2119 | - (* EList *) | ||
2120 | destruct μ'. | ||
2121 | { right; left. by constructor. } | ||
2122 | assert (red (step DEEP) (EList es) ∨ Forall (final DEEP) es ∨ | ||
2123 | ∃ m, mapM (mbind (force_deep m) ∘ interp_thunk m) | ||
2124 | (Thunk ∅ <$> es) = mfail) as Hhelp; last first. | ||
2125 | { destruct Hhelp as [?|[?|[m Hinterp]]]; [by auto using final..|]. | ||
2126 | do 2 right. exists (S m). rewrite /interp' interp_S /=. | ||
2127 | rewrite force_deep_S /=. by rewrite Hinterp. } | ||
2128 | induction H as [|e es He Hes IH]; [by right; left|]. | ||
2129 | destruct (He DEEP) as [[??]|[Hfinal|[m Hinterp]]]; simplify_eq/=. | ||
2130 | + left. eexists. by eapply (SList []). | ||
2131 | + destruct IH as [[??]|[?|[m2 Hinterp2]]]; [|by eauto|]. | ||
2132 | * left. inv_step. eexists. eapply (SList (_ :: _)); by eauto. | ||
2133 | * apply final_interp' in Hfinal as (w & m1 & Hinterp1 & _). | ||
2134 | do 2 right. exists (S (m1 `max` m2)). | ||
2135 | rewrite /interp' /force_deep' in Hinterp1. | ||
2136 | destruct (interp m1 _ _) as [[]|] eqn:Hinterp1'; simplify_res. | ||
2137 | rewrite interp_thunk_S /= (interp_le Hinterp1') /=; last lia. | ||
2138 | rewrite (force_deep_le Hinterp1) /=; last lia. | ||
2139 | rewrite (mapM_interp_le Hinterp2) /=; last lia. done. | ||
2140 | + do 2 right. exists (S m). | ||
2141 | rewrite /interp' /force_deep' in Hinterp. | ||
2142 | destruct (interp m _ _) as [mw|] eqn:Hinterp1'; simplify_res. | ||
2143 | rewrite interp_thunk_S /= Hinterp1' /=. | ||
2144 | destruct mw as [w|]; simplify_res; [|done]. | ||
2145 | rewrite (force_deep_le Hinterp) /=; last lia. done. | ||
2146 | - (* EAttr *) destruct (decide (no_recs αs)) as [Hrecs|]; last first. | ||
2147 | { left. by repeat econstructor. } | ||
2148 | destruct μ'. | ||
2149 | { right; left. by constructor. } | ||
2150 | assert (red (step DEEP) (EAttr αs) ∨ | ||
2151 | map_Forall (λ _, final DEEP ∘ attr_expr) αs ∨ | ||
2152 | ∃ m, map_mapM_sorted attr_le (mbind (force_deep m) ∘ interp_thunk m) | ||
2153 | (Thunk ∅ ∘ attr_expr <$> αs) = mfail) as Hhelp; last first. | ||
2154 | { destruct Hhelp as [?|[?|[m Hinterp]]]; [by auto using final..|]. | ||
2155 | do 2 right. exists (S m). rewrite /interp' interp_S /=. | ||
2156 | rewrite from_attr_no_recs //. rewrite force_deep_S /=. by rewrite Hinterp. } | ||
2157 | induction αs as [|x [τ e] es Hx ? IH] | ||
2158 | using (map_sorted_ind attr_le); [by right; left|]. | ||
2159 | rewrite !map_Forall_insert //. | ||
2160 | apply map_Forall_insert in H as [He Hes%IH]; clear IH; | ||
2161 | [|by eauto using no_recs_insert_inv..]. | ||
2162 | assert (τ = NONREC) as -> by (by eapply no_recs_lookup, lookup_insert). | ||
2163 | assert (∀ y, is_Some ((Thunk ∅ ∘ attr_expr <$> es) !! y) → attr_le x y). | ||
2164 | { intros y. rewrite lookup_fmap fmap_is_Some. eauto. } | ||
2165 | destruct (He DEEP) as [[??]|[Hfinal|[m Hinterp]]]; simplify_eq/=. | ||
2166 | + left. eexists; eapply SAttr; naive_solver eauto using no_recs_insert_inv. | ||
2167 | + destruct Hes as [[??]|[?|[m2 Hinterp2]]]; [|by eauto|]. | ||
2168 | * left. inv_step; first by naive_solver eauto using no_recs_insert_inv. | ||
2169 | apply lookup_insert_None in Hx as [??]. | ||
2170 | rewrite insert_commute // in Hrecs. rewrite insert_commute //. | ||
2171 | eexists; eapply SAttr; [|by rewrite lookup_insert_ne| |done]. | ||
2172 | { eapply no_recs_insert_inv; [|done]. by rewrite lookup_insert_ne. } | ||
2173 | intros ?? [[<- <-]|[??]]%lookup_insert_Some; eauto. | ||
2174 | * apply final_interp' in Hfinal as (w & m1 & Hinterp1 & _). | ||
2175 | do 2 right. exists (S (m1 `max` m2)). rewrite fmap_insert /=. | ||
2176 | rewrite map_mapM_sorted_insert //=; last by rewrite lookup_fmap Hx. | ||
2177 | rewrite /interp' /force_deep' in Hinterp1. | ||
2178 | destruct (interp m1 _ _) as [[]|] eqn:Hinterp1'; simplify_res. | ||
2179 | rewrite interp_thunk_S /= (interp_le Hinterp1') /=; last lia. | ||
2180 | rewrite (force_deep_le Hinterp1) /=; last lia. | ||
2181 | rewrite (map_mapM_interp_le Hinterp2) /=; last lia. done. | ||
2182 | + do 2 right. exists (S m). rewrite fmap_insert /=. | ||
2183 | rewrite map_mapM_sorted_insert //=; last by rewrite lookup_fmap Hx. | ||
2184 | rewrite /interp' /force_deep' in Hinterp. | ||
2185 | destruct (interp m _ _) as [mw|] eqn:Hinterp'; simplify_res. | ||
2186 | rewrite interp_thunk_S /= (interp_le Hinterp') /=; last lia. | ||
2187 | destruct mw as [w|]; simplify_res; [|done]. | ||
2188 | rewrite (force_deep_le Hinterp) /=; last lia. done. | ||
2189 | - (* ELetAttr *) destruct (IHe1 SHALLOW) as [[??]|[Hfinal|[m Hinterp]]]. | ||
2190 | + left. eexists. by eapply SLetAttr. | ||
2191 | + apply final_interp in Hfinal as (w & m & Hinterp & ->). | ||
2192 | destruct (maybe VAttr w) eqn:Hw. | ||
2193 | { destruct w; simplify_eq/=. left. by repeat econstructor. } | ||
2194 | do 2 right. exists (S m). by rewrite /interp' interp_S /= Hinterp /= Hw. | ||
2195 | + do 2 right. exists (S m). rewrite interp_shallow' in Hinterp. | ||
2196 | by rewrite /interp' interp_S /= Hinterp /=. | ||
2197 | - (* EBinOp *) | ||
2198 | destruct (IHe1 SHALLOW) as [[??]|[Hfinal1|[m Hinterp]]]. | ||
2199 | + left. eexists. by eapply SBinOpL. | ||
2200 | + apply final_interp in Hfinal1 as (w1 & m1 & Hinterp1 & ->). | ||
2201 | destruct (interp_bin_op op w1) as [f|] eqn:Hop; last first. | ||
2202 | { do 2 right. exists (S m1). rewrite /interp' interp_S /=. | ||
2203 | by rewrite Hinterp1 /= Hop. } | ||
2204 | pose proof Hop as [Φ ?]%interp_bin_op_Some_1. | ||
2205 | destruct (IHe2 SHALLOW) as [[??]|[Hfinal2|[m Hinterp2]]]. | ||
2206 | * left. by repeat econstructor. | ||
2207 | * apply final_interp in Hfinal2 as (w2 & m2 & Hinterp2 & ->). | ||
2208 | destruct (f w2) as [w|] eqn:Hf; last first. | ||
2209 | ** do 2 right. exists (S (m1 `max` m2)). rewrite /interp' interp_S /=. | ||
2210 | rewrite (interp_le Hinterp1) /=; last lia. | ||
2211 | rewrite Hop /= (interp_le Hinterp2) /=; last lia. by rewrite Hf. | ||
2212 | ** eapply interp_bin_op_Some_Some_1 in Hf as (?&?&?); [|done..]. | ||
2213 | left. by repeat econstructor. | ||
2214 | * rewrite interp_shallow' in Hinterp2. | ||
2215 | do 2 right. exists (S (m `max` m1)). rewrite /interp' interp_S /=. | ||
2216 | rewrite (interp_le Hinterp1) /=; last lia. | ||
2217 | rewrite Hop /= (interp_le Hinterp2) /=; last lia. done. | ||
2218 | + rewrite interp_shallow' in Hinterp. | ||
2219 | do 2 right. exists (S m). by rewrite /interp' interp_S /= Hinterp. | ||
2220 | - (* EIf *) | ||
2221 | destruct (IHe1 SHALLOW) as [[??]|[Hfinal1|[m Hinterp]]]. | ||
2222 | + left. eexists. by eapply SIf. | ||
2223 | + apply final_interp in Hfinal1 as (w1 & m1 & Hinterp1 & ->). | ||
2224 | destruct (maybe_VLit w1 ≫= maybe LitBool) as [b|] eqn:Hbool; last first. | ||
2225 | { do 2 right. exists (S m1). | ||
2226 | rewrite /interp' interp_S /= Hinterp1 /= Hbool. done. } | ||
2227 | left. destruct w1; repeat destruct select base_lit; simplify_eq/=. | ||
2228 | eexists; constructor. | ||
2229 | + rewrite interp_shallow' in Hinterp. | ||
2230 | do 2 right. exists (S m). by rewrite /interp' interp_S /= Hinterp. | ||
2231 | Qed. | ||
2232 | |||
2233 | Lemma interp_complete μ e1 e2 : | ||
2234 | e1 -{μ}->* e2 → nf (step μ) e2 → | ||
2235 | ∃ mw m, interp' m μ ∅ e1 = Res mw ∧ | ||
2236 | if mw is Some w then e2 = val_to_expr w else ¬final μ e2. | ||
2237 | Proof. | ||
2238 | intros Hsteps Hnf. induction Hsteps as [e|e1 e2 e3 Hstep _ IH]. | ||
2239 | { destruct (red_final_interp μ e) as [?|[Hfinal|[m Hinterp]]]; [done|..]. | ||
2240 | - apply final_interp' in Hfinal as (w & m & ? & ?). | ||
2241 | by exists (Some w), m. | ||
2242 | - exists None, m. split; [done|]. intros Hfinal. | ||
2243 | apply final_interp' in Hfinal as (w & m' & Hinterp' & _). | ||
2244 | rewrite /interp' in Hinterp, Hinterp'. | ||
2245 | by assert (mfail = mret w) by eauto using interp_agree'. } | ||
2246 | destruct IH as (mw & m & Hinterp & ?); first done. | ||
2247 | eapply interp_step' in Hstep as (mw' & m' & ? & ?); last done. | ||
2248 | destruct mw, mw'; naive_solver. | ||
2249 | Qed. | ||
2250 | |||
2251 | Lemma interp_complete_ret μ e1 e2 : | ||
2252 | e1 -{μ}->* e2 → final μ e2 → | ||
2253 | ∃ w m, interp' m μ ∅ e1 = mret w ∧ e2 = val_to_expr w. | ||
2254 | Proof. | ||
2255 | intros Hsteps Hfinal. apply interp_complete in Hsteps | ||
2256 | as ([w|] & m & ? & ?); naive_solver eauto using final_nf. | ||
2257 | Qed. | ||
2258 | Lemma interp_complete_fail μ e1 e2 : | ||
2259 | e1 -{μ}->* e2 → nf (step μ) e2 → ¬final μ e2 → | ||
2260 | ∃ m, interp' m μ ∅ e1 = mfail. | ||
2261 | Proof. | ||
2262 | intros Hsteps Hnf Hfinal. | ||
2263 | apply interp_complete in Hsteps as ([w|] & m & ? & ?); | ||
2264 | naive_solver eauto using final_val_to_expr'. | ||
2265 | Qed. | ||
2266 | |||
2267 | Lemma interp_sound_open n E e mv : | ||
2268 | interp n E e = Res mv → | ||
2269 | ∃ e', subst_env E e -{SHALLOW}->* e' ∧ | ||
2270 | if mv is Some v' then e' = val_to_expr v' else stuck SHALLOW e' | ||
2271 | with interp_thunk_sound n t mv : | ||
2272 | interp_thunk n t = Res mv → | ||
2273 | ∃ e', thunk_to_expr t -{SHALLOW}->* e' ∧ | ||
2274 | if mv is Some v' then e' = val_to_expr v' else stuck SHALLOW e' | ||
2275 | with interp_app_sound n v1 t2 mv : | ||
2276 | interp_app n v1 t2 = Res mv → | ||
2277 | ∃ e', EApp (val_to_expr v1) (thunk_to_expr t2) -{SHALLOW}->* e' ∧ | ||
2278 | if mv is Some v' then e' = val_to_expr v' else stuck SHALLOW e' | ||
2279 | with force_deep_sound n v mv : | ||
2280 | force_deep n v = Res mv → | ||
2281 | ∃ e', val_to_expr v -{DEEP}->* e' ∧ | ||
2282 | if mv is Some v' then e' = val_to_expr v' else stuck DEEP e'. | ||
2283 | Proof. | ||
2284 | - destruct n as [|n]; [done|]. | ||
2285 | rewrite subst_env_eq interp_S. intros Hinterp. | ||
2286 | destruct e; simplify_res. | ||
2287 | + (* ELit *) case_guard; simplify_res. | ||
2288 | * by eexists. | ||
2289 | * eexists; split; [done|]. split; [|by inv 1]. intros [??]; inv_step. | ||
2290 | + (* EId *) | ||
2291 | assert (union_kinded (prod_map id thunk_to_expr <$> E !! x) mke | ||
2292 | = prod_map id thunk_to_expr <$> (union_kinded (E !! x) | ||
2293 | (prod_map id (Thunk ∅) <$> mke))) as ->. | ||
2294 | { destruct (_ !! _) as [[[]]|], mke as [[[]]|]; | ||
2295 | by rewrite /= ?thunk_to_expr_eq /= ?subst_env_empty. } | ||
2296 | destruct (union_kinded _ _) as [[k t]|]; simplify_res. | ||
2297 | * apply interp_thunk_sound in Hinterp as (e' & Hsteps & He'). | ||
2298 | exists e'; split; [|done]. eapply rtc_l; [constructor|done]. | ||
2299 | * eexists; split; [done|]. split; [|inv 1]. intros [? Hstep]. inv_step. | ||
2300 | + (* EAbs *) by eexists. | ||
2301 | + (* EAbsMatch *) by eexists. | ||
2302 | + (* EApp *) | ||
2303 | destruct (interp _ _ _) as [mv1|] eqn:Hinterp1; simplify_res. | ||
2304 | apply interp_sound_open in Hinterp1 as (e1' & Hsteps1 & He1'). | ||
2305 | destruct mv1 as [v1|]; simplify_res; last first. | ||
2306 | { eexists; split; [by eapply SAppL_rtc|]. split; [|inv 1]. | ||
2307 | intros [??]. destruct He1' as [Hnf []]. | ||
2308 | inv_step; eauto using final. destruct Hnf; eauto. } | ||
2309 | apply interp_app_sound in Hinterp as (e' & Hsteps2 & He'). | ||
2310 | eexists e'; split; [|done]. etrans; [|done]. by eapply SAppL_rtc. | ||
2311 | + (* ESeq *) destruct (interp _ _ e1) as [mv'|] eqn:Hinterp'; simplify_res. | ||
2312 | apply interp_sound_open in Hinterp' as (e' & Hsteps & He'). | ||
2313 | destruct mv' as [v'|]; simplify_res; last first. | ||
2314 | { eexists; repeat split; [by apply SSeq_rtc, steps_shallow_any| |inv 1]. | ||
2315 | intros [e'' Hstep]. destruct He' as [Hnf Hfinal]. | ||
2316 | destruct Hfinal. inv_step; eauto using final_any_shallow. | ||
2317 | apply step_any_shallow in H2 as []; [|done]. destruct Hnf; eauto. } | ||
2318 | destruct μ; simplify_res. | ||
2319 | { apply interp_sound_open in Hinterp as (e'' & Hsteps' & He''). | ||
2320 | eexists; split; [|done]. etrans; first by apply SSeq_rtc. | ||
2321 | eapply rtc_l; first by apply SSeqFinal. done. } | ||
2322 | destruct (force_deep _ _) as [mw|] eqn:Hforce; simplify_res. | ||
2323 | pose proof Hforce as Hforce'. | ||
2324 | apply force_deep_sound in Hforce' as (e'' & Hsteps' & He''). | ||
2325 | destruct mw as [w|]; simplify_res; last first. | ||
2326 | { eexists. split. | ||
2327 | { etrans; [by eapply SSeq_rtc, steps_shallow_any|]. | ||
2328 | etrans; [by eapply SSeq_rtc|]. done. } | ||
2329 | split; [|inv 1]. destruct He''. intros [e''' Hstep]. | ||
2330 | inv_step; eauto using step_not_final. } | ||
2331 | apply interp_sound_open in Hinterp as (e''' & Hsteps'' & He'''). | ||
2332 | exists e'''. split; [|done]. | ||
2333 | etrans; [by eapply SSeq_rtc, steps_shallow_any|]. | ||
2334 | etrans; [by eapply SSeq_rtc|]. | ||
2335 | eapply rtc_l; first by eapply SSeqFinal, final_force_deep. done. | ||
2336 | + (* EList *) | ||
2337 | eexists; split; [done|]. f_equal. | ||
2338 | induction es; f_equal/=; auto. | ||
2339 | + (* EAttr *) | ||
2340 | eexists; split; [apply SAttr_rec_rtc|]. | ||
2341 | f_equal. apply map_eq=> x. rewrite !lookup_fmap. | ||
2342 | destruct (αs !! x) as [[[] e]|] eqn:?; do 2 f_equal/=. | ||
2343 | by rewrite subst_env_indirects_env_attr_to_tattr. | ||
2344 | + (* ELetAttr *) destruct (interp _ _ _) as [mv'|] eqn:Hinterp'; simplify_res. | ||
2345 | apply interp_sound_open in Hinterp' as (e' & Hsteps & He'). | ||
2346 | destruct mv' as [v'|]; simplify_res; last first. | ||
2347 | { eexists; repeat split; [by apply SLetAttr_rtc| |inv 1]. | ||
2348 | intros [e'' Hstep]. destruct He' as [Hnf Hfinal]. | ||
2349 | inv_step; [by destruct Hfinal; constructor|]. destruct Hnf; eauto. } | ||
2350 | destruct (maybe VAttr v') eqn:?; simplify_res; last first. | ||
2351 | { eexists; repeat split; [by apply SLetAttr_rtc| |inv 1]. | ||
2352 | intros [e'' Hstep]. destruct v'; inv_step; simplify_eq/=. } | ||
2353 | destruct v'; simplify_res. | ||
2354 | apply interp_sound_open in Hinterp as (e'' & Hsteps' & He''). | ||
2355 | eexists; split; [|done]. etrans; [by apply SLetAttr_rtc|]. | ||
2356 | eapply rtc_l; [by econstructor|]. | ||
2357 | rewrite subst_env_union in Hsteps'. | ||
2358 | rewrite subst_env_alt -!map_fmap_compose in Hsteps'. | ||
2359 | by rewrite -map_fmap_compose. | ||
2360 | + (* EBinOp *) | ||
2361 | destruct (interp _ _ e1) as [mv1|] eqn:Hinterp1; simplify_res. | ||
2362 | apply interp_sound_open in Hinterp1 as (e1' & Hsteps1 & He1'). | ||
2363 | destruct mv1 as [v1|]; simplify_res; last first. | ||
2364 | { eexists; split; [by eapply SBinOpL_rtc|]. split; [|inv 1]. | ||
2365 | intros [? Hstep]. destruct He1'. inv_step; naive_solver. } | ||
2366 | destruct (interp_bin_op _ v1) as [f|] eqn:Hop; simplify_res; last first. | ||
2367 | { assert (¬∃ Φ, sem_bin_op op (val_to_expr v1) Φ). | ||
2368 | { by intros [? ?%interp_bin_op_Some_2%not_eq_None_Some]. } | ||
2369 | eexists; split; [by eapply SBinOpL_rtc|]. split; [|inv 1]. | ||
2370 | intros [? Hstep]. inv_step; eauto using step_not_val_to_expr. } | ||
2371 | pose proof Hop as [Φ ?]%interp_bin_op_Some_1. | ||
2372 | destruct (interp _ _ e2) as [mv2|] eqn:Hinterp2; simplify_res. | ||
2373 | apply interp_sound_open in Hinterp2 as (e2' & Hsteps2 & He2'). | ||
2374 | destruct mv2 as [v2|]; simplify_res; last first. | ||
2375 | { eexists; split. | ||
2376 | { etrans; [by eapply SBinOpL_rtc|]. | ||
2377 | eapply SBinOpR_rtc; eauto using interp_bin_op_Some_1. } | ||
2378 | split; [|inv 1]. destruct He2'. | ||
2379 | intros [? Hstep]. inv_step; eauto using step_not_val_to_expr. } | ||
2380 | destruct (f v2) eqn:Hf; simplify_res; last first. | ||
2381 | { eexists; split. | ||
2382 | { etrans; [by eapply SBinOpL_rtc|]. | ||
2383 | eapply SBinOpR_rtc; eauto using interp_bin_op_Some_1. } | ||
2384 | split; [|inv 1]. pose proof @interp_bin_op_Some_Some_2. | ||
2385 | intros [? Hstep]. inv_step; naive_solver eauto using step_not_val_to_expr. } | ||
2386 | apply interp_thunk_sound in Hinterp as (e' & Hsteps3 & He'). | ||
2387 | eapply interp_bin_op_Some_Some_1 in Hf as (e3 & ? & ?); [|done..]. | ||
2388 | eapply delayed_steps_l in Hsteps3 | ||
2389 | as (e'' & Hsteps3 & Hdel); last done. | ||
2390 | eexists e''; split. | ||
2391 | { etrans; [by eapply SBinOpL_rtc|]. | ||
2392 | etrans; [eapply SBinOpR_rtc; eauto using interp_bin_op_Some_1|]. | ||
2393 | eapply rtc_l; [by econstructor|]. done. } | ||
2394 | destruct mv. | ||
2395 | { subst e'. eapply delayed_final_l in Hdel as <-; done. } | ||
2396 | destruct He' as [Hnf Hfinal]. split. | ||
2397 | { intros [e4 Hsteps4]. destruct Hnf. | ||
2398 | eapply delayed_step_r in Hsteps4 as (e4' & Hstep4' & ?); [|done]. | ||
2399 | destruct Hstep4'; eauto. } | ||
2400 | intros Hfinal'. eapply Hnf. | ||
2401 | eapply delayed_final_r in Hfinal' as Hsteps; [|done]. | ||
2402 | destruct Hsteps; by eauto. | ||
2403 | + (* EIf *) | ||
2404 | destruct (interp _ _ e1) as [mv1|] eqn:Hinterp1; simplify_res. | ||
2405 | apply interp_sound_open in Hinterp1 as (e1' & Hsteps1 & He1'). | ||
2406 | destruct mv1 as [v1|]; simplify_res; last first. | ||
2407 | { eexists; repeat split; [by apply SIf_rtc| |inv 1]. | ||
2408 | intros [e'' Hstep]. destruct He1' as [Hnf Hfinal]. | ||
2409 | destruct Hfinal. inv_step; eauto using final. destruct Hnf; eauto. } | ||
2410 | destruct (maybe_VLit v1 ≫= maybe LitBool) as [b|] eqn:Hbool; | ||
2411 | simplify_res; last first. | ||
2412 | { eexists; repeat split; [by apply SIf_rtc| |inv 1]. | ||
2413 | intros [e'' ?]. destruct v1; inv_step; eauto using final. } | ||
2414 | apply interp_sound_open in Hinterp as (e' & Hsteps & He'). | ||
2415 | exists e'; split; [|done]. etrans; [by apply SIf_rtc|]. | ||
2416 | assert (val_to_expr v1 = ELit (LitBool b)) as ->. | ||
2417 | { destruct v1; repeat destruct select base_lit; naive_solver. } | ||
2418 | eapply rtc_l; [constructor|]. by destruct b. | ||
2419 | - destruct n as [|n]; [done|]. rewrite interp_thunk_S /=. | ||
2420 | intros Hthunk. destruct t; simplify_res; [by eauto using rtc..|]. | ||
2421 | destruct (tαs !! x) as [[e|t]|] eqn:Hx; simplify_res. | ||
2422 | + apply interp_sound_open in Hthunk as (e' & Hsteps & ?). | ||
2423 | exists e'; split; [|done]. etrans; [eapply SBinOpL_rtc, SAttr_rec_rtc|]. | ||
2424 | eapply rtc_l; [eapply SBinOp; repeat constructor|]; try done; simpl. | ||
2425 | eexists; split; [done|]. rewrite !lookup_fmap Hx /=. | ||
2426 | rewrite -subst_env_indirects_env_attr_to_tattr_empty. | ||
2427 | by rewrite -subst_env_indirects_env. | ||
2428 | + apply interp_thunk_sound in Hthunk as (e' & Hsteps & ?). | ||
2429 | exists e'; split; [|done]. etrans; [eapply SBinOpL_rtc, SAttr_rec_rtc|]. | ||
2430 | eapply rtc_l; [eapply SBinOp; repeat constructor|]; try done; simpl. | ||
2431 | eexists; split; [done|]. by rewrite !lookup_fmap Hx /=. | ||
2432 | + eexists. split; [eapply SBinOpL_rtc, SAttr_rec_rtc|]. split; [|inv 1]. | ||
2433 | intros [??]. inv_step. inv H7. destruct H8 as (? & ? & Hx'); simplify_eq/=. | ||
2434 | by rewrite !lookup_fmap Hx in Hx'. | ||
2435 | - destruct n as [|n]; [done|]. rewrite interp_app_S /=. intros Happ. | ||
2436 | destruct v1; simplify_res. | ||
2437 | + eexists; split; [done|]. split; [|inv 1]. intros [??]; inv_step. | ||
2438 | + eapply interp_sound_open in Happ as (e' & Hsteps & He'). | ||
2439 | eexists; split; [|done]. eapply rtc_l; [constructor|]. | ||
2440 | rewrite subst_abs_env_insert // in Hsteps. | ||
2441 | + destruct (interp_thunk _ _) as [mv'|] eqn:Hthunk; simplify_res. | ||
2442 | apply interp_thunk_sound in Hthunk as (et & Htsteps & Het). | ||
2443 | destruct mv' as [v'|]; simplify_res; last first. | ||
2444 | { eexists; split; [by eapply SAppR_rtc|]. | ||
2445 | split; [|inv 1]. destruct Het. | ||
2446 | intros [??]; inv_step; eauto using final. } | ||
2447 | destruct (maybe VAttr v') as [ts|] eqn:?; simplify_res; last first. | ||
2448 | { eexists; repeat split; [by apply SAppR_rtc| |inv 1]. | ||
2449 | intros [e'' Hstep]. destruct v'; inv_step; simplify_eq/=. } | ||
2450 | destruct v'; simplify_res. | ||
2451 | destruct (interp_match _ _ _) as [tαs|] eqn:Hmatch; | ||
2452 | simplify_res; last first. | ||
2453 | { eexists; repeat split; [by apply SAppR_rtc| |inv 1]. | ||
2454 | intros [e'' Hstep]. inv_step. | ||
2455 | rewrite map_fmap_compose fmap_attr_expr_Attr in H6. | ||
2456 | apply interp_match_Some_2 in H6. rewrite interp_match_subst in H6. | ||
2457 | opose proof (interp_match_proper ∅ ∅ | ||
2458 | (Thunk ∅ <$> (thunk_to_expr <$> ts)) ts ms ms strict _ _). | ||
2459 | { apply map_eq=> x. rewrite !lookup_fmap. | ||
2460 | destruct (ts !! x); f_equal/=. by rewrite subst_env_empty. } | ||
2461 | { done. } | ||
2462 | repeat destruct (interp_match _ _ _); simplify_eq/=. } | ||
2463 | pose proof (interp_match_subst E ts ms strict) as Hmatch'. | ||
2464 | rewrite Hmatch /= in Hmatch'. | ||
2465 | apply interp_match_Some_1 in Hmatch'. | ||
2466 | apply interp_sound_open in Happ as (e' & Hsteps & ?). | ||
2467 | exists e'; split; [|done]. | ||
2468 | etrans; [by apply SAppR_rtc|]. | ||
2469 | eapply rtc_l; [constructor; [done|]|]. | ||
2470 | { rewrite map_fmap_compose fmap_attr_expr_Attr. done. } | ||
2471 | etrans; [|apply Hsteps]. apply reflexive_eq. f_equal. | ||
2472 | rewrite subst_env_indirects_env. | ||
2473 | rewrite subst_env_indirects_env_attr_to_tattr_empty. | ||
2474 | do 2 f_equal. apply map_eq=> y. rewrite !lookup_fmap. | ||
2475 | destruct (_ !! y) as [[]|]; f_equal/=. by rewrite subst_env_empty. | ||
2476 | + eexists; split; [done|]. split; [|inv 1]. intros [??]; inv_step. | ||
2477 | + destruct (ts !! _) eqn:Hfunc; simplify_res; last first. | ||
2478 | { eexists; split; [by eapply SAppL_rtc|]. split; [|inv 1]. | ||
2479 | intros [??]; inv_step; simplify_map_eq. } | ||
2480 | destruct (interp_thunk _ _) as [mv'|] eqn:Hthunk; simplify_res. | ||
2481 | apply interp_thunk_sound in Hthunk as (et & Htsteps & Het). | ||
2482 | assert (EApp (EAttr (AttrN ∘ thunk_to_expr <$> ts)) (thunk_to_expr t2) | ||
2483 | -{SHALLOW}->* | ||
2484 | EApp (EApp et (EAttr (AttrN ∘ thunk_to_expr <$> ts))) (thunk_to_expr t2)) | ||
2485 | as Hsteps; [|clear Htsteps]. | ||
2486 | { eapply rtc_l; [constructor; by simplify_map_eq|]. | ||
2487 | eapply SAppL_rtc, SAppL_rtc, Htsteps. } | ||
2488 | destruct mv' as [v'|]; simplify_res; last first. | ||
2489 | { eexists; split; [exact Hsteps|]. | ||
2490 | split; [|inv 1]. intros [??]. destruct Het as [Hnf []]. | ||
2491 | inv_step; eauto using final. destruct Hnf; eauto. } | ||
2492 | destruct (interp_app _ _ _) as [mv'|] eqn:Happ'; simplify_res. | ||
2493 | apply interp_app_sound in Happ' as (e' & Hsteps' & He'). | ||
2494 | destruct mv' as [v''|]; simplify_res; last first. | ||
2495 | { eexists; split; [etrans; [apply Hsteps|apply SAppL_rtc, Hsteps']|]. | ||
2496 | split; [|inv 1]. intros [??]. destruct He' as [Hnf []]. | ||
2497 | inv_step; eauto using final. destruct Hnf; eauto. } | ||
2498 | apply interp_app_sound in Happ as (e'' & Hsteps'' & He''). | ||
2499 | eexists e''; split; [|done]. | ||
2500 | etrans; [apply Hsteps|]. etrans; [apply SAppL_rtc, Hsteps'|]. done. | ||
2501 | - destruct n as [|n]; [done|]. rewrite force_deep_S. | ||
2502 | intros Hforce. destruct v; simplify_res. | ||
2503 | + (* VLit *) by eexists. | ||
2504 | + (* VAbs *) by eexists. | ||
2505 | + (* VAbsMatch *) by eexists. | ||
2506 | + (* VList *) | ||
2507 | destruct (mapM _ _) as [mvs|] eqn:Hmap; simplify_res. | ||
2508 | assert (∃ ts', | ||
2509 | EList (thunk_to_expr <$> ts) -{DEEP}->* EList (thunk_to_expr <$> ts') ∧ | ||
2510 | if mvs is Some vs then thunk_to_expr <$> ts' = val_to_expr <$> vs | ||
2511 | else nf (step DEEP) (EList (thunk_to_expr <$> ts')) ∧ | ||
2512 | ¬Forall (final DEEP ∘ thunk_to_expr) ts') | ||
2513 | as (ts' & Hsteps & Hts'); last first. | ||
2514 | { eexists; split; [done|]. destruct mvs as [vs|]; simplify_eq/=. | ||
2515 | * f_equal. rewrite -list_fmap_compose Hts'. | ||
2516 | clear. induction vs; f_equal/=; auto. | ||
2517 | * destruct Hts' as [Hnf Hfinal]; split; [done|]. | ||
2518 | inv 1. by apply Hfinal, Forall_fmap. } | ||
2519 | revert mvs Hmap. induction ts as [|t ts IH]; intros mv' Hmap; simplify_res. | ||
2520 | { by exists []. } | ||
2521 | destruct (interp_thunk _ _) as [mv''|] eqn:Hthunk; simplify_res. | ||
2522 | apply interp_thunk_sound in Hthunk as (et & Htsteps & Het). | ||
2523 | destruct mv'' as [v''|]; simplify_res; last first. | ||
2524 | { exists (Thunk ∅ et :: ts); csimpl. rewrite subst_env_empty. | ||
2525 | apply (stuck_shallow_any DEEP) in Het as [??]. split_and!. | ||
2526 | * eapply (SList_rtc []); [done|]. | ||
2527 | etrans; [by apply steps_shallow_any|done]. | ||
2528 | * by apply List_nf_cons. | ||
2529 | * rewrite Forall_cons /= subst_env_empty. | ||
2530 | naive_solver eauto using final_any_shallow. } | ||
2531 | destruct (force_deep _ _) as [mvf|] eqn:Hforce; simplify_res. | ||
2532 | pose proof Hforce as Hforce'. | ||
2533 | apply force_deep_sound in Hforce' as (e' & Hsteps' & He'). | ||
2534 | destruct mvf as [vf|]; simplify_res; last first. | ||
2535 | { exists (Thunk ∅ e' :: ts). csimpl. rewrite subst_env_empty. | ||
2536 | destruct He'. split_and!. | ||
2537 | * eapply (SList_rtc []); [done|]. | ||
2538 | etrans; [by apply steps_shallow_any|done]. | ||
2539 | * by apply List_nf_cons. | ||
2540 | * rewrite Forall_cons /= subst_env_empty. naive_solver. } | ||
2541 | destruct (mapM _ _) as [mvs|] eqn:Hmap'; simplify_res. | ||
2542 | destruct (IH _ eq_refl) as (ts' & Hsteps'' & Hts'). | ||
2543 | exists (Forced vf :: ts'); csimpl. split. | ||
2544 | { etrans; [eapply (SList_rtc []); [done..|]; | ||
2545 | etrans; [by apply steps_shallow_any|done]|]; simpl. | ||
2546 | eapply List_steps_cons; by eauto using final_force_deep. } | ||
2547 | destruct mvs as [vs|]; simplify_res. | ||
2548 | { by rewrite Hts'. } | ||
2549 | split; [|rewrite Forall_cons; naive_solver]. | ||
2550 | apply List_nf_cons_final; naive_solver eauto using final_force_deep. | ||
2551 | + (* VAttr *) | ||
2552 | destruct (map_mapM_sorted _ _) as [mvs|] eqn:Hmap; simplify_res. | ||
2553 | assert (∃ ts', | ||
2554 | EAttr (AttrN ∘ thunk_to_expr <$> ts) -{DEEP}->* | ||
2555 | EAttr (AttrN ∘ thunk_to_expr <$> ts') ∧ | ||
2556 | if mvs is Some vs then thunk_to_expr <$> ts' = val_to_expr <$> vs | ||
2557 | else nf (step DEEP) (EAttr (AttrN ∘ thunk_to_expr <$> ts')) ∧ | ||
2558 | ¬map_Forall (λ _, final DEEP ∘ thunk_to_expr) ts') | ||
2559 | as (ts' & Hsteps & Hts'); last first. | ||
2560 | { eexists; split; [done|]. destruct mvs as [vs|]; simplify_eq/=. | ||
2561 | * f_equal. rewrite map_fmap_compose Hts'. | ||
2562 | apply map_eq=> x. rewrite !lookup_fmap. by destruct (vs !! x). | ||
2563 | * destruct Hts' as [Hnf Hfinal]; split; [done|]. | ||
2564 | inv 1. apply Hfinal=> x t Hx /=. | ||
2565 | ospecialize (H2 x _ _); first by rewrite lookup_fmap Hx. done. } | ||
2566 | revert mvs Hmap. induction ts as [|x t ts Hx ? IH] | ||
2567 | using (map_sorted_ind attr_le); intros mv' Hmap. | ||
2568 | { rewrite map_mapM_sorted_empty in Hmap; simplify_res. by exists ∅. } | ||
2569 | rewrite map_mapM_sorted_insert //= in Hmap. | ||
2570 | assert ((AttrN ∘ thunk_to_expr <$> ts) !! x = None). | ||
2571 | { by rewrite lookup_fmap Hx. } | ||
2572 | assert (∀ y α, (AttrN ∘ thunk_to_expr <$> ts) !! y = Some α → | ||
2573 | final DEEP (attr_expr α) ∨ attr_le x y). | ||
2574 | { intros y α. rewrite lookup_fmap. destruct (ts !! y) eqn:?; naive_solver. } | ||
2575 | destruct (interp_thunk _ _) as [mv''|] eqn:Hthunk; simplify_res. | ||
2576 | apply interp_thunk_sound in Hthunk as (et & Htsteps & Het). | ||
2577 | destruct mv'' as [v''|]; simplify_res; last first. | ||
2578 | { exists (<[x:=Thunk ∅ et]> ts). | ||
2579 | rewrite !fmap_insert /= subst_env_empty. | ||
2580 | apply (stuck_shallow_any DEEP) in Het as [??]. split_and!. | ||
2581 | * eapply SAttr_lookup_rtc; [done..|]. | ||
2582 | etrans; [by apply steps_shallow_any|done]. | ||
2583 | * apply Attr_nf_insert; auto. | ||
2584 | intros y. rewrite lookup_fmap fmap_is_Some. eauto. | ||
2585 | * rewrite map_Forall_insert //= subst_env_empty. | ||
2586 | naive_solver eauto using final_any_shallow. } | ||
2587 | destruct (force_deep _ _) as [mvf|] eqn:Hforce; simplify_res. | ||
2588 | pose proof Hforce as Hforce'. | ||
2589 | apply force_deep_sound in Hforce' as (e' & Hsteps' & He'). | ||
2590 | destruct mvf as [vf|]; simplify_res; last first. | ||
2591 | { exists (<[x:=Thunk ∅ e']> ts). rewrite !fmap_insert /= subst_env_empty. | ||
2592 | destruct He'. split_and!. | ||
2593 | * eapply SAttr_lookup_rtc; [done..|]. | ||
2594 | etrans; [by apply steps_shallow_any|done]. | ||
2595 | * apply Attr_nf_insert; auto. | ||
2596 | intros y. rewrite lookup_fmap fmap_is_Some. eauto. | ||
2597 | * rewrite map_Forall_insert //= subst_env_empty. naive_solver. } | ||
2598 | destruct (map_mapM_sorted _ _ _) as [mvs|] eqn:Hmap'; simplify_res. | ||
2599 | destruct (IH _ eq_refl) as (ts' & Hsteps'' & Hts'). | ||
2600 | exists (<[x:=Forced vf]> ts'). split. | ||
2601 | { rewrite !fmap_insert /=. | ||
2602 | etrans; [eapply SAttr_lookup_rtc; [done..|]; | ||
2603 | etrans; [by apply steps_shallow_any|done]|]. | ||
2604 | eapply Attr_steps_insert; by eauto using final_force_deep. } | ||
2605 | destruct mvs as [vs|]; simplify_res. | ||
2606 | { by rewrite !fmap_insert Hts'. } | ||
2607 | assert (∀ y, ts !! y = None ↔ ts' !! y = None) as Hdom. | ||
2608 | { intros y. rewrite -!(fmap_None (AttrN ∘ thunk_to_expr)). | ||
2609 | rewrite -!lookup_fmap. by eapply Attr_steps_dom. } | ||
2610 | split; [|rewrite map_Forall_insert; naive_solver]. | ||
2611 | rewrite fmap_insert /=. apply Attr_nf_insert_final; | ||
2612 | eauto using final_force_deep. | ||
2613 | * rewrite lookup_fmap fmap_None. naive_solver. | ||
2614 | * intros y. rewrite lookup_fmap fmap_is_Some. | ||
2615 | rewrite -not_eq_None_Some -Hdom not_eq_None_Some. auto. | ||
2616 | * naive_solver. | ||
2617 | Qed. | ||
2618 | |||
2619 | Lemma interp_sound_open' n μ E e mv : | ||
2620 | interp' n μ E e = Res mv → | ||
2621 | ∃ e', subst_env E e -{μ}->* e' ∧ | ||
2622 | if mv is Some v' then e' = val_to_expr v' else stuck μ e'. | ||
2623 | Proof. | ||
2624 | intros Hinterp. destruct μ. | ||
2625 | { rewrite interp_shallow' in Hinterp. by eapply interp_sound_open. } | ||
2626 | rewrite /interp' /= in Hinterp. | ||
2627 | destruct (interp n E e) as [mv'|] eqn:Hinterp'; simplify_res. | ||
2628 | apply interp_sound_open in Hinterp' as (e' & Hsteps & He'). | ||
2629 | destruct mv' as [v'|]; simplify_res; last first. | ||
2630 | { eauto using steps_shallow_any, stuck_shallow_any. } | ||
2631 | eapply force_deep_sound in Hinterp as (e'' & Hsteps' & He''). | ||
2632 | eexists; split; [|done]. etrans; [by eapply steps_shallow_any|done]. | ||
2633 | Qed. | ||
2634 | |||
2635 | Lemma interp_sound n μ e mv : | ||
2636 | interp' n μ ∅ e = Res mv → | ||
2637 | ∃ e', e -{μ}->* e' ∧ | ||
2638 | if mv is Some v then e' = val_to_expr v else stuck μ e'. | ||
2639 | Proof. | ||
2640 | intros Hsteps%interp_sound_open'. by rewrite subst_env_empty in Hsteps. | ||
2641 | Qed. | ||
2642 | |||
2643 | (** Final theorems *) | ||
2644 | Theorem interp_sound_complete_ret e v : | ||
2645 | (∃ w n, interp' n SHALLOW ∅ e = mret w ∧ val_to_expr v = val_to_expr w) | ||
2646 | ↔ e -{SHALLOW}->* val_to_expr v. | ||
2647 | Proof. | ||
2648 | split. | ||
2649 | - by intros (n & w & (e' & ? & ->)%interp_sound & ->). | ||
2650 | - intros Hsteps. apply interp_complete in Hsteps as ([] & ? & ? & ?); | ||
2651 | unfold nf, red; | ||
2652 | naive_solver eauto using final_val_to_expr, step_not_val_to_expr. | ||
2653 | Qed. | ||
2654 | |||
2655 | Theorem interp_sound_complete_ret_lit μ e bl (Hbl : base_lit_ok bl) : | ||
2656 | (∃ n, interp' n μ ∅ e = mret (VLit bl Hbl)) ↔ e -{μ}->* ELit bl. | ||
2657 | Proof. | ||
2658 | split. | ||
2659 | - intros [n (e' & ? & ->)%interp_sound]. done. | ||
2660 | - intros Hsteps. apply interp_complete_ret in Hsteps | ||
2661 | as ([] & n & ? & Hv); simplify_eq/=; last by constructor. | ||
2662 | exists n. by rewrite (proof_irrel Hbl Hbl0). | ||
2663 | Qed. | ||
2664 | |||
2665 | Theorem interp_sound_complete_fail μ e : | ||
2666 | (∃ n, interp' n μ ∅ e = mfail) ↔ ∃ e', e -{μ}->* e' ∧ stuck μ e'. | ||
2667 | Proof. | ||
2668 | split. | ||
2669 | - by intros [n ?%interp_sound]. | ||
2670 | - intros (e' & Hsteps & Hnf & Hfinal). by eapply interp_complete_fail. | ||
2671 | Qed. | ||
2672 | |||
2673 | Theorem interp_sound_complete_no_fuel μ e : | ||
2674 | (∀ n, interp' n μ ∅ e = NoFuel) ↔ all_loop (step μ) e. | ||
2675 | Proof. | ||
2676 | rewrite all_loop_alt. split. | ||
2677 | - intros Hnofuel e' Hsteps. | ||
2678 | destruct (red_final_interp μ e') as [|[|He']]; [done|..]. | ||
2679 | + apply interp_complete_ret in Hsteps as (w & m & Hinterp & _); last done. | ||
2680 | by rewrite Hnofuel in Hinterp. | ||
2681 | + apply interp_sound_complete_fail in He' as (e'' & ? & [Hnf _]). | ||
2682 | destruct (interp_complete μ e e'') | ||
2683 | as (mv & n & Hinterp & _); [by etrans|done|]. | ||
2684 | by rewrite Hnofuel in Hinterp. | ||
2685 | - intros Hred n. destruct (interp' n μ ∅ e) as [mv|] eqn:Hinterp; [|done]. | ||
2686 | destruct (interp_sound _ _ _ _ Hinterp) as (e' & Hsteps & Hstuck). | ||
2687 | destruct mv as [v|]; simplify_eq/=. | ||
2688 | + apply Hred in Hsteps as []%final_nf. by eapply final_val_to_expr'. | ||
2689 | + destruct Hstuck as [[] ?]; eauto. | ||
2690 | Qed. | ||