Definition substopt {A} (ret: option ident) (v: val) (P: environ -> A)  : environ -> A :=
match ret with
| Some id => subst id v P
| None => P
end.

Lemma semax_call_typecheck_environ:
forall (Delta : tycontext) (bl : list expr) (psi : genv) (vx : env) (tx : temp_env)
(jm : juicy_mem) (b : block) (f : function)
(H17 : list_norepet (map fst (fn_params f) ++ map fst (fn_temps f)))
(H17' : list_norepet (map fst (fn_vars f)))
(H16 : Genv.find_funct_ptr psi b = Some (Internal f))
(ve' : env) (jm' : juicy_mem) (te' : temp_env)
(H15 : alloc_variables psi empty_env (m_dry jm) (fn_vars f) ve' (m_dry jm'))
(TC3 : typecheck_temp_environ (make_tenv tx) (temp_types Delta))
(TC4 : typecheck_var_environ (make_venv vx) (var_types Delta))
(TC5 : typecheck_glob_environ (filter_genv psi) (glob_types Delta))
(H : forall (b : ident) (b0 : funspec) (a' : rmap),
necR (m_phi jm') a' ->
(glob_specs Delta) ! b = Some b0 ->
exists b1 : block,
filter_genv psi b = Some b1 /\
func_at b0 (b1,0) a')
(H1: forall (b : block) (b0 : funspec) (a' : rmap),
necR (m_phi jm') a' ->
(func_at' b0 (b, 0)) a' ->
exists (b1 : ident),
filter_genv psi b1 = Some b /\
(exists fs : funspec, (glob_specs Delta) ! b1 = Some fs))
(l : list ident) (l0 : list type)
(Heqp : (l, l0) = split (fn_params f))
(TC2 : denote_tc_assert (typecheck_exprlist Delta l0 bl)
(mkEnviron (filter_genv psi) (make_venv vx) (make_tenv tx)) (m_phi jm)) (**)
(H21 : bind_parameter_temps (fn_params f)
(eval_exprlist l0 bl
(mkEnviron (filter_genv psi) (make_venv vx) (make_tenv tx)))
(create_undef_temps (fn_temps f)) = Some te')
(TE : typecheck_environ
Delta (mkEnviron (filter_genv psi) (make_venv vx) (make_tenv tx))),
typecheck_environ
(mk_tycontext
(make_tycontext_t (fn_params f) (fn_temps f))
(make_tycontext_v (fn_vars f))
(fn_return f)  (glob_types Delta) (glob_specs Delta) (annotations Delta))
(mkEnviron (filter_genv psi) (make_venv ve') (make_tenv te')).