(*
Lemma gvar_globals_only:
  forall i v rho, gvar i v rho -> gvar i v (globals_only rho).
Proof.
unfold gvar; intros.
unfold Map.get in *.
destruct (ve_of rho i) as [[? ?]|] eqn:?; try contradiction.
unfold globals_only.
simpl. auto.
Qed.
Hint Resolve gvar_globals_only.
*)

Ltac safe_auto_with_closed :=
   (* won't instantiate evars by accident *)
 match goal with |- ?A =>
          solve [first [has_evar A | auto 50 with closed]]
 end.

(* Specifications: *)
Lemma closed_env_set: forall {B} i v (P: environ -> B) rho, closed_wrt_vars (eq i) P -> P (env_set rho i v) = P rho.
Lemma subst_eval_id_eq: forall id v, subst id v (eval_id id) = v.
Lemma subst_eval_id_neq: forall id v j, id<>j -> subst id v (eval_id j) = eval_id j.
Lemma subst_eval_expr_eq: forall {cs: compspecs} j v e, subst j v (eval_expr e) = subst_eval_expr j v e with subst_eval_lvalue_eq: forall {cs: compspecs} j v e, subst j v (eval_lvalue e) = subst_eval_lvalue j v e.
Lemma closed_wrt_subst: forall {A} id e (P: environ -> A), closed_wrt_vars (eq id) P -> subst id e P = P.
Lemma closed_wrt_map_subst: forall {A: Type} id e (Q: list (environ -> A)), Forall (closed_wrt_vars (eq id)) Q -> map (subst id e) Q = Q.
Lemma closed_wrt_map_subst': forall {A: Type} id e (Q: list (environ -> A)), Forall (closed_wrt_vars (eq id)) Q -> @map (LiftEnviron A) _ (subst id e) Q = Q.
Lemma closed_wrt_subst_eval_expr: forall {cs: compspecs} j v e, closed_wrt_vars (eq j) (eval_expr e) -> subst_eval_expr j v e = eval_expr e.
Lemma closed_wrt_subst_eval_lvalue: forall {cs: compspecs} j v e, closed_wrt_vars (eq j) (eval_lvalue e) -> subst_eval_lvalue j v e = eval_lvalue e.
Lemma closed_wrt_local: forall S P, closed_wrt_vars S P -> closed_wrt_vars S (local P).
Lemma closed_wrtl_local: forall S P, closed_wrt_lvars S P -> closed_wrt_lvars S (local P).
Lemma closed_wrt_lift0: forall {A} S (Q: A), closed_wrt_vars S (lift0 Q).
Lemma closed_wrtl_lift0: forall {A} S (Q: A), closed_wrt_lvars S (lift0 Q).
Lemma closed_wrt_lift0C: forall {B} S (Q: B), closed_wrt_vars S (@liftx (LiftEnviron B) Q).
Lemma closed_wrtl_lift0C: forall {B} S (Q: B), closed_wrt_lvars S (@liftx (LiftEnviron B) Q).
Lemma closed_wrt_lift1: forall {A}{B} S (f: A -> B) P, closed_wrt_vars S P -> closed_wrt_vars S (lift1 f P).
Lemma closed_wrtl_lift1: forall {A}{B} S (f: A -> B) P, closed_wrt_lvars S P -> closed_wrt_lvars S (lift1 f P).
Lemma closed_wrt_lift1C: forall {A}{B} S (f: A -> B) P, closed_wrt_vars S P -> closed_wrt_vars S (@liftx (Tarrow A (LiftEnviron B)) f P).
Lemma closed_wrtl_lift1C: forall {A}{B} S (f: A -> B) P, closed_wrt_lvars S P -> closed_wrt_lvars S (@liftx (Tarrow A (LiftEnviron B)) f P).
Lemma closed_wrt_lift2: forall {A1 A2}{B} S (f: A1 -> A2 -> B) P1 P2, closed_wrt_vars S P1 -> closed_wrt_vars S P2 -> closed_wrt_vars S (lift2 f P1 P2).
Lemma closed_wrtl_lift2: forall {A1 A2}{B} S (f: A1 -> A2 -> B) P1 P2, closed_wrt_lvars S P1 -> closed_wrt_lvars S P2 -> closed_wrt_lvars S (lift2 f P1 P2).
Lemma closed_wrt_lift2C: forall {A1 A2}{B} S (f: A1 -> A2 -> B) P1 P2, closed_wrt_vars S P1 -> closed_wrt_vars S P2 -> closed_wrt_vars S (@liftx (Tarrow A1 (Tarrow A2 (LiftEnviron B))) f P1 P2).
Lemma closed_wrtl_lift2C: forall {A1 A2}{B} S (f: A1 -> A2 -> B) P1 P2, closed_wrt_lvars S P1 -> closed_wrt_lvars S P2 -> closed_wrt_lvars S (@liftx (Tarrow A1 (Tarrow A2 (LiftEnviron B))) f P1 P2).
Lemma closed_wrt_lift3: forall {A1 A2 A3}{B} S (f: A1 -> A2 -> A3 -> B) P1 P2 P3, closed_wrt_vars S P1 -> closed_wrt_vars S P2 -> closed_wrt_vars S P3 -> closed_wrt_vars S (lift3 f P1 P2 P3).
Lemma closed_wrtl_lift3: forall {A1 A2 A3}{B} S (f: A1 -> A2 -> A3 -> B) P1 P2 P3, closed_wrt_lvars S P1 -> closed_wrt_lvars S P2 -> closed_wrt_lvars S P3 -> closed_wrt_lvars S (lift3 f P1 P2 P3).
Lemma closed_wrt_lift3C: forall {A1 A2 A3}{B} S (f: A1 -> A2 -> A3 -> B) P1 P2 P3, closed_wrt_vars S P1 -> closed_wrt_vars S P2 -> closed_wrt_vars S P3 -> closed_wrt_vars S (@liftx (Tarrow A1 (Tarrow A2 (Tarrow A3 (LiftEnviron B)))) f P1 P2 P3).
Lemma closed_wrtl_lift3C: forall {A1 A2 A3}{B} S (f: A1 -> A2 -> A3 -> B) P1 P2 P3, closed_wrt_lvars S P1 -> closed_wrt_lvars S P2 -> closed_wrt_lvars S P3 -> closed_wrt_lvars S (@liftx (Tarrow A1 (Tarrow A2 (Tarrow A3 (LiftEnviron B)))) f P1 P2 P3).
Lemma closed_wrt_lift4: forall {A1 A2 A3 A4}{B} S (f: A1 -> A2 -> A3 -> A4 -> B) P1 P2 P3 P4, closed_wrt_vars S P1 -> closed_wrt_vars S P2 -> closed_wrt_vars S P3 -> closed_wrt_vars S P4 -> closed_wrt_vars S (lift4 f P1 P2 P3 P4).
Lemma closed_wrtl_lift4: forall {A1 A2 A3 A4}{B} S (f: A1 -> A2 -> A3 -> A4 -> B) P1 P2 P3 P4, closed_wrt_lvars S P1 -> closed_wrt_lvars S P2 -> closed_wrt_lvars S P3 -> closed_wrt_lvars S P4 -> closed_wrt_lvars S (lift4 f P1 P2 P3 P4).
Lemma closed_wrt_lift4C: forall {A1 A2 A3 A4}{B} S (f: A1 -> A2 -> A3 -> A4 -> B) P1 P2 P3 P4, closed_wrt_vars S P1 -> closed_wrt_vars S P2 -> closed_wrt_vars S P3 -> closed_wrt_vars S P4 -> closed_wrt_vars S (@liftx (Tarrow A1 (Tarrow A2 (Tarrow A3 (Tarrow A4 (LiftEnviron B))))) f P1 P2 P3 P4).
Lemma closed_wrtl_lift4C: forall {A1 A2 A3 A4}{B} S (f: A1 -> A2 -> A3 -> A4 -> B) P1 P2 P3 P4, closed_wrt_lvars S P1 -> closed_wrt_lvars S P2 -> closed_wrt_lvars S P3 -> closed_wrt_lvars S P4 -> closed_wrt_lvars S (@liftx (Tarrow A1 (Tarrow A2 (Tarrow A3 (Tarrow A4 (LiftEnviron B))))) f P1 P2 P3 P4).
Lemma closed_wrt_const: forall A (P: A) S, closed_wrt_vars S (fun rho: environ => P).
Lemma closed_wrtl_const: forall A (P: A) S, closed_wrt_lvars S (fun rho: environ => P).
Lemma closed_wrt_eval_var: forall S id t, closed_wrt_vars S (eval_var id t).
Lemma closed_wrtl_eval_var: forall S id t, ~ S id -> closed_wrt_lvars S (eval_var id t).
Lemma closed_wrt_lvar: forall S id t v, closed_wrt_vars S (locald_denote (lvar id t v)).
Lemma closed_wrt_gvars: forall S gv, closed_wrt_vars S (locald_denote (gvars gv)).
Lemma closed_wrtl_gvars: forall S gv, closed_wrt_lvars S (locald_denote (gvars gv)).
Lemma closed_wrtl_lvar: forall {cs: compspecs} S id t v, ~ S id -> closed_wrt_lvars S (locald_denote (lvar id t v)).