Require Import Coq.Strings.String. From stdpp Require Import base gmap relations tactics. From mininix Require Import binop expr interpreter maptools matching relations sem. Lemma strong_value_stuck sv : ¬ ∃ e, expr_from_strong_value sv --> e. Proof. intros []. destruct sv; inv H; inv H1; simplify_option_eq; (try inv H2); inv H. Qed. Lemma strong_value_stuck_rtc sv e: expr_from_strong_value sv -->* e → e = expr_from_strong_value sv. Proof. intros. inv H. - reflexivity. - exfalso. apply strong_value_stuck with (sv := sv). by exists y. Qed. Lemma force__strong_value (e : expr) (v : value) : X_Force e -->* v → ∃ sv, v = value_from_strong_value sv. Proof. intros [n Hsteps] % rtc_nsteps. revert e v Hsteps. induction n; intros e v Hsteps; inv Hsteps. inv H0. inv H2; simplify_eq/=. - inv H3. exists sv. apply rtc_nsteps_2 in H1. apply strong_value_stuck_rtc in H1. unfold expr_from_strong_value, compose in H1. congruence. - inv H0. destruct (IHn _ _ H1) as [sv Hsv]. by exists sv. Qed. Lemma forall2_force__strong_values es (vs : gmap string value) : map_Forall2 (λ e v', X_Force e -->* X_V v') es vs → ∃ svs, vs = value_from_strong_value <$> svs. Proof. revert vs. induction es using map_ind; intros vs HForall2. - apply map_Forall2_empty_l_L in HForall2. by exists ∅. - destruct (map_Forall2_destruct _ _ _ _ _ HForall2) as [v [m2' [Him2' Heqvs]]]. simplify_eq/=. apply map_Forall2_insert_inv_strict in HForall2 as [Hstep HForall2]; try done. apply IHes in HForall2 as [svs Hsvs]. simplify_eq/=. apply force__strong_value in Hstep as [sv Hsv]. simplify_eq/=. exists (<[i := sv]>svs). by rewrite fmap_insert. Qed. Lemma force_strong_value_forall2_impl es (svs : gmap string strong_value) : map_Forall2 (λ e v', X_Force e -->* X_V v') es (value_from_strong_value <$> svs) → map_Forall2 (λ e sv', X_Force e -->* expr_from_strong_value sv') es svs. Proof. apply map_Forall2_fmap_r_L. Qed. Lemma force_map_fmap_union_insert (sws : gmap string strong_value) es k e sv : X_Force e -->* expr_from_strong_value sv → X_Force (X_V (V_Attrset (<[k := e]>es ∪ (expr_from_strong_value <$> sws)))) -->* X_Force (X_V (V_Attrset (<[k := expr_from_strong_value sv]>es ∪ (expr_from_strong_value <$> sws)))). Proof. intros [n Hsteps] % rtc_nsteps. revert sws es k e Hsteps. induction n; intros sws es k e Hsteps. - inv Hsteps. - inv Hsteps. inv H0. inv H2. + inv H3. inv H1. * simplify_option_eq. unfold expr_from_strong_value, compose. by rewrite H4. * edestruct strong_value_stuck. exists y. done. + inv H0. simplify_option_eq. apply rtc_transitive with (y := X_Force (X_V (V_Attrset (<[k:=E2 e2]> es ∪ (expr_from_strong_value <$> sws))))). * do 2 rewrite <-insert_union_l. apply rtc_once. eapply E_Ctx with (E := λ e, X_Force (X_V (V_Attrset (<[k := E2 e]>(es ∪ (expr_from_strong_value <$> sws)))))). -- eapply IsCtx_Compose. ++ constructor. ++ eapply IsCtx_Compose with (E1 := (λ e, X_V (V_Attrset (<[k := e]>(es ∪ (expr_from_strong_value <$> sws)))))). ** constructor. ** done. -- done. * by apply IHn. Qed. Lemma insert_union_fmap__union_fmap_insert {A B} (f : A → B) i x (m1 : gmap string B) (m2 : gmap string A) : m1 !! i = None → <[i := f x]>m1 ∪ (f <$> m2) = m1 ∪ (f <$> <[i := x]>m2). Proof. intros Him1. rewrite fmap_insert. rewrite <-insert_union_l. by rewrite <-insert_union_r. Qed. Lemma fmap_insert_union__fmap_union_insert {A B} (f : A → B) i x (m1 : gmap string A) (m2 : gmap string A) : m1 !! i = None → f <$> <[i := x]>m1 ∪ m2 = f <$> m1 ∪ <[i := x]>m2. Proof. intros Him1. do 2 rewrite map_fmap_union. rewrite 2 fmap_insert. rewrite <-insert_union_l. rewrite <-insert_union_r; try done. rewrite lookup_fmap. by rewrite Him1. Qed. Lemma force_map_fmap_union (sws svs : gmap string strong_value) es : map_Forall2 (λ e sv, X_Force e -->* expr_from_strong_value sv) es svs → X_Force (X_V (V_Attrset (es ∪ (expr_from_strong_value <$> sws)))) -->* X_Force (X_V (V_Attrset (expr_from_strong_value <$> svs ∪ sws))). Proof. revert sws svs. induction es using map_ind; intros sws svs HForall2. - apply map_Forall2_empty_l_L in HForall2. subst. by do 2 rewrite map_empty_union. - apply map_Forall2_destruct in HForall2 as HForall2'. destruct HForall2' as [sv [svs' [Him2' Heqm2']]]. subst. apply map_Forall2_insert_inv_strict in HForall2 as [HForall21 HForall22]; try done. apply rtc_transitive with (X_Force (X_V (V_Attrset (<[i := expr_from_strong_value sv]> m ∪ (expr_from_strong_value <$> sws))))). + by apply force_map_fmap_union_insert. + rewrite insert_union_fmap__union_fmap_insert by done. rewrite fmap_insert_union__fmap_union_insert by done. by apply IHes. Qed. (* See 194+2024-0525-2305 for proof sketch *) Lemma force_map_fmap (svs : gmap string strong_value) (es : gmap string expr) : map_Forall2 (λ e sv, X_Force e -->* expr_from_strong_value sv) es svs → X_Force (X_V (V_Attrset es)) -->* X_Force (X_V (V_Attrset (expr_from_strong_value <$> svs))). Proof. pose proof (force_map_fmap_union ∅ svs es). rewrite fmap_empty in H. by do 2 rewrite map_union_empty in H. Qed. Lemma id_compose_l {A B} (f : A → B) : id ∘ f = f. Proof. done. Qed. Lemma is_ctx_trans uf_ext uf_aux uf_int E1 E2 : is_ctx uf_ext uf_aux E1 → is_ctx uf_aux uf_int E2 → is_ctx uf_ext uf_int (E1 ∘ E2). Proof. intros. induction H. - induction H0. + apply IsCtx_Id. + rewrite id_compose_l. by apply IsCtx_Compose with uf_aux. - apply IHis_ctx in H0. replace (E1 ∘ E0 ∘ E2) with (E1 ∘ (E0 ∘ E2)) by done. by apply IsCtx_Compose with uf_aux. Qed. Lemma ctx_mstep e e' E : e -->* e' → is_ctx false false E → E e -->* E e'. Proof. intros. induction H. - apply rtc_refl. - inv H. pose proof (is_ctx_trans false false uf_int E E0 H0 H2). eapply rtc_l. + replace (E (E0 e1)) with ((E ∘ E0) e1) by done. eapply E_Ctx; [apply H | apply H3]. + assumption. Qed. Definition is_nonempty_ctx (uf_ext uf_int : bool) (E : expr → expr) := ∃ E1 E2 uf_aux, is_ctx_item uf_ext uf_aux E1 ∧ is_ctx uf_aux uf_int E2 ∧ E = E1 ∘ E2. Lemma nonempty_ctx_mstep e e' uf_int E : e -->* e' → is_nonempty_ctx false uf_int E → E e -->* E e'. Proof. intros Hmstep Hctx. destruct Hctx as [E1 [E2 [uf_aux [Hctx1 [Hctx2 Hctx3]]]]]. simplify_option_eq. induction Hmstep. + apply rtc_refl. + apply rtc_l with (y := (E1 ∘ E2) y). * inv H. destruct (is_ctx_uf_false_impl_true E uf_int0 H0). +++ apply E_Ctx with (E := E1 ∘ (E2 ∘ E)) (uf_int := uf_int0). ++ eapply IsCtx_Compose. ** apply Hctx1. ** eapply is_ctx_trans. --- apply Hctx2. --- destruct uf_int; assumption. ++ assumption. +++ apply E_Ctx with (E := E1 ∘ (E2 ∘ E)) (uf_int := uf_int). ++ eapply IsCtx_Compose. ** apply Hctx1. ** eapply is_ctx_trans; simplify_option_eq. --- apply Hctx2. --- constructor. ++ assumption. * apply IHHmstep. Qed. Lemma force_strong_value (sv : strong_value) : X_Force sv -->* sv. Proof. destruct sv using strong_value_ind'; apply rtc_once; eapply E_Ctx with (E := id); constructor. Qed. Lemma id_compose_r {A B} (f : A → B) : f ∘ id = f. Proof. done. Qed. Lemma force_idempotent e (v' : value) : X_Force e -->* v' → X_Force (X_Force e) -->* v'. Proof. intros H. destruct (force__strong_value _ _ H) as [sv Hsv]. subst. apply rtc_transitive with (y := X_Force sv). * eapply nonempty_ctx_mstep; try assumption. rewrite <-id_compose_r. exists X_Force, id, true. repeat (split || constructor || done). * apply force_strong_value. Qed. (* Conditional force *) Definition cforce (uf : bool) e := if uf then X_Force e else e. Lemma cforce_strong_value uf (sv : strong_value) : cforce uf sv -->* sv. Proof. destruct uf; try done. apply force_strong_value. Qed. Theorem eval_sound_strong n uf e v' : eval n uf e = Some v' → cforce uf e -->* v'. Proof. revert uf e v'. induction n; intros uf e v' Heval. - discriminate. - destruct e; rewrite eval_S in Heval; simplify_option_eq; try done. + (* X_V *) case_match; simplify_option_eq. * (* V_Bool *) replace (V_Bool p) with (value_from_strong_value (SV_Bool p)) by done. apply cforce_strong_value. * (* V_Null *) replace V_Null with (value_from_strong_value SV_Null) by done. apply cforce_strong_value. * (* V_Int *) replace (V_Int n0) with (value_from_strong_value (SV_Int n0)) by done. apply cforce_strong_value. * (* V_Str *) replace (V_Str s) with (value_from_strong_value (SV_Str s)) by done. apply cforce_strong_value. * (* V_Fn *) replace (V_Fn x e) with (value_from_strong_value (SV_Fn x e)) by done. apply cforce_strong_value. * (* V_AttrsetFn *) replace (V_AttrsetFn m e) with (value_from_strong_value (SV_AttrsetFn m e)) by done. apply cforce_strong_value. * (* V_Attrset *) case_match; simplify_option_eq; try done. apply map_mapM_Some_L in Heqo. simplify_option_eq. eapply map_Forall2_impl_L in Heqo. 2: { intros a b. apply IHn. } destruct (forall2_force__strong_values _ _ Heqo). subst. apply force_strong_value_forall2_impl in Heqo. rewrite <-map_fmap_compose. fold expr_from_strong_value. apply force_map_fmap in Heqo. apply rtc_transitive with (y := X_Force (X_V (V_Attrset (expr_from_strong_value <$> x)))); try done. apply rtc_once. eapply E_Ctx with (E := id); [constructor|]. replace (X_V (V_Attrset (expr_from_strong_value <$> x))) with (expr_from_strong_value (SV_Attrset x)) by reflexivity. apply E_Force. + (* X_Attrset *) apply IHn in Heval. apply rtc_transitive with (y := cforce uf (V_Attrset (rec_subst bs))); [|done]. destruct uf; simplify_eq/=. -- eapply nonempty_ctx_mstep with (E := X_Force). ++ by eapply rtc_once, E_Ctx with (E := id). ++ by exists X_Force, id, true. -- apply rtc_once. by eapply E_Ctx with (E := id). + (* X_LetBinding *) apply IHn in Heval. apply rtc_transitive with (y := cforce uf (subst (closed (rec_subst bs)) e)); [|done]. destruct uf; simplify_eq/=. -- eapply nonempty_ctx_mstep with (E := X_Force). ++ by eapply rtc_once, E_Ctx with (E := id). ++ by exists X_Force, id, true. -- apply rtc_once. by eapply E_Ctx with (E := id). + (* X_Select *) case_match. simplify_option_eq. apply IHn in Heqo. simplify_eq/=. apply rtc_transitive with (y := cforce uf (X_Select (V_Attrset H0) (Ne_Cons head tail))). -- apply ctx_mstep with (E := cforce uf ∘ (λ e, X_Select e (Ne_Cons head tail))). ++ done. ++ destruct uf; simplify_option_eq. ** eapply IsCtx_Compose; [constructor | by apply is_ctx_once]. ** apply is_ctx_once. unfold compose. by simpl. -- case_match; apply IHn in Heval. ++ apply rtc_transitive with (y := cforce uf H); [|done]. apply rtc_once. eapply E_Ctx. ** destruct uf; [by apply is_ctx_once | done]. ** by replace H0 with (<[head := H]>H0); [|apply insert_id]. ++ apply rtc_transitive with (y := cforce uf (X_Select H (Ne_Cons s l))); [|done]. ** eapply rtc_l. --- eapply E_Ctx. +++ destruct uf; [by apply is_ctx_once | done]. +++ replace (Ne_Cons head (s :: l)) with (nonempty_cons head (Ne_Cons s l)) by done. apply E_MSelect. --- eapply rtc_once. eapply E_Ctx with (E := cforce uf ∘ (λ e, X_Select e (Ne_Cons s l))). +++ destruct uf. *** eapply IsCtx_Compose; [done | by apply is_ctx_once]. *** apply is_ctx_once. unfold compose. by simpl. +++ by replace H0 with (<[head := H]>H0); [|apply insert_id]. + (* X_SelectOr *) case_match. simplify_option_eq. apply IHn in Heqo. simplify_eq/=. apply rtc_transitive with (y := cforce uf (X_SelectOr (V_Attrset H0) (Ne_Cons head tail) e2)). -- apply ctx_mstep with (E := cforce uf ∘ (λ e, X_SelectOr e (Ne_Cons head tail) e2)). ++ done. ++ destruct uf; simplify_option_eq. ** eapply IsCtx_Compose; [constructor | by apply is_ctx_once]. ** apply is_ctx_once. unfold compose. by simpl. -- case_match; try case_match; apply IHn in Heval. ++ apply rtc_transitive with (y := cforce uf e); [|done]. eapply rtc_l. ** eapply E_Ctx. --- destruct uf; [by apply is_ctx_once | done]. --- replace (Ne_Cons head []) with (nonempty_singleton head) by done. constructor. ** eapply rtc_l. --- eapply E_Ctx with (E := cforce uf ∘ (λ e1, X_Cond e1 _ _)). +++ destruct uf; simplify_option_eq. *** eapply IsCtx_Compose; [constructor | by apply is_ctx_once]. *** apply is_ctx_once. unfold compose. by simpl. +++ by apply E_OpHasAttrTrue. --- simplify_eq/=. eapply rtc_l. +++ eapply E_Ctx with (E := cforce uf). *** destruct uf; [by apply is_ctx_once | done]. *** apply E_IfTrue. +++ eapply rtc_once. eapply E_Ctx with (E := cforce uf). *** destruct uf; [by apply is_ctx_once | done]. *** by replace H0 with (<[head := e]>H0); [|apply insert_id]. ++ apply rtc_transitive with (y := cforce uf (X_SelectOr e (Ne_Cons s l) e2)); [|done]. eapply rtc_l. ** eapply E_Ctx. --- destruct uf; [by apply is_ctx_once | done]. --- replace (Ne_Cons head (s :: l)) with (nonempty_cons head (Ne_Cons s l)) by done. constructor. ** eapply rtc_l. --- eapply E_Ctx with (E := cforce uf ∘ (λ e1, X_Cond e1 _ _)). +++ destruct uf; simplify_option_eq. *** eapply IsCtx_Compose; [constructor | by apply is_ctx_once]. *** apply is_ctx_once. unfold compose. by simpl. +++ by apply E_OpHasAttrTrue. --- simplify_eq/=. eapply rtc_l. +++ eapply E_Ctx with (E := cforce uf). *** destruct uf; [by apply is_ctx_once | done]. *** apply E_IfTrue. +++ eapply rtc_once. eapply E_Ctx with (E := cforce uf ∘ λ e1, X_SelectOr e1 (Ne_Cons s l) e2). *** destruct uf; simplify_option_eq. ---- eapply IsCtx_Compose; [constructor | by apply is_ctx_once]. ---- apply is_ctx_once. unfold compose. by simpl. *** by replace H0 with (<[head := e]>H0); [|apply insert_id]. ++ apply rtc_transitive with (y := cforce uf e2); [|done]. destruct tail. ** eapply rtc_l. --- eapply E_Ctx. +++ destruct uf; [by apply is_ctx_once | done]. +++ replace (Ne_Cons head []) with (nonempty_singleton head) by done. constructor. --- eapply rtc_l. +++ eapply E_Ctx with (E := cforce uf ∘ (λ e1, X_Cond e1 _ _)). *** destruct uf; simplify_option_eq. ---- eapply IsCtx_Compose; [constructor | by apply is_ctx_once]. ---- apply is_ctx_once. unfold compose. by simpl. *** by apply E_OpHasAttrFalse. +++ simplify_eq/=. eapply rtc_once. eapply E_Ctx with (E := cforce uf). *** destruct uf; [by apply is_ctx_once | done]. *** apply E_IfFalse. ** eapply rtc_l. --- eapply E_Ctx. +++ destruct uf; [by apply is_ctx_once | done]. +++ replace (Ne_Cons head (s :: tail)) with (nonempty_cons head (Ne_Cons s tail)) by done. constructor. --- eapply rtc_l. +++ eapply E_Ctx with (E := cforce uf ∘ (λ e1, X_Cond e1 _ _)). *** destruct uf; simplify_option_eq. ---- eapply IsCtx_Compose; [constructor | by apply is_ctx_once]. ---- apply is_ctx_once. unfold compose. by simpl. *** by apply E_OpHasAttrFalse. +++ simplify_eq/=. eapply rtc_once. eapply E_Ctx with (E := cforce uf). *** destruct uf; [by apply is_ctx_once | done]. *** apply E_IfFalse. + (* X_Apply *) case_match; simplify_option_eq; apply IHn in Heqo, Heval. * (* Basic lambda abstraction *) apply rtc_transitive with (y := cforce uf (X_Apply (V_Fn x e) e2)). -- apply ctx_mstep with (E := cforce uf ∘ λ e1, X_Apply e1 e2); [done|]. destruct uf. ++ by eapply IsCtx_Compose; [|apply is_ctx_once]. ++ apply is_ctx_once. unfold compose. by simpl. -- apply rtc_transitive with (y := cforce uf (subst {[x := X_Closed e2]} e)); [|done]. eapply rtc_once. eapply E_Ctx. ++ destruct uf; [by apply is_ctx_once | done]. ++ by constructor. * (* Pattern-matching function *) apply rtc_transitive with (y := cforce uf (X_Apply (V_AttrsetFn m e) e2)). -- apply ctx_mstep with (E := cforce uf ∘ λ e1, X_Apply e1 e2); [done|]. destruct uf. ++ by eapply IsCtx_Compose; [|apply is_ctx_once]. ++ apply is_ctx_once. unfold compose. by simpl. -- apply rtc_transitive with (y := cforce uf (X_Apply (V_AttrsetFn m e) (V_Attrset H0))). ++ apply ctx_mstep with (E := cforce uf ∘ λ e2, X_Apply (V_AttrsetFn m e) e2). ** by apply IHn in Heqo0. ** destruct uf. --- by eapply IsCtx_Compose; [|apply is_ctx_once]. --- apply is_ctx_once. unfold compose. by simpl. ++ apply rtc_transitive with (y := cforce uf (X_LetBinding H e)); [|done]. eapply rtc_once. eapply E_Ctx. ** destruct uf; [by apply is_ctx_once | done]. ** apply matches_sound in Heqo1. by constructor. * (* __functor *) apply rtc_transitive with (y := cforce uf (X_Apply (V_Attrset bs) e2)). -- apply ctx_mstep with (E := cforce uf ∘ λ e1, X_Apply e1 e2); [done|]. destruct uf. ++ by eapply IsCtx_Compose; [|apply is_ctx_once]. ++ apply is_ctx_once. unfold compose. by simpl. -- apply rtc_transitive with (y := cforce uf (X_Apply (X_Apply H (V_Attrset bs)) e2)); [|done]. eapply rtc_once. eapply E_Ctx. ++ destruct uf; [by apply is_ctx_once | done]. ++ by replace bs with (<["__functor" := H]>bs); [|apply insert_id]. + (* X_Cond *) simplify_option_eq. apply IHn in Heqo, Heval. apply rtc_transitive with (y := cforce uf (X_Cond (V_Bool H0) e2 e3)). * apply ctx_mstep with (E := cforce uf ∘ λ e1, X_Cond e1 e2 e3); [done|]. destruct uf. -- by eapply IsCtx_Compose; [|apply is_ctx_once]. -- apply is_ctx_once. unfold compose. by simpl. * destruct H0; eapply rtc_l; try done; eapply E_Ctx; try done; by destruct uf; [apply is_ctx_once|]. + (* X_Incl *) apply IHn in Heqo. apply rtc_transitive with (y := cforce uf (X_Incl H e2)). * apply ctx_mstep with (E := cforce uf ∘ λ e1, X_Incl e1 e2). -- done. -- destruct uf. ++ eapply IsCtx_Compose; [done | by apply is_ctx_once]. ++ unfold compose. apply is_ctx_once. by simpl. * destruct (decide (attrset H)). -- destruct H; inv a. simplify_option_eq. apply IHn in Heval. eapply rtc_l; [|done]. eapply E_Ctx. ++ destruct uf; [by apply is_ctx_once | done]. ++ apply E_With. -- destruct H; try (eapply rtc_l; [ eapply E_Ctx; [ destruct uf; [by apply is_ctx_once | done] | by apply E_WithNoAttrset ] | by apply IHn in Heval ]). destruct n0. by exists bs. + (* X_Assert *) apply IHn in Heqo. apply rtc_transitive with (y := cforce uf (X_Assert H e2)). * apply ctx_mstep with (E := cforce uf ∘ λ e1, X_Assert e1 e2); [done|]. destruct uf. -- by eapply IsCtx_Compose; [|apply is_ctx_once]. -- unfold compose. apply is_ctx_once. by simpl. * destruct H; try discriminate. destruct p; try discriminate. apply IHn in Heval. eapply rtc_l; [|done]. eapply E_Ctx; [|done]. by destruct uf; [apply is_ctx_once|]. + (* X_Binop *) apply IHn in Heqo, Heqo0. apply rtc_transitive with (y := cforce uf (X_Op op (X_V H) e2)). * apply ctx_mstep with (E := cforce uf ∘ λ e1, X_Op op e1 e2). -- done. -- destruct uf. ++ eapply IsCtx_Compose; [done | by apply is_ctx_once]. ++ unfold compose. apply is_ctx_once. by simpl. * apply rtc_transitive with (y := cforce uf (X_Op op (X_V H) (X_V H0))). -- apply ctx_mstep with (E := cforce uf ∘ λ e2, X_Op op (X_V H) e2). ++ done. ++ destruct uf. ** eapply IsCtx_Compose; [done | by apply is_ctx_once]. ** unfold compose. apply is_ctx_once. by simpl. -- eapply rtc_l. ++ eapply E_Ctx with (E := cforce uf). ** destruct uf; [by apply is_ctx_once | done]. ** apply E_Op. by apply binop_eval_sound. ++ by apply IHn. + (* X_HasAttr *) apply IHn in Heqo. apply rtc_transitive with (y := cforce uf (X_HasAttr H x)). * apply ctx_mstep with (E := cforce uf ∘ λ e, X_HasAttr e x); [done|]. destruct uf. -- by eapply IsCtx_Compose; [|apply is_ctx_once]. -- unfold compose. apply is_ctx_once. by simpl. * destruct (decide (attrset H)). -- case_match; inv a. simplify_option_eq. apply rtc_transitive with (y := cforce uf (bool_decide (is_Some (x0 !! x)))). ++ apply rtc_once. eapply E_Ctx. ** destruct uf; [by apply is_ctx_once | done]. ** destruct (decide (is_Some (x0 !! x))). --- rewrite bool_decide_true by done. by constructor. --- rewrite bool_decide_false by done. constructor. by apply eq_None_not_Some in n0. ++ destruct uf; [|done]. apply rtc_once. simpl. replace (V_Bool (bool_decide (is_Some (x0 !! x)))) with (value_from_strong_value (SV_Bool (bool_decide (is_Some (x0 !! x))))) by done. by eapply E_Ctx with (E := id). -- apply rtc_transitive with (y := cforce uf false). ++ apply rtc_once. eapply E_Ctx. ** destruct uf; [by apply is_ctx_once | done]. ** by constructor. ++ assert (Hforce : cforce true false -->* false). { apply rtc_once. simpl. replace (V_Bool false) with (value_from_strong_value (SV_Bool false)) by done. eapply E_Ctx with (E := id); done. } destruct H; try (by destruct uf; [apply Hforce | done]). exfalso. apply n0. by exists bs. + (* X_Force *) apply IHn in Heval. clear IHn n. destruct uf; try done. simplify_eq/=. by apply force_idempotent. + (* X_Closed *) apply IHn in Heval. eapply rtc_l; [|done]. eapply E_Ctx; [|done]. * by destruct uf; [apply is_ctx_once|]. + (* X_Placeholder *) apply IHn in Heval. clear IHn n. destruct uf; simplify_eq/=; eapply rtc_l; try done. -- eapply E_Ctx with (E := X_Force); [by apply is_ctx_once | done]. -- by eapply E_Ctx with (E := id). Qed. Lemma value_stuck v : ¬ ∃ e', X_V v --> e'. Proof. induction v; intros [e' He']; inversion He'; subst; (inv H0; [inv H1 | inv H2]). Qed. Theorem eval_sound_weak e v' n : eval n false e = Some v' → is_nf_of step e v'. Proof. intros Heval. pose proof (eval_sound_strong _ _ _ _ Heval). split; [done | apply value_stuck]. Qed.