(** *** Exercise  Complete the proof of the substitution lemma. The proof proceeds by induction on the typing derivation for [e].  The initial steps should use [remember as] and [generalize dependent] in a manner similar to the proof of weakening.  HINTS: - Use the lemma proved above for the [typing_var_c] case.  - The [typing_abs_c] case follows from the induction hypothesis. -- Use [simpl] to simplify the substitution.  -- Recall the tactic [pick fresh and apply].  -- In order to use the induction hypothesis, use [subst_open_var_c] to push the substitution under the opening operation.  -- Recall the lemma [typing_c_to_lc_c] and the [rewrite_env] and [simpl_env] tactics.  - The [typing_app_c] case follows from the induction hypotheses. Use [simpl] to simplify the substitution. *)

(* Specifications: *)
Lemma typing_c_subst : forall (E F : env) e u S T (z : atom),
typing_c (F ++ (z ~ S) ++ E) e T ->
typing_c E u S ->
typing_c (F ++ E) ([z ~> u] e) T.
Lemma typing_c_subst : forall (E F : env) e u S T (z : atom),
typing_c (F ++ (z ~ S) ++ E) e T ->
typing_c E u S ->
typing_c (F ++ E) ([z ~> u] e) T.
(* Demo: the proof of renaming.  Note that this proof does not proceed by induction: even if we add new typing rules to the language, as long as the weakening and substution properties hold we can use this proof. *)
Lemma typing_c_rename : forall (x y : atom) E e T1 T2,
x `notin` fv e -> y `notin` (dom E `union` fv e) ->
typing_c ((x ~ T1) ++ E) (open e x) T2 ->
typing_c ((y ~ T1) ++ E) (open e y) T2.