theory RedSafeAppLemma
  imports RedSafeCV RedSafeCase SafeSubTPX
begin

    (* ##### sares *)

lemma sares_lam_helper: "\<lbrakk> well_typed env delta r_s1 e2 tau (diff_use_env (comp_use_env r_s3 r_exa) (comp_use_env rxa (lift_use_env rx2 r)))
      (diff_use_env (comp_use_env rxa rx2) (comp_use_env rxa (lift_use_env rx2 r))); non_prim_env env \<rbrakk> \<Longrightarrow>
  well_typed env delta r_s1 e2 tau (diff_use_env (comp_use_env r_s3 r_exa) (comp_use_env rxa (lift_use_env rx2 r))) (app_req rxa rx2 r tau empty_use_env)"
  apply (simp add: app_req_def)
  apply (auto)
   apply (rule_tac rx="diff_use_env (comp_use_env rxa rx2) (comp_use_env rxa (lift_use_env rx2 r))" in prim_type_no_req)
     apply (auto)
  apply (cut_tac r="comp_use_env rxa (lift_use_env rx2 r)" in comp_empty_use_env2)
  apply (auto)
  done

lemma sares_fix_case: "\<lbrakk>well_typed_state s1 env delta; sub_use_env s1 r_f; app_red_exp FixApp (s1, AppExp (ConstExp FixConst) x62) ax (s2, e2);
        e1 = AppExp (ConstExp FixConst) x62; well_typed env delta r_s2a x62 t1 r_s3 rx2;
        leq_use_env r_s2 (diff_use_env r_s3 (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex)); (*safe_use_lift rx2 r; safe_type t1 r;*)
        leq_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_s3; disj_use_env rx1 (lift_use_env rx2 r); leq_use_env rx r_s2; leq_use_env r_ex r_s1;
        leq_use_env (app_req rx1 rx2 r tau r_ex) rx; leq_use_env r_s2a r_s1; leq_use_env rx1 r_s2a;
        FunTy t1 tau r a = pure_fun (pure_fun t t (req_type t)) t Prim; fun_ty t; unlim t; leq_use_env r_s1 r_f \<rbrakk>
       \<Longrightarrow> \<exists>g_ax. well_typed (red_env env g_ax) (red_delta delta g_ax) (exp_red_use_env r_s1 g_ax) e2 tau (end_red_use_env r_s2 g_ax) (end_red_use_env rx g_ax) \<and>
                  well_typed_state s2 (red_env env g_ax) (red_delta delta g_ax) \<and>
                  sub_use_env s2 (exp_red_use_env r_f g_ax) \<and> safe_act s1 (infl_use_env r_f r_s2) g_ax \<and> corr_act ax g_ax"
  apply (case_tac x62)
       apply (auto)
  apply (case_tac ax)
    apply (auto)
  apply (simp add: pure_fun_def)
  apply (auto)
    (* - prelim: rxa is weak *)
  apply (case_tac "\<not> weak_use_env rxa")
   apply (simp add: aff_use_env_def)
   apply (case_tac "req_type tau")
     apply (simp add: unlim_def)
    apply (simp)
   apply (simp add: null_use_env_def)
   apply (simp add: weak_use_env_def)
  apply (rule_tac x="NoResAct" in exI)
  apply (auto)
    (* e2 = x52 (Fix (\<lambda> x51. x52)). We can type the external app as: <<r_s1>> x52 <<r_s2a, rx1>> (Fix (\<lambda> x51. x52)) <<r_s3, rx2>>
      We can type the internal app as: <<r_s2a>> Fix <<r_s2a, {}>> (\<lambda> x51. x52) <<r_s2a, rxa>>
    *)
  apply (rule_tac ?r_s2.0="diff_use_env (diff_use_env r_s2a (comp_use_env rxa (lift_use_env rxa UsePerm))) (comp_use_env rx2 (comp_use_env r_exa r_ex))" and
        rx="diff_use_env (diff_use_env (comp_use_env rxa rxa) (comp_use_env rxa (lift_use_env rxa UsePerm))) (comp_use_env rx2 (comp_use_env r_exa r_ex))" in well_typed_simul_end_perm)
     apply (rule_tac well_typed_diff_end_perm)
      apply (rule_tac t="tau" and ?rx1.0="rxa" and r_s'="r_s'" and r_end="r_end" and ?e1.0="x62a" and x="x61" and
          ?r_s2.0="r_s2a" and ?r_s3.0="r_s2a" and e'="AppExp (ConstExp FixConst) (LamExp x61 x62a)" in safe_subst_type_preserve_x)
               apply (auto)
         apply (rule_tac x="FunTy tau tau UsePerm (req_type tau)" in exI)
         apply (rule_tac x="UsePerm" in exI)
         apply (auto)
          apply (simp add: pure_fun_def)
         apply (rule_tac x="r_s2a" in exI)
         apply (auto)
          apply (rule_tac id_leq_use_env)
         apply (rule_tac x="empty_use_env" in exI)
         apply (auto)
          apply (rule_tac leq_empty_use_env)
         apply (case_tac "\<not> weak_use_env empty_use_env")
          apply (simp add: weak_use_env_def)
          apply (simp add: empty_use_env_def)
         apply (rule_tac x="rxa" in exI)
         apply (rule_tac x="r_s2a" in exI)
         apply (auto)
          apply (rule_tac x="rxa" in exI)
          apply (auto)
          apply (rule_tac x="empty_use_env" in exI)
          apply (auto)
            apply (rule_tac rhs_weak_leq_use_env)
             apply (auto)
            apply (rule_tac id_leq_use_env)
           apply (rule_tac leq_empty_use_env)
          apply (rule_tac self_diff_leq_use_env)
         apply (rule_tac x="empty_use_env" in exI)
         apply (auto)
              apply (rule_tac rhs_weak_leq_use_env)
               apply (rule_tac dist_weak_comp_use_env)
                apply (rule_tac dist_weak_comp_use_env)
                 apply (auto)(*
              apply (simp add: aff_use_env_def)
              apply (simp add: weak_use_env_def)*)
              apply (rule_tac id_leq_use_env)(*
             apply (simp add: aff_use_env_def)
             apply (case_tac "req_type tau")
               apply (simp add: unlim_def)
              apply (simp add: weak_use_env_def)
             apply (simp add: null_use_env_def)*)
            apply (rule_tac dist_comp_leq_use_env)
             apply (rule_tac leq_empty_use_env)
            apply (simp)
           apply (rule_tac disj_empty_use_env2)
          apply (rule_tac leq_empty_use_env)
         apply (simp add: app_req_def)
         apply (auto)
          apply (rule_tac leq_empty_use_env)
         apply (rule_tac diff_leq_use_env)
         apply (rule_tac dist_comp_leq_use_env)
          apply (rule_tac leq_empty_use_env)
         apply (rule_tac id_leq_use_env)
        apply (rule_tac wts_well_formed_delta)
        apply (auto)
       apply (rule_tac r_sb="r_s2a" in trans_leq_use_env)
        apply (auto)
      apply (rule_tac dist_comp_leq_use_env)
       apply (auto)
     apply (simp add: weak_use_env_def)
     apply (simp add: aff_use_env_def)
     apply (simp add: disj_use_env_def)
     apply (simp add: mini_disj_use_env_def)
    (* diff correctness *)
     apply (rule_tac dist_comp_leq_use_env)
      apply (rule_tac r_sb="comp_use_env rx1 rx2" in trans_leq_use_env)
       apply (rule_tac r_sb="r_s3" in trans_leq_use_env)
        apply (rule_tac r_sb="diff_use_env r_s2a r_exa" in trans_leq_use_env)
         apply (rule_tac diff_leq_use_env)
         apply (simp_all)
      apply (rule_tac self_comp_leq_use_env2)
     apply (rule_tac dist_comp_leq_use_env)
      apply (rule_tac r_sb="r_s2a" in trans_leq_use_env)
       apply (auto)
    (* prove bound shifts were valid. to show that r_s2 (the only end perm bound) is lower than r_s2a - rxa (our proposed bound),
        we use the fact that r_s2 \<le> r_s3 - rx2, and whatever is not removed by rx2 was already removed by r_exa from r_s2a.  *)
    apply (rule_tac r_sb="diff_use_env r_s3 (comp_use_env (comp_use_env rx1 rx2) r_ex)" in trans_leq_use_env)
     apply (rule_tac r_sb="diff_use_env (diff_use_env r_s2a r_exa) (comp_use_env (comp_use_env rx1 rx2) r_ex)" in trans_leq_use_env)
      apply (rule_tac lhs_fold_dcl_use_env)
      apply (rule_tac dist_diff_leq_use_env_gen)
       apply (rule_tac rhs_weak_leq_use_env)
        apply (rule_tac dist_weak_comp_use_env)
         apply (simp_all)
      apply (rule_tac id_leq_use_env)
     apply (rule_tac dist_comp_leq_use_env)
      apply (rule_tac comp_leq_use_env2)
      apply (rule_tac comp_leq_use_env1)
      apply (rule_tac self_comp_leq_use_env2)
     apply (rule_tac dist_comp_leq_use_env)
      apply (rule_tac self_comp_leq_use_env1)
     apply (rule_tac comp_leq_use_env2)
     apply (rule_tac self_comp_leq_use_env2)
    apply (rule_tac dist_diff_leq_use_env)
    apply (simp)
    (* proving the rx bound in the primitive case is predicated on the fact that rxa is null *)
  apply (simp add: app_req_def)
  apply (case_tac "req_type tau = Prim")
   apply (case_tac "\<not> leq_use_env rxa empty_use_env")
    apply (simp add: aff_use_env_def)
    apply (simp add: null_use_env_def)
    apply (simp add: leq_use_env_def)
   apply (rule_tac r_sb="empty_use_env" in trans_leq_use_env)
    apply (rule_tac leq_empty_use_env)
   apply (rule_tac diff_leq_use_env)
   apply (rule_tac diff_leq_use_env)
   apply (rule_tac dist_comp_leq_use_env)
    apply (auto)
    (* otherwise, to show that rx \<ge> rxa - (rxa + r_exa + r_ex) (our proposed bound). we note that rxa - r_exa \<le> rx2.
        rx \<ge> rx2 - (rx1 + rx2 + r_ex). rx1 is disjoint, rx2 is weak, r_ex is included in our bound *)
  apply (rule_tac r_sb="diff_use_env (comp_use_env rx1 rx2) (comp_use_env (comp_use_env rx1 rx2) r_ex)" in trans_leq_use_env)
   apply (simp)
  apply (rule_tac r_sb="diff_use_env (diff_use_env rxa r_exa) (comp_use_env (comp_use_env rx1 rx2) r_ex)" in trans_leq_use_env)
   apply (rule_tac dist_diff_leq_use_env)
   apply (rule_tac comp_leq_use_env2)
   apply (simp)
  apply (rule_tac unroll_dcl_use_env)
  apply (rule_tac lhs_unroll_dcl_use_env)
  apply (rule_tac dist_diff_leq_use_env)
  apply (rule_tac lhs_fold_dcl_use_env)
  apply (rule_tac lhs_flip_use_env)
  apply (rule_tac unroll_dcl_use_env)
  apply (rule_tac dist_diff_leq_use_env)
  apply (rule_tac disj_diff_leq_use_env)
   apply (rule_tac r_s="rx2" in disj_leq_use_env2)
    apply (simp)
   apply (rule_tac r_sb="diff_use_env rxa r_exa" in trans_leq_use_env)
    apply (simp)
   apply (rule_tac dist_diff_leq_use_env)
   apply (rule_tac diff_leq_use_env)
   apply (rule_tac dist_comp_leq_use_env)
    apply (rule_tac id_leq_use_env)
   apply (rule_tac id_leq_use_env)
  apply (rule_tac dist_diff_leq_use_env)
  apply (rule_tac diff_leq_use_env)
  apply (rule_tac dist_comp_leq_use_env)
   apply (rule_tac id_leq_use_env)
  apply (rule_tac id_leq_use_env)
  apply (simp add: corr_act_def)
  done

lemma sares_lam_case: "\<lbrakk>well_typed_state s2 env delta; sub_use_env s2  r_f; e1 = AppExp (LamExp x51 x52) x62; well_typed env delta r_s2a x62 t1 r_s3 rx2;
        leq_use_env r_s2 (diff_use_env r_s3 (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex)); (*safe_use_lift rx2 r; safe_type t1 r;*)
        leq_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_s3; disj_use_env rx1 (lift_use_env rx2 r); leq_use_env rx r_s2; leq_use_env r_ex r_s1;
        leq_use_env (app_req rx1 rx2 r tau r_ex) rx; ax = NoAct; well_typed (add_env env (Var x51) t1) delta (add_use_env rxa (Var x51) r) x52 tau r_s' r_end; is_value x62;
        aff_use_env rxa a; safe_subst_exp x52 x51 x62 e2; s1 = s2; leq_use_env rxa r_s1; leq_use_env r_s2a (diff_use_env r_s1 r_exa); leq_use_env rx1 r_s2a;
        leq_use_env r_exa r_s1; leq_use_env (diff_use_env rxa r_exa) rx1; leq_use_env r_s1 r_f \<rbrakk>
       \<Longrightarrow> \<exists>g_ax. well_typed (red_env env g_ax) (red_delta delta g_ax) (exp_red_use_env r_s1 g_ax) e2 tau (end_red_use_env r_s2 g_ax) (end_red_use_env rx g_ax) \<and>
                  well_typed_state s2 (red_env env g_ax) (red_delta delta g_ax) \<and>
                  sub_use_env s2 (exp_red_use_env r_f g_ax) \<and> safe_act s2 (infl_use_env r_f r_s2) g_ax \<and> corr_act ax g_ax"
  apply (case_tac ax)
    apply (auto)
  apply (rule_tac x="NoResAct" in exI)
  apply (auto)
  apply (rule_tac ?r_s2.0="diff_use_env (diff_use_env (comp_use_env r_s3 (cut_use_env r_exa)) (comp_use_env rxa (lift_use_env rx2 r))) (comp_use_env r_exa (comp_use_env r_ex rx1))" and
      rx="diff_use_env (app_req rxa rx2 r tau empty_use_env) (comp_use_env r_exa (comp_use_env r_ex rx1))" in well_typed_simul_end_perm)
     apply (rule_tac well_typed_diff_end_perm)
      apply (rule_tac sares_lam_helper)
       apply (auto)
      apply (rule_tac x="x51" and t="t1" and ?rx1.0="rxa" and r="r" and ?e1.0="x52" and r_s'="r_s'" and r_end="r_end"
    and e'="x62" and ?r_s2.0="comp_use_env r_s2a (cut_use_env r_exa)" and ?r_s3.0="comp_use_env r_s3 (cut_use_env r_exa)" and ?rx2.0="rx2" in safe_subst_type_preserve_x)
               apply (auto)
          apply (case_tac x62)
                 apply (auto)
            apply (case_tac x3)
             apply (auto)
           apply (case_tac x71)
                 apply (auto)
           apply (case_tac x1)
                      apply (auto)
          apply (rule_tac well_typed_comp_perms_gen)
           apply (auto)
          apply (rule_tac r_s="r_s1" in mini_disj_strong_use_env)
           apply (rule_tac r_sb="diff_use_env r_s1 r_exa" in trans_leq_use_env)
            apply (rule_tac dist_diff_leq_use_env_gen)
             apply (rule_tac id_leq_use_env)
            apply (rule_tac self_cut_leq_use_env)
           apply (simp)
          apply (rule_tac strong_cut_use_env)
         apply (rule_tac wts_well_formed_delta)
         apply (auto)
        apply (rule_tac dist_comp_leq_use_env)
         apply (rule_tac r_sb="diff_use_env r_s1 r_exa" in trans_leq_use_env)
          apply (rule_tac self_diff_leq_use_env)
         apply (simp)
        apply (rule_tac cut_leq_use_env)
        apply (simp)
       apply (rule_tac dist_comp_leq_use_env)
        apply (rule_tac st_diff_comp_leq_use_env)
        apply (rule_tac r_sb="diff_use_env rxa r_exa" in trans_leq_use_env)
         apply (rule_tac r_sb="comp_use_env rx1 (lift_use_env rx2 r)" in trans_leq_use_env)
          apply (simp)
         apply (rule_tac comp_leq_use_env1)
         apply (simp)
        apply (rule_tac diff_cut_leq_use_env)
        apply (rule_tac id_leq_use_env)
       apply (rule_tac r_sb="comp_use_env rx1 (lift_use_env rx2 r)" in trans_leq_use_env)
        apply (rule_tac comp_leq_use_env1)
        apply (simp)
       apply (rule_tac self_comp_leq_use_env2)
    (* the last thing we have to do is show that rxa is disjoint from rx2. the idea is that rxa is contained in rx1 + cut r_exa. *)
      apply (rule_tac r_s="comp_use_env rx1 (cut_use_env r_exa)" in disj_leq_use_env1)
       apply (rule_tac disj_comp_use_env1)
        apply (simp)
       apply (rule_tac r_s="r_s2a" in disj_leq_use_env2)
        apply (simp add: disj_use_env_def)
        apply (auto)
         apply (rule_tac r_s="r_s1" in swp_mini_disj_use_env)
         apply (rule_tac r_sb="diff_use_env r_s1 r_exa" in trans_leq_use_env)
          apply (rule_tac dist_diff_leq_use_env_gen)
           apply (rule_tac id_leq_use_env)
          apply (rule_tac self_cut_leq_use_env)
         apply (simp)
        apply (rule_tac r_s="r_s1" in mini_disj_strong_use_env)
         apply (rule_tac r_sb="diff_use_env r_s1 r_exa" in trans_leq_use_env)
          apply (rule_tac dist_diff_leq_use_env_gen)
           apply (rule_tac id_leq_use_env)
          apply (rule_tac self_cut_leq_use_env)
         apply (simp)
        apply (rule_tac strong_cut_use_env)
       apply (rule_tac r_sb="comp_use_env rx1 (lift_use_env rx2 r)" in trans_leq_use_env)
        apply (rule_tac r_sb="r_s3" in trans_leq_use_env)
         apply (rule_tac well_typed_perm_leq)
         apply (auto)
       apply (rule_tac self_comp_leq_use_env2)
      apply (rule_tac st_diff_comp_leq_use_env)
      apply (rule_tac r_sb="diff_use_env rxa r_exa" in trans_leq_use_env)
       apply (simp)
      apply (rule_tac diff_cut_leq_use_env)
      apply (rule_tac id_leq_use_env)
     apply (rule_tac well_typed_state_non_prim_env)
      apply (auto)
    (* - proving initial boundary changes *)
    apply (rule_tac dist_comp_leq_use_env)
     apply (simp)
    apply (rule_tac dist_comp_leq_use_env)
     apply (simp)
    apply (rule_tac r_sb="r_s2a" in trans_leq_use_env)
     apply (rule_tac r_sb="diff_use_env r_s1 r_exa" in trans_leq_use_env)
      apply (rule_tac self_diff_leq_use_env)
     apply (auto)
   (*apply (rule_tac r_sb="diff_use_env r_s3 (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex)" in trans_leq_use_env)*)
   apply (rule_tac r_sb="diff_use_env (diff_use_env r_s3 (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex)) r_exa" in trans_leq_use_env)
    apply (rule_tac fold_dcl_use_env)
    apply (rule_tac dist_diff_leq_use_env_gen)
     apply (rule_tac self_comp_leq_use_env1)
    apply (rule_tac dist_comp_leq_use_env)
     apply (rule_tac dist_comp_leq_use_env)
      apply (rule_tac r_sb="comp_use_env rx1 r_exa" in trans_leq_use_env)
       apply (rule_tac dist_comp_leq_use_env)
        apply (rule_tac comp_leq_use_env1)
        apply (rule_tac comp_leq_use_env1)
        apply (rule_tac self_comp_leq_use_env1)
       apply (rule_tac self_comp_leq_use_env2)
      apply (rule_tac st_diff_comp_leq_use_env)
      apply (simp)
     apply (rule_tac comp_leq_use_env1)
     apply (rule_tac comp_leq_use_env1)
     apply (rule_tac self_comp_leq_use_env2)
    apply (rule_tac dist_comp_leq_use_env)
     apply (rule_tac self_comp_leq_use_env2)
    apply (rule_tac comp_leq_use_env1)
    apply (rule_tac dist_comp_leq_use_env)
     apply (rule_tac self_comp_leq_use_env2)
    apply (rule_tac comp_leq_use_env1)
    apply (rule_tac self_comp_leq_use_env1)
   apply (rule_tac mini_disj_diff_leq_use_env)
    apply (simp)
   apply (rule_tac r_s="diff_use_env r_s1 r_exa" in mini_disj_leq_use_env2)
    apply (rule_tac mini_disj_diff_use_env)
   apply (rule_tac r_sb="r_s2a" in trans_leq_use_env)
    apply (simp)
   apply (rule_tac diff_leq_use_env)
   apply (rule_tac well_typed_perm_leq)
   apply (auto)
    (* - secondary boundary change. *)
  apply (simp add: app_req_def)
  apply (auto)
   apply (rule_tac diff_leq_use_env)
   apply (rule_tac leq_empty_use_env)
  apply (rule_tac r_sb="diff_use_env (comp_use_env rx1 rx2) (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex)" in trans_leq_use_env)
   apply (simp)
  apply (rule_tac unroll_dcl_use_env)
  apply (rule_tac lhs_flip_use_env)
  apply (rule_tac lhs_unroll_dcl_use_env)
  apply (rule_tac dist_diff_leq_use_env)
  apply (rule_tac rhs_flip_use_env)
  apply (rule_tac rhs_unroll_dcl_use_env)
  apply (rule_tac dist_diff_leq_use_env)
  apply (rule_tac lhs_fold_dcl_use_env)
  apply (rule_tac lhs_flip_use_env)
  apply (rule_tac lhs_unroll_dcl_use_env)
  apply (rule_tac dist_diff_leq_use_env_gen)
   apply (rule_tac lhs_dist_dcl_use_env)
   apply (rule_tac dist_comp_leq_use_env)
    apply (rule_tac comp_leq_use_env1)
    apply (simp)
   apply (rule_tac comp_leq_use_env2)
   apply (rule_tac self_diff_leq_use_env)
  apply (rule_tac comp_leq_use_env1)
  apply (rule_tac self_comp_leq_use_env2)
  apply (simp add: corr_act_def)
  done

lemma empty_infl_use_env: "infl_use_env r_s r_s = empty_use_env"
  apply (case_tac "\<forall> x. infl_use_env r_s r_s x = empty_use_env x")
   apply (auto)
  apply (simp add: infl_use_env_def)
  apply (simp add: empty_use_env_def)
  apply (case_tac "r_s x")
    apply (auto)
  done

lemma flat_infl_sexp_wp: "\<lbrakk> well_typed env delta r_s e tau r_s rx; well_formed_delta env delta; is_value e \<rbrakk> \<Longrightarrow> well_typed env delta rx e tau rx rx"
  apply (cut_tac env="env" and ?r_s1.0="r_s" and e="e" and rx="rx" in infl_sexp_wp)
    apply (auto)
   apply (rule_tac value_is_sexp)
   apply (auto)
  apply (cut_tac r_s="r_s" in empty_infl_use_env)
  apply (auto)
  apply (cut_tac r="rx" in comp_empty_use_env2)
  apply (auto)
  done

lemma cancel_strong_leq_use_env: "\<lbrakk> strong_use_env r_x \<rbrakk> \<Longrightarrow> leq_use_env (diff_use_env r_x r_x) r_s"
  apply (simp add: strong_use_env_def)
  apply (simp add: leq_use_env_def)
  apply (simp add: diff_use_env_def)
  apply (auto)
  apply (erule_tac x="x" in allE)
  apply (case_tac "r_x x")
    apply (auto)
  done

lemma infl_strong_use_env: "strong_use_env (infl_use_env r_s r_x)"
  apply (simp add: strong_use_env_def)
  apply (simp add: infl_use_env_def)
  done

lemma strong_lift_use_env: "\<lbrakk> strong_use_env r_s \<rbrakk> \<Longrightarrow> lift_use_env r_s r = r_s"
  apply (case_tac "\<forall> x. lift_use_env r_s r x = r_s x")
   apply (auto)
  apply (simp add: strong_use_env_def)
  apply (erule_tac x="x" in allE)
  apply (case_tac r)
    apply (auto)
  apply (case_tac "r_s x")
    apply (auto)
  done
(*
lemma proper_op: "\<lbrakk> app_op xop c e \<rbrakk> \<Longrightarrow> proper_exp rs_map e"
  apply (simp add: proper_exp_def)
  apply (case_tac xop)
       apply (auto)
  done
  *)
lemma safe_app_red_exp_strict: "\<lbrakk> well_typed env delta r_s1 e1 tau r_s2 rx; well_typed_state s1 env delta;
  sub_use_env s1 r_f; leq_use_env r_s1 r_f; app_red_exp are (s1, e1) ax (s2, e2) \<rbrakk> \<Longrightarrow> (\<exists> g_ax.
  well_typed (red_env env g_ax) (red_delta delta g_ax) (exp_red_use_env r_s1 g_ax) e2 tau (end_red_use_env r_s2 g_ax) (end_red_use_env rx g_ax) \<and>
  (*red_env env ax env' \<and> *)well_typed_state s2 (red_env env g_ax) (red_delta delta g_ax) \<and>
  sub_use_env s2 (exp_red_use_env r_f g_ax) \<and> safe_act s1 (infl_use_env r_f r_s2) g_ax \<and> corr_act ax g_ax)"
  apply (case_tac are)
        apply (auto)
    (* lam case *)
        apply (rule_tac sares_lam_case)
                      apply (auto)
    (* fix-point case *)
       apply (rule_tac r_s2a="r_s2a" and ?r_s3.0="r_s3" in sares_fix_case)
                      apply (auto)
       apply (rule_tac x="rxa" in exI)
       apply (auto)
    (* remaining const cases. the idea is that any "destructive" uses should have had
      end perms removes to begin with, so red_use_env should be fine. *)
      apply (rule_tac ?r_s1.0="r_s1" and ?r_s2.0="r_s3" and ?rx1.0="rx1" and ?rx2.0="rx2" in safe_app_con_case)
             apply (auto)
       apply (rule_tac ?r_s1.0="r_s2a" in well_typed_incr_start_perm)
        apply (auto)(*
      apply (rule_tac r_sb="diff_use_env r_s3 (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex)" in trans_leq_use_env)
       apply (rule_tac lhs_unroll_dcl_use_env)
       apply (rule_tac self_diff_leq_use_env)
      apply (simp)*)
    (* op case *)
     apply (case_tac "ax \<noteq> NoAct")
      apply (auto)
     apply (rule_tac x="NoResAct" in exI)
     apply (auto)
     apply (rule_tac ?r_s2.0="r_s1" and rx="empty_use_env" in well_typed_simul_end_perm)
        apply (rule_tac safe_app_op_case)
         apply (auto)
      apply (rule_tac r_sb="diff_use_env r_s3 (comp_use_env (comp_use_env rx1 (lift_use_env rx2 r)) r_ex)" in trans_leq_use_env)
       apply (rule_tac r_sb="r_s2a" in trans_leq_use_env)
        apply (auto)
      apply (rule_tac diff_leq_use_env)
      apply (simp)
     apply (rule_tac leq_empty_use_env)
  apply (simp add: corr_act_def)
    (* if case 1 *)
    apply (rule_tac x="NoResAct" in exI)
    apply (case_tac ax)
      apply (auto)
    apply (rule_tac ?r_s1.0="r_s2a" in well_typed_incr_start_perm)
     apply (auto)
    apply (rule_tac rx="rx1" in well_typed_incr_req)
      apply (simp)
     apply (rule_tac self_comp_leq_use_env1)
    apply (rule_tac dist_comp_leq_use_env)
     apply (rule_tac well_typed_perm_leqx)
     apply (auto)
    apply (rule_tac well_typed_perm_leqx)
     apply (auto)
  apply (simp add: corr_act_def)
    (* if case 2 *)
   apply (rule_tac x="NoResAct" in exI)
   apply (auto)
   apply (case_tac ax)
    apply (auto)
   apply (rule_tac ?r_s1.0="r_s2a" in well_typed_incr_start_perm)
    apply (auto)
  apply (rule_tac rx="rx2" in well_typed_incr_req)
     apply (simp)
    apply (rule_tac self_comp_leq_use_env2)
   apply (rule_tac dist_comp_leq_use_env)
    apply (rule_tac well_typed_perm_leqx)
    apply (auto)
   apply (rule_tac well_typed_perm_leqx)
   apply (auto)
  apply (simp add: corr_act_def)
    (* cv case *)
  apply (rule_tac sares_cv_case)
    apply (auto)
  done

lemma sares_valid: "valid_reduct app_red_exp"
  apply (simp add: valid_reduct_def)
  apply (auto)
  apply (cut_tac env="env" and ?r_s1.0="r_s1" and ?e1.0="e1" and tau="tau" and ?r_s2.0="r_s2" and rx="rx" and
      ?s1.0="s1" and ax="ax" and ?s2.0="s2" and ?e2.0="e2" in safe_app_red_exp_strict)
       apply (auto)
  done

end


           (*-------------------------------------------*
            |        CSP-Prover on Isabelle2005         |
            |              Februaru 2006                |
            |                 March 2007  (modified)    |
            |                 August 2007  (modified)   |
            |                                           |
            |        Yoshinao Isobe (AIST JAPAN)        |
            *-------------------------------------------*)

theory FNF_F_sf_par
imports FNF_F_sf_induct FNF_F_sf_ext
begin

(*  The following simplification rules are deleted in this theory file *)
(*  because they unexpectly rewrite UnionT and InterT.                 *)
(*                  disj_not1: (~ P | Q) = (P --> Q)                   *)

declare disj_not1 [simp del]

(*  The following simplification rules are deleted in this theory file *)
(*       P (if Q then x else y) = ((Q --> P x) & (~ Q --> P y))        *)
(* Isabelle 2017: split_if --> if_split *)

declare if_split  [split del]

(*****************************************************************

         1. full sequentialization for Parallel (P1 |[X]| DIV)
         2. full sequentialization for Parallel (P1 |[X]| SKIP)
         3. full sequentialization for Parallel (P1 |[X]| P2)

 *****************************************************************)

(*============================================================*
 |                                                            |
 |                Parallel (P |[X]| DIV)                      |
 |                                                            |
 *============================================================*)

definition
  Pfun_Parallel_DIV :: "'a set => (('p,'a) proc => ('p,'a) proc)"
  where
  Pfun_Parallel_DIV_def :
    "Pfun_Parallel_DIV X == (%P1. P1 |[X]| DIV)"

definition
  SP_step_Parallel_DIV ::
   "'a set => ('a set => ('a => ('p,'a) proc) => ('p,'a) proc => ('a => ('p,'a) proc) => ('p,'a) proc)"
  where
  SP_step_Parallel_DIV_def :
    "SP_step_Parallel_DIV X == (%A1 Pf1 Q1 SPf.
                               (? :(A1-X) -> SPf) [+] DIV)"

definition
  fsfF_Parallel_DIV :: "'a set => ('p,'a) proc => ('p,'a) proc"
  where
  fsfF_Parallel_DIV_def :
    "fsfF_Parallel_DIV X == (%P1.
       (fsfF_induct1 (Pfun_Parallel_DIV X)
                     (SP_step_Parallel_DIV X) P1))"

(*------------------------------------------------------------*
 |                        in fsfF_proc                        |
 *------------------------------------------------------------*)

lemma fsfF_Parallel_DIV_in:
    "P1 : fsfF_proc
     ==> fsfF_Parallel_DIV X P1 : fsfF_proc"
apply (simp add: fsfF_Parallel_DIV_def)
apply (rule fsfF_induct1_in)
apply (simp_all add: SP_step_Parallel_DIV_def
                     fsfF_proc.intros)
done

(*------------------------------------------------------------*
 |             syntactical transformation to fsfF             |
 *------------------------------------------------------------*)

lemma cspF_fsfF_Parallel_DIV_eqF:
    "P1 |[X]| DIV =F fsfF_Parallel_DIV X P1"
apply (simp add: fsfF_Parallel_DIV_def)
apply (rule cspF_rw_right)
apply (rule cspF_fsfF_induct1_eqF[THEN cspF_sym])
apply (simp_all add: Pfun_Parallel_DIV_def
                     SP_step_Parallel_DIV_def)
apply (rule cspF_Dist_nonempty, simp)

apply (rule cspF_rw_left)
apply (rule cspF_SKIP_or_DIV_or_STOP_Parallel_Ext_choice)
apply (simp)
apply (rule cspF_rw_left)
apply (rule cspF_SKIP_DIV)
apply (simp)
apply (rule cspF_decompo | rule cspF_reflex | simp)+
done

(*============================================================*
 |                                                            |
 |                Parallel (P |[X]| SKIP)                     |
 |                                                            |
 *============================================================*)

definition
  Pfun_Parallel_SKIP :: "'a set => (('p,'a) proc => ('p,'a) proc)"
  where
  Pfun_Parallel_SKIP_def :
    "Pfun_Parallel_SKIP X == (%P1. P1 |[X]| SKIP)"

definition
  SP_step_Parallel_SKIP ::
   "'a set => ('a set => ('a => ('p,'a) proc) => ('p,'a) proc =>
     ('a => ('p,'a) proc) => ('p,'a) proc)"
  where
  SP_step_Parallel_SKIP_def :
    "SP_step_Parallel_SKIP X == (%A1 Pf1 Q1 SPf.
                                (? :(A1-X) -> SPf) [+] Q1)"

definition
  fsfF_Parallel_SKIP  :: "'a set => ('p,'a) proc => ('p,'a) proc"
  where
  fsfF_Parallel_SKIP_def :
    "fsfF_Parallel_SKIP X == (%P1.
       (fsfF_induct1 (Pfun_Parallel_SKIP X)
                     (SP_step_Parallel_SKIP X) P1))"

(*------------------------------------------------------------*
 |                        in fsfF_proc                        |
 *------------------------------------------------------------*)

lemma fsfF_Parallel_SKIP_in:
    "P1 : fsfF_proc
     ==> fsfF_Parallel_SKIP X P1 : fsfF_proc"
apply (simp add: fsfF_Parallel_SKIP_def)
apply (rule fsfF_induct1_in)
apply (simp_all add: SP_step_Parallel_SKIP_def
                     fsfF_proc.intros)
done

(*------------------------------------------------------------*
 |             syntactical transformation to fsfF             |
 *------------------------------------------------------------*)

lemma cspF_fsfF_Parallel_SKIP_eqF:
    "P1 |[X]| SKIP =F fsfF_Parallel_SKIP X P1"
apply (simp add: fsfF_Parallel_SKIP_def)
apply (rule cspF_rw_right)
apply (rule cspF_fsfF_induct1_eqF[THEN cspF_sym])
apply (simp_all add: Pfun_Parallel_SKIP_def
                     SP_step_Parallel_SKIP_def)

apply (rule cspF_Dist_nonempty, simp)

apply (rule cspF_rw_left)
apply (rule cspF_SKIP_or_DIV_or_STOP_Parallel_Ext_choice)
apply (simp)
apply (simp)
apply (rule cspF_decompo | rule cspF_reflex | simp)+
done

(*============================================================*
 |                                                            |
 |              Parallel (P |[X]| SKIP or DIV)                |
 |                                                            |
 *============================================================*)

definition
  fsfF_Parallel_SKIP_DIV  :: "'a set => ('p,'a) proc => ('p,'a) proc => ('p,'a) proc"

where
  fsfF_Parallel_SKIP_DIV_def :
    "fsfF_Parallel_SKIP_DIV X P1 P2 ==
        if (P2 = SKIP) then fsfF_Parallel_SKIP X P1
        else if (P2 = DIV) then fsfF_Parallel_DIV X P1
        else (P1 |[X]| P2)"

(*------------------------------------------------------------*
 |                        in fsfF_proc                        |
 *------------------------------------------------------------*)

lemma fsfF_Parallel_SKIP_DIV_in:
    "[| P1 : fsfF_proc ; P2 = SKIP | P2 = DIV |]
     ==> fsfF_Parallel_SKIP_DIV X P1 P2 : fsfF_proc"
apply (simp add: fsfF_Parallel_SKIP_DIV_def)
apply (erule disjE)
apply (simp add: fsfF_Parallel_SKIP_in)
apply (simp add: fsfF_Parallel_DIV_in)
done

(*------------------------------------------------------------*
 |             syntactical transformation to fsfF             |
 *------------------------------------------------------------*)

lemma cspF_fsfF_Parallel_SKIP_DIV_eqF:
    "P1 |[X]| P2 =F fsfF_Parallel_SKIP_DIV X P1 P2"
apply (simp add: fsfF_Parallel_SKIP_DIV_def)
apply (simp split: if_split)
apply (intro conjI impI)
apply (simp add: cspF_fsfF_Parallel_DIV_eqF)
apply (simp add: cspF_fsfF_Parallel_SKIP_eqF)
done

lemmas cspF_fsfF_Parallel_SKIP_DIV_eqF_sym =
       cspF_fsfF_Parallel_SKIP_DIV_eqF[THEN cspF_sym]

(*============================================================*
 |                                                            |
 |            Genaralized Parallel (P |[X]| Q)                |
 |                                                            |
 *============================================================*)

definition
  Pfun_Parallel :: "'a set => (('p,'a) proc => ('p,'a) proc => ('p,'a) proc)"
  where
  Pfun_Parallel_def :
    "Pfun_Parallel X == (%P1 P2. P1 |[X]| P2)"

definition
  SP_step_Parallel ::
   "'a set =>
    ('a set => ('a => ('p,'a) proc) => ('p,'a) proc =>
     'a set => ('a => ('p,'a) proc) => ('p,'a) proc =>
    ('a => ('p,'a) proc) => ('a => ('p,'a) proc) => ('a => ('p,'a) proc) => ('p,'a) proc)"
  where
  SP_step_Parallel_def :
    "SP_step_Parallel X == (%A1 Pf1 Q1 A2 Pf2 Q2 SPf SPf1 SPf2.
    (if (Q1 = STOP & Q2 = STOP) then
     ((? a:((X Int A1 Int A2) Un (A1 - X) Un (A2 - X))
          -> (if (a : X) then (SPf a)
                 else if (a : A1 & a : A2)
                      then ((SPf1 a) |~|seq (SPf2 a))
                 else if (a : A1) then (SPf1 a)
                 else (SPf2 a))) [+] STOP)
    else if (Q1 = STOP) then
    (((? a:((X Int A1 Int A2) Un (A1 - X) Un (A2 - X))
        -> (if (a : X) then (SPf a)
               else if (a : A1 & a : A2)
                    then ((SPf1 a) |~|seq (SPf2 a))
               else if (a : A1) then (SPf1 a)
               else (SPf2 a))) [+] STOP)
     [>seq
     (fsfF_Parallel_SKIP_DIV X (((? :A1 -> Pf1) [+] Q1)) Q2))

    else if (Q2 = STOP) then
    (((? a:((X Int A1 Int A2) Un (A1 - X) Un (A2 - X))
        -> (if (a : X) then (SPf a)
               else if (a : A1 & a : A2)
                    then ((SPf1 a) |~|seq (SPf2 a))
               else if (a : A1) then (SPf1 a)
               else (SPf2 a))) [+] STOP)
     [>seq
     (fsfF_Parallel_SKIP_DIV X (((? :A2 -> Pf2) [+] Q2)) Q1))

   else
    (((? a:((X Int A1 Int A2) Un (A1 - X) Un (A2 - X))
        -> (if (a : X) then (SPf a)
               else if (a : A1 & a : A2)
                    then ((SPf1 a) |~|seq (SPf2 a))
               else if (a : A1) then (SPf1 a)
               else (SPf2 a))) [+] STOP)
     [>seq
     ((fsfF_Parallel_SKIP_DIV X
             (((? :A2 -> Pf2) [+] Q2)) Q1) |~|seq
      (fsfF_Parallel_SKIP_DIV X
             (((? :A1 -> Pf1) [+] Q1)) Q2)))))"

definition
  fsfF_Parallel  :: "('p,'a) proc => 'a set => ('p,'a) proc => ('p,'a) proc"
                          ("(1_ /|[_]|seq _)" [76,0,77] 76)
  where
  fsfF_Parallel_def :
    "P1 |[X]|seq P2 ==
       (fsfF_induct2 (Pfun_Parallel X) (SP_step_Parallel X) P1 P2)"

(*------------------------------------------------------------*
 |                        in fsfF_proc                        |
 *------------------------------------------------------------*)

lemma fsfF_Parallel_in_lm:
  "[| ALL a:A1. Pf1 a : fsfF_proc;
      ALL a:A2. Pf2 a : fsfF_proc;
      ALL a:A1 Int A2. SPf a : fsfF_proc;
      ALL a:A1. SPf1 a : fsfF_proc;
      ALL a:A2. SPf2 a : fsfF_proc;
      Q1 = SKIP | Q1 = DIV | Q1 = STOP; Q2 = SKIP | Q2 = DIV | Q2 = STOP |]
   ==> SP_step_Parallel X A1 Pf1 Q1 A2 Pf2 Q2 SPf SPf1 SPf2 : fsfF_proc"
apply (simp_all add: SP_step_Parallel_def)

(* Q1 = STOP & Q2 = STOP *)
apply (case_tac "Q1 = STOP & Q2 = STOP")
apply (simp)
apply (rule fsfF_proc.intros)
apply (rule ballI)
apply (simp split: if_split)
apply (intro conjI ballI impI)
apply (simp_all)
apply (simp add: fsfF_Int_choice_in)

(* Q1 = STOP *)
apply (subgoal_tac "~ (Q1 = STOP & Q2 = STOP)")
apply (simp (no_asm_simp))
apply (case_tac "Q1 = STOP")
apply (simp)
apply (rule fsfF_Timeout_in)

apply (rule fsfF_proc.intros)
apply (rule ballI)
apply (simp split: if_split)
apply (intro conjI ballI impI)
apply (simp_all)
apply (simp add: fsfF_Int_choice_in)
apply (rule fsfF_Parallel_SKIP_DIV_in)

apply (simp add: fsfF_proc.intros)
apply (simp)

(* Q2 = STOP *)
apply (case_tac "Q2 = STOP")
apply (simp)
apply (rule fsfF_Timeout_in)

apply (rule fsfF_proc.intros)
apply (rule ballI)
apply (simp split: if_split)
apply (intro conjI ballI impI)
apply (simp_all)
apply (simp add: fsfF_Int_choice_in)
apply (rule fsfF_Parallel_SKIP_DIV_in)
apply (simp add: fsfF_proc.intros)
apply (simp)

(* Q1 = SKIP | DIV , Q2 = SKIP | DIV *)
apply (rule fsfF_Timeout_in)

apply (rule fsfF_proc.intros)
apply (rule ballI)
apply (simp split: if_split)
apply (intro conjI ballI impI)
apply (simp_all)
apply (simp add: fsfF_Int_choice_in)

apply (rule fsfF_Int_choice_in)
apply (rule fsfF_Parallel_SKIP_DIV_in)
apply (simp add: fsfF_proc.intros)
apply (simp)

apply (rule fsfF_Parallel_SKIP_DIV_in)
apply (simp add: fsfF_proc.intros)
apply (simp)
done

(*------------------------------------*
 |                 in                 |
 *------------------------------------*)

lemma fsfF_Parallel_in:
    "[| P1 : fsfF_proc ; P2 : fsfF_proc |]
     ==> P1 |[X]|seq P2 : fsfF_proc"
apply (simp add: fsfF_Parallel_def)
apply (rule fsfF_induct2_in)
apply (simp_all)
apply (simp add: fsfF_Parallel_in_lm)
done

(*------------------------------------------------------------*
 |             syntactical transformation to fsfF             |
 *------------------------------------------------------------*)

lemma cspF_fsfF_Parallel_eqF:
    "P1 |[X]| P2 =F P1 |[X]|seq P2"
apply (simp add: fsfF_Parallel_def)
apply (rule cspF_rw_right)
apply (rule cspF_fsfF_induct2_eqF[THEN cspF_sym])
apply (simp_all add: Pfun_Parallel_def)
apply (rule cspF_Dist_nonempty, simp)
apply (rule cspF_Dist_nonempty, simp)

apply (simp add: SP_step_Parallel_def)

(* Q1 = STOP & Q2 = STOP *)
apply (case_tac "Q1 = STOP & Q2 = STOP")
apply (simp)

apply (rule cspF_rw_right)
apply (rule cspF_unit)

apply (rule cspF_rw_left)
apply (rule cspF_decompo)
apply (simp)
apply (rule cspF_unit)
apply (rule cspF_unit)

apply (rule cspF_rw_left)
apply (rule cspF_step)
apply (rule cspF_decompo)
apply (simp)

apply (simp split: if_split)
apply (intro conjI impI)
apply (simp)

apply (rule cspF_rw_left, rule cspF_IF)+

apply (rule cspF_rw_right)
apply (rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])

 apply (rule cspF_decompo)
 apply (rule cspF_decompo)
 apply (simp)
 apply (simp)
 apply (rule cspF_rw_right)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)

 apply (rule cspF_decompo)
 apply (simp)
 apply (simp)
 apply (rule cspF_rw_right)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)
 apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_rw_right)
 apply (rule cspF_decompo)
 apply (simp)
 apply (rule cspF_reflex)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_rw_right)
 apply (rule cspF_decompo)
 apply (simp)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)
 apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_rw_right)
 apply (rule cspF_decompo)
 apply (simp)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)
 apply (rule cspF_reflex)

