Local Open Scope logic.
Ltac unfold_for_go_lower :=
cbv delta [PROPx LOCALx SEPx locald_denote
eval_exprlist eval_expr eval_lvalue cast_expropt
eval_binop eval_unop force_val1 force_val2
msubst_tc_expropt msubst_tc_expr msubst_tc_exprlist msubst_tc_lvalue msubst_tc_LR (* msubst_tc_LR_strong *) msubst_tc_efield msubst_simpl_tc_assert
function_body_ret_assert frame_ret_assert
make_args' bind_ret get_result1 retval
classify_cast
(* force_val sem_cast_neutral ... NOT THESE TWO!  *)
denote_tc_assert (* tc_andp tc_iszero *)
liftx LiftEnviron Tarrow Tend lift_S lift_T
lift_prod lift_last lifted lift_uncurry_open lift_curry
local lift lift0 lift1 lift2 lift3
] beta iota.
Ltac go_lower0 :=
intros ?rho;
try (simple apply grab_tc_environ; intro);
repeat (progress unfold_for_go_lower; simpl).
Ltac old_go_lower :=
go_lower0;
autorewrite with go_lower;
try findvars;
simpl;
autorewrite with go_lower;
try match goal with H: tc_environ _ ?rho |- _ => clear H rho end.
Hint Rewrite eval_id_same : go_lower.
Hint Rewrite eval_id_other using solve [clear; intro Hx; inversion Hx] : go_lower.
(*Hint Rewrite Vint_inj' : go_lower.*)
(*** New go_lower stuff ****)
Ltac safe_subst x := subst x.
Ltac safe_subst_any := subst_any.
(* safe_subst is meant to avoid doing rewrites or substitution of variables that are in the scope of a unification variable.  Right now, the tactic is a placeholder for real tactic that will detect the scope violation and (if so) avoid doing the substition.  See issue #186. *)
Ltac lower_one_temp_Vint' :=
match goal with
| |- (local _ && PROPx _ (LOCALx (temp _ ?v :: _) _)) _ |-- _ =>
is_var v;
simple eapply lower_one_temp_Vint';
[ reflexivity | ];
let v' := fresh "v" in rename v into v';
let tc := fresh "TC" in
intros [v [? [tc ?EVAL]]]; unfold tc_val in tc; safe_subst v';
revert tc; fancy_intro true
end.

Lemma quick_finish_lower:
forall LHS,
emp |-- !! True ->
LHS |-- !! True.