(* Q1 = STOP *)
apply (simp (no_asm_simp))
apply (case_tac "Q1 = STOP")
apply (simp)

apply (rule cspF_rw_left)
apply (rule cspF_decompo)
apply (simp)
apply (rule cspF_Ext_choice_unit)
apply (rule cspF_reflex)

apply (rule cspF_rw_left)
apply (rule cspF_SKIP_or_DIV_resolve)
apply (fast)

apply (rule cspF_rw_right)
apply (rule cspF_fsfF_Timeout_eqF[THEN cspF_sym])
apply (rule cspF_decompo)
apply (rule cspF_decompo)

apply (rule cspF_rw_right)
apply (rule cspF_unit)
apply (rule cspF_decompo)
apply (simp)

(* IF --> if *)
apply (simp split: if_split)
apply (intro conjI impI)
apply (simp)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_rw_right)
apply (rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])

 apply (rule cspF_decompo)
 apply (simp)
 apply (rule cspF_rw_right)
 apply (rule cspF_decompo)
 apply (simp)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)
 apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
 apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_rw_right)
 apply (rule cspF_decompo)
 apply (simp)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)
 apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_rw_right)
 apply (rule cspF_decompo)
 apply (simp)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)
 apply (rule cspF_reflex)

apply (rule cspF_reflex)

apply (rule cspF_rw_right)
apply (rule cspF_fsfF_Parallel_SKIP_DIV_eqF[THEN cspF_sym])
apply (rule cspF_rw_right)
 apply (rule cspF_decompo)
 apply (simp)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)
 apply (rule cspF_reflex)

(* Q2 = STOP *)
apply (case_tac "Q2 = STOP")
apply (simp)

apply (rule cspF_rw_left)
apply (rule cspF_decompo)
apply (simp)
apply (rule cspF_reflex)
apply (rule cspF_unit)

apply (rule cspF_rw_left)
apply (rule cspF_SKIP_or_DIV_resolve)
apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_fsfF_Timeout_eqF[THEN cspF_sym])
apply (rule cspF_decompo)
apply (rule cspF_decompo)

apply (rule cspF_rw_right)
apply (rule cspF_unit)
apply (rule cspF_decompo)
apply (simp)

(* IF --> if *)
apply (simp split: if_split)
apply (intro conjI impI)
apply (simp)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_rw_right)
apply (rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])

 apply (rule cspF_decompo)
 apply (rule cspF_rw_right)
 apply (rule cspF_decompo)
 apply (simp)
 apply (rule cspF_reflex)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)
 apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_rw_right)
 apply (rule cspF_decompo)
 apply (simp)
 apply (rule cspF_reflex)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
 apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
 apply (rule cspF_reflex)

apply (rule cspF_reflex)

apply (rule cspF_rw_right)
apply (rule cspF_fsfF_Parallel_SKIP_DIV_eqF[THEN cspF_sym])
apply (rule cspF_rw_right)
 apply (rule cspF_decompo)
 apply (simp)
 apply (rule cspF_unit)
 apply (rule cspF_reflex)
 apply (rule cspF_commut)

(* DIV or SKIP *)
apply (simp)

apply (rule cspF_rw_left)
apply (rule cspF_SKIP_or_DIV_resolve)
apply (simp)
apply (simp)
apply (rule cspF_rw_right)
apply (rule cspF_fsfF_Timeout_eqF[THEN cspF_sym])
apply (rule cspF_decompo)
apply (rule cspF_decompo)

apply (rule cspF_rw_right)
apply (rule cspF_unit)
apply (rule cspF_decompo)
apply (simp)

(* IF --> if *)
apply (simp split: if_split)
apply (intro conjI impI)
apply (simp)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_rw_right)
apply (rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])
apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_reflex)

apply (rule cspF_rw_left, rule cspF_IF)+
apply (rule cspF_reflex)

apply (rule cspF_reflex)

apply (rule cspF_rw_right)
apply (rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])
apply (rule cspF_decompo)

 apply (rule cspF_rw_right)
 apply (rule cspF_fsfF_Parallel_SKIP_DIV_eqF[THEN cspF_sym])
 apply (rule cspF_commut)
 apply (rule cspF_rw_right)
 apply (rule cspF_fsfF_Parallel_SKIP_DIV_eqF[THEN cspF_sym])
 apply (rule cspF_reflex)

(* congruence *)

apply (simp add: SP_step_Parallel_def)

apply (simp split: if_split)
apply (intro conjI impI)

apply (rule cspF_decompo, simp)
apply (rule cspF_decompo, simp)
apply (simp split: if_split)
apply (intro conjI impI)
apply (simp_all)
apply (rule cspF_rw_left, rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])
apply (rule cspF_rw_right, rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])
apply (rule cspF_decompo)
apply (simp_all)

apply (rule cspF_rw_left,  rule cspF_fsfF_Timeout_eqF[THEN cspF_sym])
apply (rule cspF_rw_right, rule cspF_fsfF_Timeout_eqF[THEN cspF_sym])
apply (rule cspF_Timeout_cong)
apply (rule cspF_decompo, simp)
apply (rule cspF_decompo, simp)
apply (simp split: if_split)
apply (intro conjI impI)
apply (simp_all)
apply (rule cspF_rw_left, rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])
apply (rule cspF_rw_right, rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])
apply (rule cspF_decompo)
apply (simp_all)

apply (rule cspF_rw_left,  rule cspF_fsfF_Timeout_eqF[THEN cspF_sym])
apply (rule cspF_rw_right, rule cspF_fsfF_Timeout_eqF[THEN cspF_sym])
apply (rule cspF_Timeout_cong)
apply (rule cspF_decompo, simp)
apply (rule cspF_decompo, simp)
apply (simp split: if_split)
apply (intro conjI impI)
apply (simp_all)
apply (rule cspF_rw_left, rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])
apply (rule cspF_rw_right, rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])
apply (rule cspF_decompo)
apply (simp_all)

apply (rule cspF_rw_left,  rule cspF_fsfF_Timeout_eqF[THEN cspF_sym])
apply (rule cspF_rw_right, rule cspF_fsfF_Timeout_eqF[THEN cspF_sym])
apply (rule cspF_Timeout_cong)
apply (rule cspF_decompo, simp)
apply (rule cspF_decompo, simp)
apply (simp split: if_split)
apply (intro conjI impI)
apply (simp_all)
apply (rule cspF_rw_left, rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])
apply (rule cspF_rw_right, rule cspF_fsfF_Int_choice_eqF[THEN cspF_sym])
apply (rule cspF_decompo)
apply (simp_all)
done

(****************** to add them again ******************)

declare if_split    [split]
declare disj_not1   [simp]

end


(*  Title:       CoreC++
    Author:      Daniel Wasserrab
    Maintainer:  Daniel Wasserrab <wasserra at fmi.uni-passau.de>

    Based on the Jinja theory J/WellTypeRT.thy by Tobias Nipkow
*)

section \<open>Runtime Well-typedness\<close>

theory WellTypeRT imports WellType begin

subsection \<open>Run time types\<close>

primrec typeof_h :: "prog \<Rightarrow> heap \<Rightarrow> val \<Rightarrow> ty option" ("_ \<turnstile> typeof\<^bsub>_\<^esub>") where
  "P \<turnstile> typeof\<^bsub>h\<^esub> Unit     = Some Void"
| "P \<turnstile> typeof\<^bsub>h\<^esub> Null     = Some NT"
| "P \<turnstile> typeof\<^bsub>h\<^esub> (Bool b) = Some Boolean"
| "P \<turnstile> typeof\<^bsub>h\<^esub> (Intg i) = Some Integer"
| "P \<turnstile> typeof\<^bsub>h\<^esub> (Ref r)  = (case h (the_addr (Ref r)) of None \<Rightarrow> None
                            | Some(C,S) \<Rightarrow> (if Subobjs P C (the_path(Ref r)) then
                                   Some(Class(last(the_path(Ref r))))
                                            else None))"

lemma type_eq_type: "typeof v = Some T \<Longrightarrow> P \<turnstile> typeof\<^bsub>h\<^esub> v = Some T"
by(induct v)auto

lemma typeof_Void [simp]: "P \<turnstile> typeof\<^bsub>h\<^esub> v = Some Void \<Longrightarrow> v = Unit"
by(induct v,auto split:if_split_asm)

lemma typeof_NT [simp]: "P \<turnstile> typeof\<^bsub>h\<^esub> v = Some NT \<Longrightarrow> v = Null"
by(induct v,auto split:if_split_asm)

lemma typeof_Boolean [simp]: "P \<turnstile> typeof\<^bsub>h\<^esub> v = Some Boolean \<Longrightarrow> \<exists>b. v = Bool b"
by(induct v,auto split:if_split_asm)

lemma typeof_Integer [simp]: "P \<turnstile> typeof\<^bsub>h\<^esub> v = Some Integer \<Longrightarrow> \<exists>i. v = Intg i"
by(induct v,auto split:if_split_asm)

lemma typeof_Class_Subo:
"P \<turnstile> typeof\<^bsub>h\<^esub> v = Some (Class C) \<Longrightarrow>
\<exists>a Cs D S. v = Ref(a,Cs) \<and> h a = Some(D,S) \<and> Subobjs P D Cs \<and> last Cs = C"
by(induct v,auto split:if_split_asm)

subsection \<open>The rules\<close>

inductive
  WTrt :: "[prog,env,heap,expr,     ty     ] \<Rightarrow> bool"
        ("_,_,_ \<turnstile> _ : _"   [51,51,51]50)
  and WTrts :: "[prog,env,heap,expr list,ty list] \<Rightarrow> bool"
        ("_,_,_ \<turnstile> _ [:] _" [51,51,51]50)
  for P :: prog
where

  WTrtNew:
  "is_class P C  \<Longrightarrow>
  P,E,h \<turnstile> new C : Class C"

| WTrtDynCast:
  "\<lbrakk> P,E,h \<turnstile> e : T; is_refT T; is_class P C \<rbrakk>
  \<Longrightarrow> P,E,h \<turnstile> Cast C e : Class C"

| WTrtStaticCast:
  "\<lbrakk> P,E,h \<turnstile> e : T; is_refT T; is_class P C \<rbrakk>
  \<Longrightarrow> P,E,h \<turnstile> \<lparr>C\<rparr>e : Class C"

| WTrtVal:
  "P \<turnstile> typeof\<^bsub>h\<^esub> v = Some T \<Longrightarrow>
  P,E,h \<turnstile> Val v : T"

| WTrtVar:
  "E V = Some T \<Longrightarrow>
  P,E,h \<turnstile> Var V : T"

| WTrtBinOp:
  "\<lbrakk> P,E,h \<turnstile> e\<^sub>1 : T\<^sub>1;  P,E,h \<turnstile> e\<^sub>2 : T\<^sub>2;
     case bop of Eq \<Rightarrow> T = Boolean
               | Add \<Rightarrow> T\<^sub>1 = Integer \<and> T\<^sub>2 = Integer \<and> T = Integer \<rbrakk>
  \<Longrightarrow> P,E,h \<turnstile> e\<^sub>1 \<guillemotleft>bop\<guillemotright> e\<^sub>2 : T"

| WTrtLAss:
  "\<lbrakk> E V = Some T;  P,E,h \<turnstile> e : T'; P \<turnstile> T' \<le> T \<rbrakk>
  \<Longrightarrow> P,E,h \<turnstile> V:=e : T"

| WTrtFAcc:
"\<lbrakk>P,E,h \<turnstile> e : Class C; Cs \<noteq> []; P \<turnstile> C has least F:T via Cs \<rbrakk>
  \<Longrightarrow> P,E,h \<turnstile> e\<bullet>F{Cs} : T"

| WTrtFAccNT:
  "P,E,h \<turnstile> e : NT \<Longrightarrow> P,E,h \<turnstile> e\<bullet>F{Cs} : T"

| WTrtFAss:
"\<lbrakk>P,E,h \<turnstile> e\<^sub>1 : Class C; Cs \<noteq> [];
  P \<turnstile> C has least F:T via Cs; P,E,h \<turnstile> e\<^sub>2 : T'; P \<turnstile> T' \<le> T \<rbrakk>
  \<Longrightarrow> P,E,h \<turnstile> e\<^sub>1\<bullet>F{Cs}:=e\<^sub>2 : T"

| WTrtFAssNT:
  "\<lbrakk> P,E,h \<turnstile> e\<^sub>1 : NT; P,E,h \<turnstile> e\<^sub>2 : T'; P \<turnstile> T' \<le> T \<rbrakk>
  \<Longrightarrow> P,E,h \<turnstile> e\<^sub>1\<bullet>F{Cs}:=e\<^sub>2 : T"

| WTrtCall:
  "\<lbrakk> P,E,h \<turnstile> e : Class C;  P \<turnstile> C has least M = (Ts,T,m) via Cs;
     P,E,h \<turnstile> es [:] Ts'; P \<turnstile> Ts' [\<le>] Ts \<rbrakk>
  \<Longrightarrow> P,E,h \<turnstile> e\<bullet>M(es) : T"

| WTrtStaticCall:
  "\<lbrakk> P,E,h \<turnstile> e : Class C'; P \<turnstile> Path C' to C unique;
     P \<turnstile> C has least M = (Ts,T,m) via Cs;
     P,E,h \<turnstile> es [:] Ts'; P \<turnstile> Ts' [\<le>] Ts \<rbrakk>
  \<Longrightarrow> P,E,h \<turnstile> e\<bullet>(C::)M(es) : T"

| WTrtCallNT:
  "\<lbrakk>P,E,h \<turnstile> e : NT; P,E,h \<turnstile> es [:] Ts\<rbrakk> \<Longrightarrow> P,E,h \<turnstile> Call e Copt M es : T"

| WTrtBlock:
  "\<lbrakk>P,E(V\<mapsto>T),h \<turnstile> e : T'; is_type P T\<rbrakk> \<Longrightarrow>
  P,E,h \<turnstile> {V:T; e} : T'"

| WTrtSeq:
  "\<lbrakk> P,E,h \<turnstile> e\<^sub>1 : T\<^sub>1;  P,E,h \<turnstile> e\<^sub>2 : T\<^sub>2 \<rbrakk>  \<Longrightarrow>  P,E,h \<turnstile> e\<^sub>1;;e\<^sub>2 : T\<^sub>2"

| WTrtCond:
  "\<lbrakk> P,E,h \<turnstile> e : Boolean;  P,E,h \<turnstile> e\<^sub>1 : T;  P,E,h \<turnstile> e\<^sub>2 : T \<rbrakk>
  \<Longrightarrow> P,E,h \<turnstile> if (e) e\<^sub>1 else e\<^sub>2 : T"

| WTrtWhile:
  "\<lbrakk> P,E,h \<turnstile> e : Boolean;  P,E,h \<turnstile> c : T \<rbrakk>
  \<Longrightarrow>  P,E,h \<turnstile> while(e) c : Void"

| WTrtThrow:
  "\<lbrakk>P,E,h \<turnstile> e : T'; is_refT T'\<rbrakk>
 \<Longrightarrow>  P,E,h \<turnstile> throw e : T"

| WTrtNil:
"P,E,h \<turnstile> [] [:] []"

| WTrtCons:
 "\<lbrakk> P,E,h \<turnstile> e : T;  P,E,h \<turnstile> es [:] Ts \<rbrakk> \<Longrightarrow>  P,E,h \<turnstile> e#es [:] T#Ts"

declare
  WTrt_WTrts.intros[intro!]
  WTrtNil[iff]
declare
  WTrtFAcc[rule del] WTrtFAccNT[rule del]
  WTrtFAss[rule del] WTrtFAssNT[rule del]
  WTrtCall[rule del] WTrtCallNT[rule del]

lemmas WTrt_induct = WTrt_WTrts.induct [split_format (complete)]
  and WTrt_inducts = WTrt_WTrts.inducts [split_format (complete)]

subsection\<open>Easy consequences\<close>

inductive_simps [iff]:
  "P,E,h \<turnstile> [] [:] Ts"
  "P,E,h \<turnstile> e#es [:] T#Ts"
  "P,E,h \<turnstile> (e#es) [:] Ts"
  "P,E,h \<turnstile> Val v : T"
  "P,E,h \<turnstile> Var V : T"
  "P,E,h \<turnstile> e\<^sub>1;;e\<^sub>2 : T\<^sub>2"
  "P,E,h \<turnstile> {V:T; e} : T'"

apply(induct_tac es\<^sub>1)
 apply simp
apply clarsimp
apply(erule thin_rl)
apply (rule iffI)
 apply clarsimp
 apply(rule exI)+
 apply(rule conjI)
  prefer 2 apply blast
 apply simp
apply fastforce
done

inductive_cases WTrt_elim_cases[elim!]:
  "P,E,h \<turnstile> new C : T"
  "P,E,h \<turnstile> Cast C e : T"
  "P,E,h \<turnstile> \<lparr>C\<rparr>e : T"
  "P,E,h \<turnstile> e\<^sub>1 \<guillemotleft>bop\<guillemotright> e\<^sub>2 : T"
  "P,E,h \<turnstile> V:=e : T"
  "P,E,h \<turnstile> e\<bullet>F{Cs} : T"
  "P,E,h \<turnstile> e\<bullet>F{Cs} := v : T"
  "P,E,h \<turnstile> e\<bullet>M(es) : T"
  "P,E,h \<turnstile> e\<bullet>(C::)M(es) : T"
  "P,E,h \<turnstile> if (e) e\<^sub>1 else e\<^sub>2 : T"
  "P,E,h \<turnstile> while(e) c : T"
  "P,E,h \<turnstile> throw e : T"

subsection\<open>Some interesting lemmas\<close>

lemma WTrts_Val[simp]:
 "\<And>Ts. (P,E,h \<turnstile> map Val vs [:] Ts) = (map (\<lambda>v. (P \<turnstile> typeof\<^bsub>h\<^esub>) v) vs = map Some Ts)"

apply(induct vs)
 apply fastforce
apply(case_tac Ts)
 apply simp
apply simp
done

lemma WTrt_env_mono:
  "P,E,h \<turnstile> e : T \<Longrightarrow> (\<And>E'. E \<subseteq>\<^sub>m E' \<Longrightarrow> P,E',h \<turnstile> e : T)" and
  "P,E,h \<turnstile> es [:] Ts \<Longrightarrow> (\<And>E'. E \<subseteq>\<^sub>m E' \<Longrightarrow> P,E',h \<turnstile> es [:] Ts)"

apply(induct rule: WTrt_inducts)
apply(simp add: WTrtNew)
apply(fastforce simp: WTrtDynCast)
apply(fastforce simp: WTrtStaticCast)
apply(fastforce simp: WTrtVal)
apply(simp add: WTrtVar map_le_def dom_def)
apply(fastforce simp add: WTrtBinOp)
apply (force simp:map_le_def)
apply(fastforce simp: WTrtFAcc)
apply(simp add: WTrtFAccNT)
apply(fastforce simp: WTrtFAss)
apply(fastforce simp: WTrtFAssNT)
apply(fastforce simp: WTrtCall)
apply(fastforce simp: WTrtStaticCall)
apply(fastforce simp: WTrtCallNT)
apply(fastforce simp: map_le_def)
apply(fastforce)
apply(fastforce simp: WTrtCond)
apply(fastforce simp: WTrtWhile)
apply(fastforce simp: WTrtThrow)
apply(simp add: WTrtNil)
apply(simp add: WTrtCons)
done

lemma WT_implies_WTrt: "P,E \<turnstile> e :: T \<Longrightarrow> P,E,h \<turnstile> e : T"
and WTs_implies_WTrts: "P,E \<turnstile> es [::] Ts \<Longrightarrow> P,E,h \<turnstile> es [:] Ts"

proof(induct rule: WT_WTs_inducts)
  case WTVal thus ?case by (fastforce dest:type_eq_type)
next
  case WTBinOp thus ?case by (fastforce split:bop.splits)
next
  case WTFAcc thus ?case
    by(fastforce intro!:WTrtFAcc dest:Subobjs_nonempty
                  simp:LeastFieldDecl_def FieldDecls_def)
next
  case WTFAss thus ?case
    by(fastforce intro!:WTrtFAss dest:Subobjs_nonempty
                  simp:LeastFieldDecl_def FieldDecls_def)
next
  case WTCall thus ?case by (fastforce intro:WTrtCall)
qed (auto simp del:fun_upd_apply)

end


(*  Title:      HOL/Bali/Type.thy
    Author:     David von Oheimb
*)

subsection \<open>Java types\<close>

theory Type imports Name begin

text \<open>
simplifications:
\begin{itemize}
\item only the most important primitive types
\item the null type is regarded as reference type
\end{itemize}
\<close>

datatype prim_ty        \<comment>\<open>primitive type, cf. 4.2\<close>
        = Void          \<comment>\<open>result type of void methods\<close>
        | Boolean
        | Integer

datatype ref_ty         \<comment>\<open>reference type, cf. 4.3\<close>
        = NullT         \<comment>\<open>null type, cf. 4.1\<close>
        | IfaceT qtname \<comment>\<open>interface type\<close>
        | ClassT qtname \<comment>\<open>class type\<close>
        | ArrayT ty     \<comment>\<open>array type\<close>

and ty                  \<comment>\<open>any type, cf. 4.1\<close>
        = PrimT prim_ty \<comment>\<open>primitive type\<close>
        | RefT  ref_ty  \<comment>\<open>reference type\<close>

abbreviation "NT == RefT NullT"
abbreviation "Iface I == RefT (IfaceT I)"
abbreviation "Class C == RefT (ClassT C)"
abbreviation Array :: "ty \<Rightarrow> ty"  ("_.[]" [90] 90)
  where "T.[] == RefT (ArrayT T)"

definition
  the_Class :: "ty \<Rightarrow> qtname"
  where "the_Class T = (SOME C. T = Class C)" (** primrec not possible here **)

lemma the_Class_eq [simp]: "the_Class (Class C)= C"
by (auto simp add: the_Class_def)

end


theory JVMCFG_wf imports JVMInterpretation "../StaticInter/CFGExit_wf" begin

inductive_set Def :: "wf_jvmprog \<Rightarrow> cfg_node \<Rightarrow> var set"
  for P :: "wf_jvmprog"
  and n :: "cfg_node"
where
  Def_Main_Heap:
  "n = (ClassMain P, MethodMain P, \<lfloor>0\<rfloor>, Return)
  \<Longrightarrow> Heap \<in> Def P n"
| Def_Main_Exception:
  "n = (ClassMain P, MethodMain P, \<lfloor>0\<rfloor>, Return)
  \<Longrightarrow> Exception \<in> Def P n"
| Def_Main_Stack_0:
  "n = (ClassMain P, MethodMain P, \<lfloor>0\<rfloor>, Return)
  \<Longrightarrow> Stack 0 \<in> Def P n"
| Def_Load:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Enter);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = Load idx;
  i = stkLength (P, C, M) pc\<rbrakk>
  \<Longrightarrow> Stack i \<in> Def P n"
| Def_Store:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Enter);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = Store idx \<rbrakk>
  \<Longrightarrow> Local idx \<in> Def P n"
| Def_Push:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Enter);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = Push v;
  i = stkLength (P, C, M) pc \<rbrakk>
  \<Longrightarrow> Stack i \<in> Def P n"
| Def_IAdd:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Enter);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = IAdd;
  i = stkLength (P, C, M) pc - 2 \<rbrakk>
  \<Longrightarrow> Stack i \<in> Def P n"
| Def_CmpEq:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Enter);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = CmpEq;
  i = stkLength (P, C, M) pc - 2 \<rbrakk>
  \<Longrightarrow> Stack i \<in> Def P n"
| Def_New_Heap:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Normal);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = New Cl \<rbrakk>
  \<Longrightarrow> Heap \<in> Def P n"
| Def_New_Stack:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Normal);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = New Cl;
  i = stkLength (P, C, M) pc \<rbrakk>
  \<Longrightarrow> Stack i \<in> Def P n"
| Def_Exception:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Exceptional pco nt);
  C \<noteq> ClassMain P \<rbrakk>
  \<Longrightarrow> Exception \<in> Def P n"
| Def_Exception_handle:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Exceptional \<lfloor>pc'\<rfloor> Enter);
  C \<noteq> ClassMain P;
  i = stkLength (P, C, M) pc' - 1 \<rbrakk>
  \<Longrightarrow> Stack i \<in> Def P n"
| Def_Exception_handle_return:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Exceptional \<lfloor>pc'\<rfloor> Return);
  C \<noteq> ClassMain P;
  i = stkLength (P, C, M) pc' - 1 \<rbrakk>
  \<Longrightarrow> Stack i \<in> Def P n"
| Def_Getfield:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Normal);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = Getfield Cl Fd;
  i = stkLength (P, C, M) pc - 1 \<rbrakk>
  \<Longrightarrow> Stack i \<in> Def P n"
| Def_Putfield:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Normal);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = Putfield Cl Fd \<rbrakk>
  \<Longrightarrow> Heap \<in> Def P n"
| Def_Invoke_Return_Heap:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Return);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = Invoke M' n' \<rbrakk>
  \<Longrightarrow> Heap \<in> Def P n"
| Def_Invoke_Return_Exception:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Return);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = Invoke M' n' \<rbrakk>
  \<Longrightarrow> Exception \<in> Def P n"
| Def_Invoke_Return_Stack:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Return);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = Invoke M' n';
  i = stkLength (P, C, M) (Suc pc) - 1 \<rbrakk>
  \<Longrightarrow> Stack i \<in> Def P n"
| Def_Invoke_Call_Heap:
  "\<lbrakk> n = (C, M, None, Enter);
  C \<noteq> ClassMain P \<rbrakk>
  \<Longrightarrow> Heap \<in> Def P n"
| Def_Invoke_Call_Local:
  "\<lbrakk> n = (C, M, None, Enter);
  C \<noteq> ClassMain P;
  i < locLength (P, C, M) 0 \<rbrakk>
  \<Longrightarrow> Local i \<in> Def P n"
| Def_Return:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Enter);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = instr.Return \<rbrakk>
  \<Longrightarrow> Stack 0 \<in> Def P n"

inductive_set Use :: "wf_jvmprog \<Rightarrow> cfg_node \<Rightarrow> var set"
  for P :: "wf_jvmprog"
  and n :: "cfg_node"
where
  Use_Main_Heap:
  "n = (ClassMain P, MethodMain P, \<lfloor>0\<rfloor>, Normal)
  \<Longrightarrow> Heap \<in> Use P n"
| Use_Load:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Enter);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = Load idx \<rbrakk>
  \<Longrightarrow> Local idx \<in> Use P n"
| Use_Enter_Stack:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Enter);
  C \<noteq> ClassMain P;
  case (instrs_of (PROG P) C M ! pc)
    of Store n' \<Rightarrow> d = 1
    | Getfield F Cl \<Rightarrow> d = 1
    | Putfield F Cl \<Rightarrow> d = 2
    | Checkcast Cl \<Rightarrow> d = 1
    | Invoke M' n' \<Rightarrow> d = Suc n'
    | IAdd \<Rightarrow> d \<in> {1, 2}
    | IfFalse i \<Rightarrow> d = 1
    | CmpEq \<Rightarrow> d \<in> {1 , 2}
    | Throw \<Rightarrow> d = 1
    | instr.Return \<Rightarrow> d = 1
    | _ \<Rightarrow> False;
  i = stkLength (P, C, M) pc - d \<rbrakk>
  \<Longrightarrow> Stack i \<in> Use P n"
| Use_Enter_Local:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Enter);
  C \<noteq> ClassMain P;
  instrs_of (PROG P) C M ! pc = Load n' \<rbrakk>
  \<Longrightarrow> Local n' \<in> Use P n"
| Use_Enter_Heap:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Enter);
  C \<noteq> ClassMain P;
  case (instrs_of (PROG P) C M ! pc)
    of New Cl \<Rightarrow> True
    | Checkcast Cl \<Rightarrow> True
    | Throw \<Rightarrow> True
    | _ \<Rightarrow> False \<rbrakk>
  \<Longrightarrow> Heap \<in> Use P n"
| Use_Normal_Heap:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Normal);
  C \<noteq> ClassMain P;
  case (instrs_of (PROG P) C M ! pc)
    of New Cl \<Rightarrow> True
    | Getfield F Cl \<Rightarrow> True
    | Putfield F Cl \<Rightarrow> True
    | Invoke M' n' \<Rightarrow> True
    | _ \<Rightarrow> False \<rbrakk>
  \<Longrightarrow> Heap \<in> Use P n"
| Use_Normal_Stack:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Normal);
  C \<noteq> ClassMain P;
  case (instrs_of (PROG P) C M ! pc)
    of Getfield F Cl \<Rightarrow> d = 1
    | Putfield F Cl \<Rightarrow> d \<in> {1, 2}
    | Invoke M' n' \<Rightarrow> d > 0 \<and> d \<le> Suc n'
    | _ \<Rightarrow> False;
  i = stkLength (P, C, M) pc - d \<rbrakk>
  \<Longrightarrow> Stack i \<in> Use P n"
| Use_Return_Heap:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Return);
  instrs_of (PROG P) C M ! pc = Invoke M' n' \<or> C = ClassMain P \<rbrakk>
  \<Longrightarrow> Heap \<in> Use P n"
| Use_Return_Stack:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Return);
  (instrs_of (PROG P) C M ! pc = Invoke M' n' \<and> i = stkLength (P, C, M) (Suc pc) - 1) \<or>
  (C = ClassMain P \<and> i = 0) \<rbrakk>
  \<Longrightarrow> Stack i \<in> Use P n"
| Use_Return_Exception:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Return);
  instrs_of (PROG P) C M ! pc = Invoke M' n' \<or> C = ClassMain P \<rbrakk>
  \<Longrightarrow> Exception \<in> Use P n"
| Use_Exceptional_Stack:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Exceptional opc' nt);
  case (instrs_of (PROG P) C M ! pc)
    of Throw \<Rightarrow> True
    | _ \<Rightarrow> False;
  i = stkLength (P, C, M) pc - 1 \<rbrakk>
  \<Longrightarrow> Stack i \<in> Use P n"
| Use_Exceptional_Exception:
  "\<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Exceptional \<lfloor>pc'\<rfloor> Return);
  instrs_of (PROG P) C M ! pc = Invoke M' n' \<rbrakk>
  \<Longrightarrow> Exception \<in> Use P n"
| Use_Method_Leave_Exception:
  "\<lbrakk> n = (C, M, None, Return);
  C \<noteq> ClassMain P \<rbrakk>
  \<Longrightarrow> Exception \<in> Use P n"
| Use_Method_Leave_Heap:
  "\<lbrakk> n = (C, M, None, Return);
  C \<noteq> ClassMain P \<rbrakk>
  \<Longrightarrow> Heap \<in> Use P n"
| Use_Method_Leave_Stack:
  "\<lbrakk> n = (C, M, None, Return);
  C \<noteq> ClassMain P \<rbrakk>
  \<Longrightarrow> Stack 0 \<in> Use P n"
| Use_Method_Entry_Heap:
  "\<lbrakk> n = (C, M, None, Enter);
  C \<noteq> ClassMain P \<rbrakk>
  \<Longrightarrow> Heap \<in> Use P n"
| Use_Method_Entry_Local:
  "\<lbrakk> n = (C, M, None, Enter);
  C \<noteq> ClassMain P;
  i < locLength (P, C, M) 0 \<rbrakk>
  \<Longrightarrow> Local i \<in> Use P n"

fun ParamDefs :: "wf_jvmprog \<Rightarrow> cfg_node \<Rightarrow> var list"
where
  "ParamDefs P (C, M, \<lfloor>pc\<rfloor>, Return) = [Heap, Stack (stkLength (P, C, M) (Suc pc) - 1), Exception]"
  | "ParamDefs P (C, M, opc, nt) = []"

function ParamUses :: "wf_jvmprog \<Rightarrow> cfg_node \<Rightarrow> var set list"
where
  "ParamUses P (ClassMain P, MethodMain P, \<lfloor>0\<rfloor>, Normal) = [{Heap},{}]"
  |
  "M \<noteq> MethodMain P \<or> opc \<noteq> \<lfloor>0\<rfloor> \<or> nt \<noteq> Normal
  \<Longrightarrow> ParamUses P (ClassMain P, M, opc, nt) = []"
  |
  "C \<noteq> ClassMain P
  \<Longrightarrow> ParamUses P (C, M, opc, nt) = (case opc of None \<Rightarrow> []
  | \<lfloor>pc\<rfloor> \<Rightarrow> (case nt of Normal \<Rightarrow> (case (instrs_of (PROG P) C M ! pc) of
      Invoke M' n \<Rightarrow> (
          {Heap} # rev (map (\<lambda>n. {Stack (stkLength (P, C, M) pc - (Suc n))}) [0..<n + 1])
      )
      | _ \<Rightarrow> [])
    | _ \<Rightarrow> []
    )
  )"
  by atomize_elim auto
termination by lexicographic_order

lemma in_set_ParamDefsE:
  "\<lbrakk> V \<in> set (ParamDefs P n);
  \<And>C M pc. \<lbrakk> n = (C, M, \<lfloor>pc\<rfloor>, Return);
         V \<in> {Heap, Stack (stkLength (P, C, M) (Suc pc) - 1), Exception} \<rbrakk> \<Longrightarrow> thesis \<rbrakk>
  \<Longrightarrow> thesis"
  by (cases "(P, n)" rule: ParamDefs.cases) auto

lemma in_set_ParamUsesE:
  assumes V_in_ParamUses: "V \<in> \<Union>(set (ParamUses P n))"
  obtains "n = (ClassMain P, MethodMain P, \<lfloor>0\<rfloor>, Normal)" and "V = Heap"
  | C M pc M' n' i where "n = (C, M, \<lfloor>pc\<rfloor>, Normal)" and "instrs_of (PROG P) C M ! pc = Invoke M' n'"
    and "V = Heap \<or> V = Stack (stkLength (P, C, M) pc - Suc i)" and "i < Suc n'" and "C \<noteq> ClassMain P"
proof (cases "(P, n)" rule: ParamUses.cases)
  case 1 with V_in_ParamUses that show ?thesis by clarsimp
next
  case 2 with V_in_ParamUses that show ?thesis by clarsimp
next
  case (3 C P M pc nt)
  with V_in_ParamUses that show ?thesis
    using [[simproc del: list_to_set_comprehension]]
    by (cases nt, auto) (rename_tac a b, case_tac "instrs_of (PROG P) C M ! a", simp_all, fastforce)
qed

lemma sees_method_fun_wf:
  assumes "PROG P \<turnstile> D sees M': Ts\<rightarrow>T = (mxs, mxl\<^sub>0, is, xt) in D"
  and "(D, D', fs, ms) \<in> set (PROG P)"
  and "(M', Ts', T', mxs', mxl\<^sub>0', is', xt') \<in> set ms"
  shows "Ts = Ts' \<and> T = T' \<and> mxs = mxs' \<and> mxl\<^sub>0 = mxl\<^sub>0' \<and> is = is' \<and> xt = xt'"
proof -
  from distinct_class_names [of P] \<open>(D, D', fs, ms) \<in> set (PROG P)\<close>
  have "class (PROG P) D = \<lfloor>(D', fs, ms)\<rfloor>"
    by (fastforce intro: map_of_SomeI simp: class_def)
  moreover with distinct_method_names have "distinct_fst ms"
    by fastforce
  ultimately show ?thesis using
    \<open>PROG P \<turnstile> D sees M': Ts\<rightarrow>T = (mxs, mxl\<^sub>0, is, xt) in D\<close>
    \<open>(M', Ts', T', mxs', mxl\<^sub>0', is', xt') \<in> set ms\<close>
    by (fastforce dest: visible_method_exists map_of_SomeD distinct_fst_isin_same_fst
      simp: distinct_fst_is_distinct_fst)
qed

interpretation JVMCFG_wf:
  CFG_wf  "sourcenode" "targetnode" "kind" "valid_edge (P, C0, Main)"
  "(ClassMain P, MethodMain P, None, Enter)"
  "(\<lambda>(C, M, pc, type). (C, M))" "get_return_edges P"
  "((ClassMain P, MethodMain P),[],[]) # procs (PROG P)"
  "(ClassMain P, MethodMain P)"
  "Def P" "Use P" "ParamDefs P" "ParamUses P"
  for P C0 Main
proof (unfold_locales)
  show "Def P (ClassMain P, MethodMain P, None, Enter) = {} \<and>
    Use P (ClassMain P, MethodMain P, None, Enter) = {}"
    by (fastforce elim: Def.cases Use.cases)
next
  fix a Q r p fs ins outs
  assume "valid_edge (P, C0, Main) a"
    and "kind a = Q:r\<hookrightarrow>\<^bsub>p\<^esub>fs"
    and params: "(p, ins, outs) \<in> set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
  hence "(P, C0, Main) \<turnstile> sourcenode a -Q:r\<hookrightarrow>\<^bsub>p\<^esub>fs\<rightarrow> targetnode a"
    by (simp add: valid_edge_def)
  from this params show "length (ParamUses P (sourcenode a)) = length ins"
  proof cases
    case Main_Call
    with params show ?thesis
      by auto (erule in_set_procsE, auto dest: sees_method_idemp sees_method_fun)
  next
    case (CFG_Invoke_Call C M pc M' n ST LT D' Ts T mxs mxl0 "is" xt D Q' paramDefs)
    hence [simp]: "Q' = Q" and [simp]: "r = (C, M, pc)" and [simp]: "p = (D, M')"
      and [simp]: "fs = paramDefs"
      by simp_all
    from CFG_Invoke_Call obtain T' mxs' mpc' xt' where
      "PROG P,T',mxs',mpc',xt' \<turnstile> instrs_of (PROG P) C M ! pc,pc :: TYPING P C M"
      by (blast dest: reachable_node_impl_wt_instr)
    moreover from \<open>PROG P \<turnstile> D' sees M': Ts\<rightarrow>T = (mxs, mxl0, is, xt) in D\<close>
    have "PROG P \<turnstile> D sees M': Ts\<rightarrow>T = (mxs, mxl0, is, xt) in D"
      by -(drule sees_method_idemp)
    with params have "PROG P \<turnstile> D sees M': Ts\<rightarrow>T=(mxs, mxl0, is, xt) in D"
      and "ins = Heap # map Local [0..<Suc (length Ts)]"
      by (fastforce elim: in_set_procsE dest: sees_method_fun)+
    ultimately show ?thesis using CFG_Invoke_Call
      by (fastforce dest: sees_method_fun list_all2_lengthD simp: min_def)
  qed simp_all
next
  fix a
  assume "valid_edge (P, C0, Main) a"
  thus "distinct (ParamDefs P (targetnode a))"
    by (clarsimp simp: valid_edge_def) (erule JVMCFG.cases, auto)
next
  fix a Q' p f' ins outs
  assume "valid_edge (P, C0, Main) a"
    and "kind a = Q'\<hookleftarrow>\<^bsub>p\<^esub>f'"
    and params: "(p, ins, outs) \<in> set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
  hence "(P, C0, Main) \<turnstile> sourcenode a -Q'\<hookleftarrow>\<^bsub>p\<^esub>f'\<rightarrow> targetnode a"
    by (simp add: valid_edge_def)
  from this params
  show "length (ParamDefs P (targetnode a)) = length outs"
    by cases (auto elim: in_set_procsE)
next
  fix n V
  assume params: "V \<in> set (ParamDefs P n)"
    and vn: "CFG.valid_node sourcenode targetnode (valid_edge (P, C0, Main)) n"
  then obtain ek n'
    where ve:"valid_edge (P, C0, Main) (n, ek, n') \<or> valid_edge (P, C0, Main) (n', ek, n)"
    by (fastforce simp: JVMCFG_Interpret.valid_node_def)
  from params obtain C M pc where [simp]: "n = (C, M, \<lfloor>pc\<rfloor>, Return)"
    and V: "V \<in> {Heap, Stack (stkLength (P, C, M) (Suc pc) - 1), Exception}"
    by (blast elim: in_set_ParamDefsE)
  from ve show "V \<in> Def P n"
  proof
    assume "valid_edge (P, C0, Main) (n, ek, n')"
    thus ?thesis unfolding valid_edge_def
    proof cases
      case Main_Return_to_Exit with V show ?thesis
        by (auto intro: Def_Main_Heap Def_Main_Stack_0 Def_Main_Exception simp: stkLength_def)
    next
      case CFG_Invoke_Return_Check_Normal with V show ?thesis
        by (fastforce intro: Def_Invoke_Return_Heap
          Def_Invoke_Return_Stack Def_Invoke_Return_Exception)
    next
      case CFG_Invoke_Return_Check_Exceptional with V show ?thesis
        by (fastforce intro: Def_Invoke_Return_Heap
          Def_Invoke_Return_Stack Def_Invoke_Return_Exception)
    next
      case CFG_Invoke_Return_Exceptional_prop with V show ?thesis
        by (fastforce intro: Def_Invoke_Return_Heap
          Def_Invoke_Return_Stack Def_Invoke_Return_Exception)
    qed simp_all
  next
    assume "valid_edge (P, C0, Main) (n', ek, n)"
    thus ?thesis unfolding valid_edge_def
    proof cases
      case Main_Call_LFalse with V show ?thesis
        by (auto intro: Def_Main_Heap Def_Main_Stack_0 Def_Main_Exception simp: stkLength_def)
    next
      case CFG_Invoke_False with V show ?thesis
        by (fastforce intro: Def_Invoke_Return_Heap
          Def_Invoke_Return_Stack Def_Invoke_Return_Exception)
    next
      case CFG_Return_from_Method with V show ?thesis
        by (fastforce elim!: JVMCFG.cases intro!: Def_Main_Stack_0
          intro: Def_Main_Heap Def_Main_Exception Def_Invoke_Return_Heap
          Def_Invoke_Return_Exception Def_Invoke_Return_Stack simp: stkLength_def)
    qed simp_all
  qed
next
  fix a Q r p fs ins outs V
  assume ve: "valid_edge (P, C0, Main) a"
    and kind: "kind a = Q:r\<hookrightarrow>\<^bsub>p\<^esub>fs"
    and params: "(p, ins, outs) \<in> set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
    and V: "V \<in> set ins"
  from params V obtain D fs ms Ts T mb where "class (PROG P) (fst p) = \<lfloor>(D, fs, ms)\<rfloor>"
    and "method": "PROG P \<turnstile> (fst p) sees (snd p): Ts\<rightarrow>T = mb in (fst p)"
    and ins: "ins = Heap # map Local [0..<Suc (length Ts)]"
    by (cases p) (fastforce elim: in_set_procsE)
  from ve kind show "V \<in> Def P (targetnode a)" unfolding valid_edge_def
  proof cases
    case (Main_Call T' mxs mxl0 "is" xt D' initParams)
    with kind have "PROG P \<turnstile> D' sees Main: []\<rightarrow>T' = (mxs, mxl0, is, xt) in D'"
      and [simp]: "p = (D', Main)"
      by (auto dest: sees_method_idemp)
    with "method" have [simp]: "Ts = []" and [simp]: "T' = T" and [simp]: "mb = (mxs, mxl0, is, xt)"
      by (fastforce dest: sees_method_fun)+
    from Main_Call ins V show ?thesis
      by (fastforce intro!: Def_Invoke_Call_Heap Def_Invoke_Call_Local
        dest: sees_method_idemp wt_jvm_prog_impl_wt_start[OF wf_jvmprog_is_wf_typ]
        simp: locLength_def wt_start_def)
  next
    case (CFG_Invoke_Call C M pc M' n ST LT D' Ts' T' mxs mxl0 "is" xt D'')
    with kind have "PROG P \<turnstile> D'' sees M': Ts'\<rightarrow>T' = (mxs, mxl0, is, xt) in D''"
      and [simp]: "p = (D'', M')"
      by (auto dest: sees_method_idemp)
    with "method" have [simp]: "Ts' = Ts" and [simp]: "T' = T" and [simp]: "mb = (mxs, mxl0, is, xt)"
      by (fastforce dest: sees_method_fun)+
    from CFG_Invoke_Call ins V show ?thesis
      by (fastforce intro!: Def_Invoke_Call_Local Def_Invoke_Call_Heap
        dest: sees_method_idemp wt_jvm_prog_impl_wt_start[OF wf_jvmprog_is_wf_typ] list_all2_lengthD
        simp: locLength_def min_def wt_start_def)
  qed simp_all
next
  fix a Q r p fs
  assume "valid_edge (P, C0, Main) a" and "kind a = Q:r\<hookrightarrow>\<^bsub>p\<^esub>fs"
  thus "Def P (sourcenode a) = {}" unfolding valid_edge_def
    by cases (auto elim: Def.cases)
next
  fix n V
  assume "CFG.valid_node sourcenode targetnode (valid_edge (P, C0, Main)) n"
    and V: "V \<in> \<Union>(set (ParamUses P n))"
  then obtain ek n'
    where ve:"valid_edge (P, C0, Main) (n, ek, n') \<or> valid_edge (P, C0, Main) (n', ek, n)"
    by (fastforce simp: JVMCFG_Interpret.valid_node_def)
  from V obtain C M pc M' n'' i where
    V: "n = (ClassMain P, MethodMain P, \<lfloor>0\<rfloor>, Normal) \<and> V = Heap \<or>
    n = (C, M, \<lfloor>pc\<rfloor>, Normal) \<and> instrs_of (PROG P) C M ! pc = Invoke M' n'' \<and>
      (V = Heap \<or> V = Stack (stkLength (P, C, M) pc - Suc i)) \<and> i < Suc n'' \<and> C \<noteq> ClassMain P"
    by -(erule in_set_ParamUsesE, fastforce+)
  from ve show "V \<in> Use P n"
  proof
    assume "valid_edge (P, C0, Main) (n, ek, n')"
    from this V show ?thesis unfolding valid_edge_def
    proof cases
      case Main_Call_LFalse with V show ?thesis by (fastforce intro: Use_Main_Heap)
    next
      case Main_Call with V show ?thesis by (fastforce intro: Use_Main_Heap)
    next
      case CFG_Invoke_Call with V show ?thesis
        by (fastforce intro: Use_Normal_Heap Use_Normal_Stack [where d="Suc i"])
    next
      case CFG_Invoke_False with V show ?thesis
        by (fastforce intro: Use_Normal_Heap Use_Normal_Stack [where d="Suc i"])
    qed simp_all
  next
    assume "valid_edge (P, C0, Main) (n', ek, n)"
    from this V show ?thesis unfolding valid_edge_def
    proof cases
      case Main_to_Call with V show ?thesis by (fastforce intro: Use_Main_Heap)
    next
      case CFG_Invoke_Check_NP_Normal with V show ?thesis
        by (fastforce intro: Use_Normal_Heap Use_Normal_Stack [where d="Suc i"])
    qed simp_all
  qed
next
  fix a Q p f ins outs V
  assume "valid_edge (P, C0, Main) a"
    and "kind a = Q\<hookleftarrow>\<^bsub>p\<^esub>f"
    and "(p, ins, outs) \<in> set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
    and "V \<in> set outs"
  thus "V \<in> Use P (sourcenode a)" unfolding valid_edge_def
    by (cases, simp_all)
  (fastforce elim: in_set_procsE
    intro: Use_Method_Leave_Heap Use_Method_Leave_Stack Use_Method_Leave_Exception)
next
  fix a V s
  assume ve: "valid_edge (P, C0, Main) a"
    and V_notin_Def: "V \<notin> Def P (sourcenode a)"
    and ik: "intra_kind (kind a)"
    and pred: "JVMCFG_Interpret.pred (kind a) s"
  show "JVMCFG_Interpret.state_val
    (CFG.transfer (((ClassMain P, MethodMain P), [], []) # procs (PROG P)) (kind a) s) V
    = JVMCFG_Interpret.state_val s V"
  proof (cases s)
    case Nil
    thus ?thesis by simp
  next
    case [simp]: Cons
    with ve V_notin_Def ik pred show ?thesis unfolding valid_edge_def
    proof cases
      case CFG_Load with V_notin_Def show ?thesis by (fastforce intro: Def_Load)
    next case CFG_Store with V_notin_Def show ?thesis by (fastforce intro: Def_Store)
    next case CFG_Push with V_notin_Def show ?thesis by (fastforce intro: Def_Push)
    next case CFG_IAdd with V_notin_Def show ?thesis by (fastforce intro: Def_IAdd)
    next case CFG_CmpEq with V_notin_Def show ?thesis by (fastforce intro: Def_CmpEq)
    next case CFG_New_Update with V_notin_Def show ?thesis
        by (fastforce intro: Def_New_Heap Def_New_Stack)
    next case CFG_New_Exceptional_prop with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception)
    next case CFG_New_Exceptional_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Getfield_Update with V_notin_Def show ?thesis
        by (fastforce intro: Def_Getfield split: prod.split)
    next case CFG_Getfield_Exceptional_prop with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception)
    next case CFG_Getfield_Exceptional_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Putfield_Update with V_notin_Def show ?thesis
        by (fastforce intro: Def_Putfield split: prod.split)
    next case CFG_Putfield_Exceptional_prop with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception)
    next case CFG_Putfield_Exceptional_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Checkcast_Exceptional_prop with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception)
    next case CFG_Checkcast_Exceptional_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Throw_prop with V_notin_Def show ?thesis by (fastforce intro: Def_Exception)
    next case CFG_Throw_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Invoke_NP_prop with V_notin_Def show ?thesis by (fastforce intro: Def_Exception)
    next case CFG_Invoke_NP_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception Def_Exception_handle)
    next case CFG_Invoke_Return_Exceptional_handle with V_notin_Def show ?thesis
        by (fastforce intro: Def_Exception_handle_return Def_Exception)
    next case CFG_Return with V_notin_Def show ?thesis by (fastforce intro: Def_Return)
    qed (simp_all add: intra_kind_def)
  qed
next
  fix a s s'
  assume ve: "valid_edge (P, C0, Main) a"
    and use_Eq: "\<forall>V\<in>Use P (sourcenode a). JVMCFG_Interpret.state_val s V
    = JVMCFG_Interpret.state_val s' V"
    and ik: "intra_kind (kind a)"
    and pred_s: "JVMCFG_Interpret.pred (kind a) s"
    and pred_s': "JVMCFG_Interpret.pred (kind a) s'"
  then obtain cfs C M pc cs cfs' C' M' pc' cs' where [simp]: "s = (cfs, (C, M, pc)) # cs"
    and [simp]: "s' = (cfs', (C', M', pc')) # cs'"
    by (cases s, fastforce) (cases s', fastforce+)
  from ve show "\<forall>V\<in>Def P (sourcenode a).
             JVMCFG_Interpret.state_val
              (CFG.transfer (((ClassMain P, MethodMain P), [], []) # procs (PROG P)) (kind a) s) V =
             JVMCFG_Interpret.state_val
              (CFG.transfer (((ClassMain P, MethodMain P), [], []) # procs (PROG P)) (kind a) s') V"
    unfolding valid_edge_def
  proof cases
    case Main_Call with ik show ?thesis by (simp add: intra_kind_def)
  next case Main_Return_to_Exit with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Return_Heap Use_Return_Exception Use_Return_Stack)
  next case Method_LFalse with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Method_Entry_Heap Use_Method_Entry_Local)
  next case Method_LTrue with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Method_Entry_Heap Use_Method_Entry_Local)
  next case CFG_Load with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Enter_Local)
  next case CFG_Store with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Enter_Stack)
  next case (CFG_IAdd C M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      and "Stack (stkLength (P, C, M) pc - 2) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)+
    with use_Eq CFG_IAdd show ?thesis by (auto elim!: Def.cases)
  next case (CFG_CmpEq C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      and "Stack (stkLength (P, C, M) pc - 2) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)+
    with use_Eq CFG_CmpEq show ?thesis by (auto elim!: Def.cases)
  next case CFG_New_Update
    hence "Heap \<in> Use P (sourcenode a)" by (fastforce intro: Use_Normal_Heap)
    with use_Eq CFG_New_Update show ?thesis by (fastforce elim: Def.cases)
  next case (CFG_Getfield_Update C  M pc)
    hence "Heap \<in> Use P (sourcenode a)"
      and "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Normal_Heap Use_Normal_Stack)+
    with use_Eq CFG_Getfield_Update show ?thesis by (auto elim!: Def.cases split: prod.split)
  next case (CFG_Putfield_Update C  M pc)
    hence "Heap \<in> Use P (sourcenode a)"
      and "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      and "Stack (stkLength (P, C, M) pc - 2) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Normal_Heap Use_Normal_Stack)+
    with use_Eq CFG_Putfield_Update show ?thesis by (auto elim!: Def.cases split: prod.split)
  next case (CFG_Throw_prop C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Exceptional_Stack)
    with use_Eq CFG_Throw_prop show ?thesis by (fastforce elim: Def.cases)
  next case (CFG_Throw_handle C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Exceptional_Stack)
    with use_Eq CFG_Throw_handle show ?thesis by (fastforce elim: Def.cases)
  next case CFG_Invoke_Call with ik show ?thesis by (simp add: intra_kind_def)
  next case CFG_Invoke_Return_Check_Normal with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Return_Heap Use_Return_Exception Use_Return_Stack)
  next case CFG_Invoke_Return_Check_Exceptional with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Return_Heap Use_Return_Exception Use_Return_Stack)
  next case CFG_Invoke_Return_Exceptional_handle with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Exceptional_Exception)
  next case CFG_Invoke_Return_Exceptional_prop with use_Eq show ?thesis
      by (fastforce elim: Def.cases intro: Use_Return_Heap Use_Return_Exception Use_Return_Stack)
  next case CFG_Return with use_Eq show ?thesis
      by (fastforce elim!: Def.cases intro: Use_Enter_Stack)
  next case CFG_Return_from_Method with ik show ?thesis by (simp add: intra_kind_def)
  qed (fastforce elim: Def.cases)+
next
  fix a s s'
  assume ve: "valid_edge (P, C0, Main) a"
    and pred: "JVMCFG_Interpret.pred (kind a) s"
    and "snd (hd s) = snd (hd s')"
    and use_Eq: "\<forall>V\<in>Use P (sourcenode a).
           JVMCFG_Interpret.state_val s V = JVMCFG_Interpret.state_val s' V"
    and "length s = length s'"
  then obtain cfs C M pc cs cfs' cs' where [simp]: "s = (cfs, (C, M, pc)) # cs"
    and [simp]: "s' = (cfs', (C, M, pc)) # cs'" and length_cs: "length cs = length cs'"
    by (cases s, fastforce) (cases s', fastforce+)
  from ve pred show "JVMCFG_Interpret.pred (kind a) s'"
    unfolding valid_edge_def
  proof cases
    case Main_Call_LFalse with pred show ?thesis by simp
  next case Main_Call with pred use_Eq show ?thesis by simp
  next case Method_LTrue with pred use_Eq show ?thesis by simp
  next case CFG_Goto with pred use_Eq show ?thesis by simp
  next case (CFG_IfFalse_False C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with use_Eq CFG_IfFalse_False pred show ?thesis by fastforce
  next case (CFG_IfFalse_True C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_IfFalse_True show ?thesis by fastforce
  next case CFG_New_Check_Normal
    hence "Heap \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Heap)
    with pred use_Eq CFG_New_Check_Normal show ?thesis by fastforce
  next case CFG_New_Check_Exceptional
    hence "Heap \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Heap)
    with pred use_Eq CFG_New_Check_Exceptional show ?thesis by fastforce
  next case (CFG_Getfield_Check_Normal C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Getfield_Check_Normal show ?thesis by fastforce
  next case (CFG_Getfield_Check_Exceptional C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Getfield_Check_Exceptional  show ?thesis by fastforce
  next case (CFG_Putfield_Check_Normal C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 2) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Putfield_Check_Normal show ?thesis by fastforce
  next case (CFG_Putfield_Check_Exceptional C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 2) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Putfield_Check_Exceptional show ?thesis by fastforce
  next case (CFG_Checkcast_Check_Normal C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      and "Heap \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack Use_Enter_Heap)+
    with pred use_Eq CFG_Checkcast_Check_Normal show ?thesis by fastforce
  next case (CFG_Checkcast_Check_Exceptional C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      and "Heap \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack Use_Enter_Heap)+
    with pred use_Eq CFG_Checkcast_Check_Exceptional show ?thesis by fastforce
  next case (CFG_Throw_Check C  M pc)
    hence "Stack (stkLength (P, C, M) pc - 1) \<in> Use P (sourcenode a)"
      and "Heap \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack Use_Enter_Heap)+
    with pred use_Eq CFG_Throw_Check show ?thesis by fastforce
  next case (CFG_Invoke_Check_NP_Normal C  M pc M' n)
    hence "Stack (stkLength (P, C, M) pc - (Suc n)) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Invoke_Check_NP_Normal show ?thesis by fastforce
  next case (CFG_Invoke_Check_NP_Exceptional C  M pc M' n)
    hence "Stack (stkLength (P, C, M) pc - (Suc n)) \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Enter_Stack)
    with pred use_Eq CFG_Invoke_Check_NP_Exceptional show ?thesis by fastforce
  next case (CFG_Invoke_Call C  M pc M' n)
    hence "Stack (stkLength (P, C, M) pc - (Suc n)) \<in> Use P (sourcenode a)"
      and "Heap \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Normal_Heap Use_Normal_Stack)+
    with pred use_Eq CFG_Invoke_Call show ?thesis by fastforce
  next case CFG_Invoke_Return_Check_Normal
    hence "Exception \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Return_Exception)
    with pred use_Eq CFG_Invoke_Return_Check_Normal show ?thesis by fastforce
  next case CFG_Invoke_Return_Check_Exceptional
    hence "Exception \<in> Use P (sourcenode a)" and "Heap \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Return_Exception Use_Return_Heap)+
    with pred use_Eq CFG_Invoke_Return_Check_Exceptional show ?thesis by fastforce
  next case CFG_Invoke_Return_Exceptional_prop
    hence "Exception \<in> Use P (sourcenode a)" and "Heap \<in> Use P (sourcenode a)"
      by (fastforce intro: Use_Return_Exception Use_Return_Heap)+
    with pred use_Eq CFG_Invoke_Return_Exceptional_prop show ?thesis by fastforce
  next case CFG_Return_from_Method with pred length_cs show ?thesis by clarsimp
  qed auto
next
  fix a Q r p fs ins outs
  assume "valid_edge (P, C0, Main) a"
    and kind: "kind a = Q:r\<hookrightarrow>\<^bsub>p\<^esub>fs"
    and params: "(p, ins, outs) \<in> set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
  thus "length fs = length ins" unfolding valid_edge_def
  proof cases
    case (Main_Call  T mxs mxl0 "is" xt D)
    with kind params have [simp]: "p = (D, Main)"
      and "PROG P \<turnstile> D sees Main: []\<rightarrow>T = (mxs, mxl0, is, xt) in D"
      and "ins = Heap # map Local [0..<Suc 0]"
      by (auto elim!: in_set_procsE dest: sees_method_fun sees_method_idemp)
    with Main_Call kind show ?thesis
      by auto
  next
    case (CFG_Invoke_Call C  M pc M' n ST LT D' Ts T mxs mxl0 "is" xt D)
    with kind params have [simp]: "p = (D, M')"
      and "PROG P \<turnstile> D' sees M': Ts\<rightarrow>T = (mxs, mxl0, is, xt) in D"
      and "ins = Heap # map Local [0..<Suc (length Ts)]"
      by (auto elim!: in_set_procsE dest: sees_method_fun sees_method_idemp)
    moreover with \<open>(P, C0, Main) \<turnstile> \<Rightarrow>(C, M, \<lfloor>pc\<rfloor>, Normal)\<close> \<open>C \<noteq> ClassMain P\<close>
      \<open>instrs_of (PROG P) C M ! pc = Invoke M' n\<close> \<open>TYPING P C M ! pc = \<lfloor>(ST, LT)\<rfloor>\<close>
      \<open>ST ! n = Class D'\<close> have "n = length Ts"
      by (fastforce dest!: reachable_node_impl_wt_instr dest: sees_method_fun list_all2_lengthD)
    ultimately show ?thesis using CFG_Invoke_Call kind by auto
  qed simp_all
next
  fix a Q r p fs a' Q' r' p' fs' s s'
  assume ve_a: "valid_edge (P, C0, Main) a"
    and kind_a: "kind a = Q:r\<hookrightarrow>\<^bsub>p\<^esub>fs"
    and ve_a': "valid_edge (P, C0, Main) a'"
    and kind_a': "kind a' = Q':r'\<hookrightarrow>\<^bsub>p'\<^esub>fs'"
    and src: "sourcenode a = sourcenode a'"
    and pred_s: "JVMCFG_Interpret.pred (kind a) s"
    and pred_s': "JVMCFG_Interpret.pred (kind a') s"
  then obtain cfs C M pc cs cfs' C' M' pc' cs'
    where [simp]: "s = (cfs, (C, M, pc)) # cs"
    by (cases s) fastforce+
  with ve_a kind_a show "a = a'" unfolding valid_edge_def
  proof cases
    case Main_Call with ve_a' kind_a' src pred_s pred_s' show ?thesis unfolding valid_edge_def
      by (cases a, cases a') (fastforce elim: JVMCFG.cases dest: sees_method_fun)
  next
    case CFG_Invoke_Call
    note invoke_call1 = this
    from ve_a' kind_a' show ?thesis unfolding valid_edge_def
    proof cases
      case Main_Call with CFG_Invoke_Call src have False by simp
      thus ?thesis by simp
    next
      case CFG_Invoke_Call with src invoke_call1 show ?thesis
        by clarsimp (cases a, cases a', fastforce dest: sees_method_fun)
    qed simp_all
  qed simp_all
next
  fix a Q r p fs i ins outs s s'
  assume ve: "valid_edge (P, C0, Main) a"
    and kind: "kind a = Q:r\<hookrightarrow>\<^bsub>p\<^esub>fs"
    and "i < length ins"
    and "(p, ins, outs) \<in> set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
    and "JVMCFG_Interpret.pred (kind a) s"
    and "JVMCFG_Interpret.pred (kind a) s'"
    and use_Eq: "\<forall>V\<in>ParamUses P (sourcenode a) ! i.
           JVMCFG_Interpret.state_val s V = JVMCFG_Interpret.state_val s' V"
  then obtain cfs C M pc cs cfs' C' M' pc' cs' where [simp]: "s = (cfs, (C, M, pc)) # cs"
    and [simp]: "s' = (cfs', (C', M', pc')) # cs'"
    by (cases s, fastforce) (cases s', fastforce+)
  from ve kind
  show "JVMCFG_Interpret.params fs (JVMCFG_Interpret.state_val s) ! i =
          JVMCFG_Interpret.params fs (JVMCFG_Interpret.state_val s') ! i"
    unfolding valid_edge_def
  proof cases
    case Main_Call with kind use_Eq \<open>i < length ins\<close> show ?thesis
      by (cases i) auto
  next
    case CFG_Invoke_Call
    { fix P C M pc n st st' i
      have "\<forall>V\<in>rev (map (\<lambda>n. {Stack (stkLength (P, C, M) pc - Suc n)}) [0..<n]) ! i. st V = st' V
        \<Longrightarrow> JVMCFG_Interpret.params
        (rev (map (\<lambda>i s. s (Stack (stkLength (P, C, M) pc - Suc i))) [0..<n])) st ! i =
        JVMCFG_Interpret.params
        (rev (map (\<lambda>i s. s (Stack (stkLength (P, C, M) pc - Suc i))) [0..<n])) st' ! i"
        by (induct n arbitrary: i) (simp, case_tac i, auto)
    }
    note stack_params = this
    from CFG_Invoke_Call kind use_Eq \<open>i < length ins\<close> show ?thesis
      by (cases i, auto) (case_tac nat, auto intro: stack_params)
  qed simp_all
next
  fix a Q' p f' ins outs vmap vmap'
  assume "valid_edge (P, C0, Main) a"
    and "kind a = Q'\<hookleftarrow>\<^bsub>p\<^esub>f'"
    and "(p, ins, outs) \<in> set (((ClassMain P, MethodMain P), [], []) # procs (PROG P))"
  thus "f' vmap vmap' = vmap'(ParamDefs P (targetnode a) [:=] map vmap outs)"
    unfolding valid_edge_def
    by (cases, simp_all) (fastforce elim: in_set_procsE simp: fun_upd_twist)
next
  fix a a'
  { fix P n f n' e n''
    assume "P \<turnstile> n -\<Up>f\<rightarrow> n'" and "P \<turnstile> n -e\<rightarrow> n''"
    hence "e = \<Up>f \<and> n' = n''"
      by cases (simp_all, (fastforce elim: JVMCFG.cases)+)
  }
  note upd_det = this
  { fix P n Q n' Q' n'' s
    assume "P \<turnstile> n -(Q)\<^sub>\<surd>\<rightarrow> n'" and edge': "P \<turnstile> n -(Q')\<^sub>\<surd>\<rightarrow> n''" and trg: "n' \<noteq> n''"
    hence "(Q s \<longrightarrow> \<not> Q' s) \<and> (Q' s \<longrightarrow> \<not> Q s)"
    proof cases
      case CFG_Throw_Check with edge' trg show ?thesis by cases fastforce+
    qed (simp_all, (fastforce elim: JVMCFG.cases)+)
  }
  note pred_det = this
  assume "valid_edge (P, C0, Main) a"
    and ve': "valid_edge (P, C0, Main) a'"
    and src: "sourcenode a = sourcenode a'"
    and trg: "targetnode a \<noteq> targetnode a'"
    and "intra_kind (kind a)"
    and "intra_kind (kind a')"
  thus "\<exists>Q Q'. kind a = (Q)\<^sub>\<surd> \<and> kind a' = (Q')\<^sub>\<surd> \<and> (\<forall>s. (Q s \<longrightarrow> \<not> Q' s) \<and> (Q' s \<longrightarrow> \<not> Q s))"
    unfolding valid_edge_def intra_kind_def
    by (auto dest: upd_det pred_det)
qed

interpretation JVMCFGExit_wf :
  CFGExit_wf "sourcenode" "targetnode" "kind" "valid_edge (P, C0, Main)"
  "(ClassMain P, MethodMain P, None, Enter)"
  "(\<lambda>(C, M, pc, type). (C, M))" "get_return_edges P"
  "((ClassMain P, MethodMain P),[],[]) # procs (PROG P)"
  "(ClassMain P, MethodMain P)"
  "(ClassMain P, MethodMain P, None, Return)"
  "Def P" "Use P" "ParamDefs P" "ParamUses P"
proof
  show "Def P (ClassMain P, MethodMain P, None, nodeType.Return) = {} \<and>
    Use P (ClassMain P, MethodMain P, None, nodeType.Return) = {}"
    by (fastforce elim: Def.cases Use.cases)
qed

end