(*  Title:      HOL/MicroJava/BV/BVNoTypeErrors.thy

    Author:     Gerwin Klein
    Copyright   GPL
*)

header {* \isaheader{Welltyped Programs produce no Type Errors} *}

theory BVNoTypeError
imports "../JVM/JVMDefensive" BVSpecTypeSafe
begin

lemma has_methodI:
  "P \<turnstile> C sees M:Ts\<rightarrow>T = m in D \<Longrightarrow> P \<turnstile> C has M"
  by (unfold has_method_def) blast

text {*
  Some simple lemmas about the type testing functions of the
  defensive JVM:
*}
lemma typeof_NoneD [simp,dest]: "typeof v = Some x \<Longrightarrow> \<not>is_Addr v"
  by (cases v) auto

lemma is_Ref_def2:
  "is_Ref v = (v = Null \<or> (\<exists>a. v = Addr a))"
  by (cases v) (auto simp add: is_Ref_def)

lemma is_RefI [intro, simp]: "P,h \<turnstile> v :\<le> T \<Longrightarrow> is_refT T \<Longrightarrow> is_Ref v"
(*<*)
  apply (cases T)
  apply (auto simp add: is_refT_def is_Ref_def dest: conf_ClassD)
  done
(*>*)

lemma is_BoolI [intro, simp]: "P,h \<turnstile> v :\<le> Boolean \<Longrightarrow> is_Bool v"
(*<*)
  apply (unfold conf_def)
  apply auto
  done
(*>*)

declare defs1 [simp del]

lemma wt_jvm_prog_states:
  "\<lbrakk> wf_jvm_prog\<^bsub>\<Phi>\<^esub> P; P \<turnstile> C sees M: Ts\<rightarrow>T = (mxs, mxl, ins, et) in C;
     \<Phi> C M ! pc = \<tau>; pc < size ins \<rbrakk>
  \<Longrightarrow> OK \<tau> \<in> states P mxs (1+size Ts+mxl)"
(*<*)
  apply (unfold wf_jvm_prog_phi_def)
  apply (drule (1) sees_wf_mdecl)
  apply (simp add: wf_mdecl_def wt_method_def check_types_def)
  apply (blast intro: nth_in)
  done
(*>*)

text {*
  The main theorem: welltyped programs do not produce type errors if they
  are started in a conformant state.
*}
theorem no_type_error:
  fixes \<sigma> :: jvm_state
  assumes welltyped: "wf_jvm_prog\<^bsub>\<Phi>\<^esub> P" and conforms: "P,\<Phi> \<turnstile> \<sigma> \<surd>"
  shows "exec_d P \<sigma> \<noteq> TypeError"
(*<*)
proof -
  from welltyped obtain mb where wf: "wf_prog mb P" by (fast dest: wt_jvm_progD)

  obtain xcp h frs where s [simp]: "\<sigma> = (xcp, h, frs)" by (cases \<sigma>)

  from conforms have "xcp \<noteq> None \<or> frs = [] \<Longrightarrow> check P \<sigma>"
    by (unfold correct_state_def check_def) auto
  moreover {
    assume "\<not>(xcp \<noteq> None \<or> frs = [])"
    then obtain stk reg C M pc frs' where
      xcp [simp]: "xcp = None" and
      frs [simp]: "frs = (stk,reg,C,M,pc)#frs'"
      by (clarsimp simp add: neq_Nil_conv)

    from conforms obtain  ST LT Ts T mxs mxl ins xt where
      hconf:  "P \<turnstile> h \<surd>" and
      meth:   "P \<turnstile> C sees M:Ts\<rightarrow>T = (mxs, mxl, ins, xt) in C" and
      \<Phi>:      "\<Phi> C M ! pc = Some (ST,LT)" and
      frame:  "conf_f P h (ST,LT) ins (stk,reg,C,M,pc)" and
      frames: "conf_fs P h \<Phi> M (size Ts) T frs'"
      by (fastforce simp add: correct_state_def dest: sees_method_fun)

    from frame obtain
      stk: "P,h \<turnstile> stk [:\<le>] ST" and
      reg: "P,h \<turnstile> reg [:\<le>\<^sub>\<top>] LT" and
      pc:  "pc < size ins"
      by (simp add: conf_f_def)

    from welltyped meth \<Phi> pc
    have "OK (Some (ST, LT)) \<in> states P mxs (1+size Ts+mxl)"
      by (rule wt_jvm_prog_states)
    hence "size ST \<le> mxs" by (auto simp add: JVM_states_unfold)
    with stk have mxs: "size stk \<le> mxs"
      by (auto dest: list_all2_lengthD)

    from welltyped meth pc
    have "P,T,mxs,size ins,xt \<turnstile> ins!pc,pc :: \<Phi> C M"
      by (rule wt_jvm_prog_impl_wt_instr)
    hence app\<^sub>0: "app (ins!pc) P mxs T pc (size ins) xt (\<Phi> C M!pc) "
      by (simp add: wt_instr_def)
    with \<Phi> have eff:
      "\<forall>(pc',s')\<in>set (eff (ins ! pc) P pc xt (\<Phi> C M ! pc)). pc' < size ins"
      by (unfold app_def) simp

    from app\<^sub>0 \<Phi> have app:
      "xcpt_app (ins!pc) P pc mxs xt (ST,LT) \<and> app\<^sub>i (ins!pc, P, pc, mxs, T, (ST,LT))"
      by (clarsimp simp add: app_def)

    with eff stk reg
    have "check_instr (ins!pc) P h stk reg C M pc frs'"
    proof (cases "ins!pc")
      case (Getfield F C)
      with app stk reg \<Phi> obtain v vT stk' where
        field: "P \<turnstile> C sees F:vT in C" and
        stk:   "stk = v # stk'" and
        conf:  "P,h \<turnstile> v :\<le> Class C"
        by auto
      from conf have is_Ref: "is_Ref v" by auto
      moreover {
        assume "v \<noteq> Null"
        with conf field is_Ref wf
        have "\<exists>D vs. h (the_Addr v) = Some (D,vs) \<and> P \<turnstile> D \<preceq>\<^sup>* C"
          by (auto dest!: non_npD)
      }
      ultimately show ?thesis using Getfield field stk hconf
        apply clarsimp
        apply (rule conjI, fastforce)
        apply clarsimp
        apply (drule has_visible_field)
        apply (drule (1) has_field_mono)
        apply (drule (1) hconfD)
        apply (unfold oconf_def has_field_def)
        apply clarsimp
        apply (fastforce dest: has_fields_fun)
        done
    next
      case (Putfield F C)
      with app stk reg \<Phi> obtain v ref vT stk' where
        field: "P \<turnstile> C sees F:vT in C" and
        stk:   "stk = v # ref # stk'" and
        confv: "P,h \<turnstile> v :\<le> vT" and
        confr: "P,h \<turnstile> ref :\<le> Class C"
        by fastforce
      from confr have is_Ref: "is_Ref ref" by simp
      moreover {
        assume "ref \<noteq> Null"
        with confr field is_Ref wf
        have "\<exists>D vs. h (the_Addr ref) = Some (D,vs) \<and> P \<turnstile> D \<preceq>\<^sup>* C"
          by (auto dest: non_npD)
      }
      ultimately show ?thesis using Putfield field stk confv by fastforce
    next
      case (Invoke M' n)
      with app have n: "n < size ST" by simp

      from stk have [simp]: "size stk = size ST" by (rule list_all2_lengthD)

      { assume "stk!n = Null" with n Invoke have ?thesis by simp }
      moreover {
        assume "ST!n = NT"
        with n stk have "stk!n = Null" by (auto simp: list_all2_conv_all_nth)
        with n Invoke have ?thesis by simp
      }
      moreover {
        assume Null: "stk!n \<noteq> Null" and NT: "ST!n \<noteq> NT"

        from NT app Invoke
        obtain D D' Ts T m where
          D:  "ST!n = Class D" and
          M': "P \<turnstile> D sees M': Ts\<rightarrow>T = m in D'" and
          Ts: "P \<turnstile> rev (take n ST) [\<le>] Ts"
          by auto

        from D stk n have "P,h \<turnstile> stk!n :\<le> Class D"
          by (auto simp: list_all2_conv_all_nth)
        with Null obtain a C' fs where
          [simp]: "stk!n = Addr a" "h a = Some (C',fs)" and
          "P \<turnstile> C' \<preceq>\<^sup>* D"
          by (fastforce dest!: conf_ClassD)

        with M' wf obtain m' Ts' T' D'' where
          C': "P \<turnstile> C' sees M': Ts'\<rightarrow>T' = m' in D''" and
          Ts': "P \<turnstile> Ts [\<le>] Ts'"
          by (auto dest!: sees_method_mono)

        from stk have "P,h \<turnstile> take n stk [:\<le>] take n ST" ..
        hence "P,h \<turnstile> rev (take n stk) [:\<le>] rev (take n ST)" ..
        also note Ts also note Ts'
        finally have "P,h \<turnstile> rev (take n stk) [:\<le>] Ts'" .

        with Invoke Null n C'
        have ?thesis by (auto simp add: is_Ref_def2 has_methodI)
      }
      ultimately show ?thesis by blast
    next
      case Return with stk app \<Phi> meth frames
      show ?thesis by (auto simp add: has_methodI)
    qed (auto simp add: list_all2_lengthD)
    hence "check P \<sigma>" using meth pc mxs by (simp add: check_def has_methodI)
  } ultimately
  have "check P \<sigma>" by blast
  thus "exec_d P \<sigma> \<noteq> TypeError" ..
qed
(*>*)

text {*
  The theorem above tells us that, in welltyped programs, the
  defensive machine reaches the same result as the aggressive
  one (after arbitrarily many steps).
*}
theorem welltyped_aggressive_imp_defensive:
  "wf_jvm_prog\<^bsub>\<Phi>\<^esub> P \<Longrightarrow> P,\<Phi> \<turnstile> \<sigma> \<surd> \<Longrightarrow> P \<turnstile> \<sigma> -jvm\<rightarrow> \<sigma>'
  \<Longrightarrow> P \<turnstile> (Normal \<sigma>) -jvmd\<rightarrow> (Normal \<sigma>')"
(*<*)
  apply (simp only: exec_all_def)
  apply (erule rtrancl_induct)
   apply (simp add: exec_all_d_def1)
  apply simp
  apply (simp only: exec_all_def [symmetric])
  apply (frule BV_correct, assumption+)
  apply (drule no_type_error, assumption, drule no_type_error_commutes, simp)
  apply (simp add: exec_all_d_def1)
  apply (rule rtrancl_trans, assumption)
  apply (drule exec_1_d_NormalI)
  apply auto
  done
(*>*)

text {*
  As corollary we get that the aggressive and the defensive machine
  are equivalent for welltyped programs (if started in a conformant
  state or in the canonical start state)
*}
corollary welltyped_commutes:
  fixes \<sigma> :: jvm_state
  assumes wf: "wf_jvm_prog\<^bsub>\<Phi>\<^esub> P" and conforms: "P,\<Phi> \<turnstile> \<sigma> \<surd>"
  shows "P \<turnstile> (Normal \<sigma>) -jvmd\<rightarrow> (Normal \<sigma>') = P \<turnstile> \<sigma> -jvm\<rightarrow> \<sigma>'"
  apply rule
  apply (erule defensive_imp_aggressive)
  apply (erule welltyped_aggressive_imp_defensive [OF wf conforms])
  done

corollary welltyped_initial_commutes:
  assumes wf: "wf_jvm_prog P"
  assumes meth: "P \<turnstile> C sees M:[]\<rightarrow>T = b in C"
  defines start: "\<sigma> \<equiv> start_state P C M"
  shows "P \<turnstile> (Normal \<sigma>) -jvmd\<rightarrow> (Normal \<sigma>') = P \<turnstile> \<sigma> -jvm\<rightarrow> \<sigma>'"
proof -
  from wf obtain \<Phi> where wf': "wf_jvm_prog\<^bsub>\<Phi>\<^esub> P" by (auto simp: wf_jvm_prog_def)
  from this meth have "P,\<Phi> \<turnstile> \<sigma> \<surd>" unfolding start by (rule BV_correct_initial)
  with wf' show ?thesis by (rule welltyped_commutes)
qed

lemma not_TypeError_eq [iff]:
  "x \<noteq> TypeError = (\<exists>t. x = Normal t)"
  by (cases x) auto

locale cnf =
  fixes P and \<Phi> and \<sigma>
  assumes wf: "wf_jvm_prog\<^bsub>\<Phi>\<^esub> P"
  assumes cnf: "correct_state P \<Phi> \<sigma>"

theorem (in cnf) no_type_errors:
  "P \<turnstile> (Normal \<sigma>) -jvmd\<rightarrow> \<sigma>' \<Longrightarrow> \<sigma>' \<noteq> TypeError"
  apply (unfold exec_all_d_def1)
  apply (erule rtrancl_induct)
   apply simp
  apply (fold exec_all_d_def1)
  apply (insert cnf wf)
  apply clarsimp
  apply (drule defensive_imp_aggressive)
  apply (frule (2) BV_correct)
  apply (drule (1) no_type_error) back
  apply (auto simp add: exec_1_d_eq)
  done

locale start =
  fixes P and C and M and \<sigma> and T and b
  assumes wf: "wf_jvm_prog P"
  assumes sees: "P \<turnstile> C sees M:[]\<rightarrow>T = b in C"
  defines "\<sigma> \<equiv> Normal (start_state P C M)"

corollary (in start) bv_no_type_error:
  shows "P \<turnstile> \<sigma> -jvmd\<rightarrow> \<sigma>' \<Longrightarrow> \<sigma>' \<noteq> TypeError"
proof -
  from wf obtain \<Phi> where "wf_jvm_prog\<^bsub>\<Phi>\<^esub> P" by (auto simp: wf_jvm_prog_def)
  moreover
  with sees have "correct_state P \<Phi> (start_state P C M)"
    by - (rule BV_correct_initial)
  ultimately have "cnf P \<Phi> (start_state P C M)" by (rule cnf.intro)
  moreover assume "P \<turnstile> \<sigma> -jvmd\<rightarrow> \<sigma>'"
  ultimately show ?thesis by (unfold \<sigma>_def) (rule cnf.no_type_errors)
qed

end


(*  Title:      RTS/JinjaSuppl/JVMExecStepInductive.thy
    Author:     Susannah Mansky
    2020, UIUC

    Program Execution in the JVM as an inductive
*)

section "Inductive JVM execution"

theory JVMExecStepInductive
imports "../../JinjaDCI/JVM/JVMExec"
begin

datatype step_input = StepI instr |
                      StepC cname "cname list" | StepC2 cname "cname list" |
                      StepT "cname list" addr

inductive exec_step_ind :: "[step_input, jvm_prog, heap, val list, val list,
                  cname, mname, pc, init_call_status, frame list, sheap,jvm_state] \<Rightarrow> bool"
where
  exec_step_ind_Load:
"exec_step_ind (StepI (Load n)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
   (None, h, ((loc ! n) # stk, loc, C\<^sub>0, M\<^sub>0, Suc pc, ics)#frs, sh)"

| exec_step_ind_Store:
"exec_step_ind (StepI (Store n)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
   (None, h, (tl stk, loc[n:=hd stk], C\<^sub>0, M\<^sub>0, Suc pc, ics)#frs, sh)"

| exec_step_ind_Push:
"exec_step_ind (StepI (Push v)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
   (None, h, (v # stk, loc, C\<^sub>0, M\<^sub>0, Suc pc, ics)#frs, sh)"

|  exec_step_ind_NewOOM_Called:
"new_Addr h = None
  \<Longrightarrow> exec_step_ind (StepI (New C)) P h stk loc C\<^sub>0 M\<^sub>0 pc (Called Cs) frs sh
   (\<lfloor>addr_of_sys_xcpt OutOfMemory\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, No_ics)#frs, sh)"

|  exec_step_ind_NewOOM_Done:
"\<lbrakk> sh C = Some(obj, Done); new_Addr h = None; \<forall>Cs. ics \<noteq> Called Cs \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (New C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
   (\<lfloor>addr_of_sys_xcpt OutOfMemory\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

|  exec_step_ind_New_Called:
"new_Addr h = Some a
  \<Longrightarrow> exec_step_ind (StepI (New C)) P h stk loc C\<^sub>0 M\<^sub>0 pc (Called Cs) frs sh
   (None, h(a\<mapsto>blank P C), (Addr a#stk, loc, C\<^sub>0, M\<^sub>0, Suc pc, No_ics)#frs, sh)"

|  exec_step_ind_New_Done:
"\<lbrakk> sh C = Some(obj, Done); new_Addr h = Some a; \<forall>Cs. ics \<noteq> Called Cs \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (New C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
   (None, h(a\<mapsto>blank P C), (Addr a#stk, loc, C\<^sub>0, M\<^sub>0, Suc pc, ics)#frs, sh)"

|  exec_step_ind_New_Init:
"\<lbrakk> \<forall>obj. sh C \<noteq> Some(obj, Done); \<forall>Cs. ics \<noteq> Called Cs \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (New C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
   (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, Calling C [])#frs, sh)"

| exec_step_ind_Getfield_Null:
"hd stk = Null
  \<Longrightarrow> exec_step_ind (StepI (Getfield F C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
   (\<lfloor>addr_of_sys_xcpt NullPointer\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Getfield_NoField:
"\<lbrakk> v = hd stk; (D,fs) = the(h(the_Addr v)); v \<noteq> Null; \<not>(\<exists>t b. P \<turnstile> D has F,b:t in C) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Getfield F C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
   (\<lfloor>addr_of_sys_xcpt NoSuchFieldError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Getfield_Static:
"\<lbrakk> v = hd stk; (D,fs) = the(h(the_Addr v)); v \<noteq> Null; P \<turnstile> D has F,Static:t in C \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Getfield F C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
   (\<lfloor>addr_of_sys_xcpt IncompatibleClassChangeError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Getfield:
"\<lbrakk> v = hd stk; (D,fs) = the(h(the_Addr v)); (D',b,t) = field P C F; v \<noteq> Null;
   P \<turnstile> D has F,NonStatic:t in C \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Getfield F C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
   (None, h, (the(fs(F,C))#(tl stk), loc, C\<^sub>0, M\<^sub>0, pc+1, ics)#frs, sh)"

| exec_step_ind_Getstatic_NoField:
"\<not>(\<exists>t b. P \<turnstile> C has F,b:t in D)
  \<Longrightarrow> exec_step_ind (StepI (Getstatic C F D)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>addr_of_sys_xcpt NoSuchFieldError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Getstatic_NonStatic:
"P \<turnstile> C has F,NonStatic:t in D
  \<Longrightarrow> exec_step_ind (StepI (Getstatic C F D)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>addr_of_sys_xcpt IncompatibleClassChangeError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Getstatic_Called:
"\<lbrakk> (D',b,t) = field P D F; P \<turnstile> C has F,Static:t in D;
   v = the ((fst(the(sh D'))) F) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Getstatic C F D)) P h stk loc C\<^sub>0 M\<^sub>0 pc (Called Cs) frs sh
    (None, h, (v#stk, loc, C\<^sub>0, M\<^sub>0, Suc pc, No_ics)#frs, sh)"

| exec_step_ind_Getstatic_Done:
"\<lbrakk> (D',b,t) = field P D F; P \<turnstile> C has F,Static:t in D;
   \<forall>Cs. ics \<noteq> Called Cs; sh D' = Some(sfs,Done);
   v = the (sfs F) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Getstatic C F D)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (v#stk, loc, C\<^sub>0, M\<^sub>0, Suc pc, ics)#frs, sh)"

| exec_step_ind_Getstatic_Init:
"\<lbrakk> (D',b,t) = field P D F; P \<turnstile> C has F,Static:t in D;
   \<forall>sfs. sh D' \<noteq> Some(sfs,Done); \<forall>Cs. ics \<noteq> Called Cs \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Getstatic C F D)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, Calling D' [])#frs, sh)"

| exec_step_ind_Putfield_Null:
"hd(tl stk) = Null
  \<Longrightarrow> exec_step_ind (StepI (Putfield F C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
  (\<lfloor>addr_of_sys_xcpt NullPointer\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Putfield_NoField:
"\<lbrakk> r = hd(tl stk); a = the_Addr r; (D,fs) = the (h a); r \<noteq> Null; \<not>(\<exists>t b. P \<turnstile> D has F,b:t in C) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Putfield F C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
  (\<lfloor>addr_of_sys_xcpt NoSuchFieldError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Putfield_Static:
"\<lbrakk> r = hd(tl stk); a = the_Addr r; (D,fs) = the (h a); r \<noteq> Null; P \<turnstile> D has F,Static:t in C \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Putfield F C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
  (\<lfloor>addr_of_sys_xcpt IncompatibleClassChangeError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Putfield:
"\<lbrakk> v = hd stk; r = hd(tl stk); a = the_Addr r; (D,fs) = the (h a); (D',b,t) = field P C F;
   r \<noteq> Null; P \<turnstile> D has F,NonStatic:t in C \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Putfield F C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
  (None, h(a \<mapsto> (D, fs((F,C) \<mapsto> v))), (tl (tl stk), loc, C\<^sub>0, M\<^sub>0, pc+1, ics)#frs, sh)"

| exec_step_ind_Putstatic_NoField:
"\<not>(\<exists>t b. P \<turnstile> C has F,b:t in D)
  \<Longrightarrow> exec_step_ind (StepI (Putstatic C F D)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>addr_of_sys_xcpt NoSuchFieldError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Putstatic_NonStatic:
"P \<turnstile> C has F,NonStatic:t in D
  \<Longrightarrow> exec_step_ind (StepI (Putstatic C F D)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>addr_of_sys_xcpt IncompatibleClassChangeError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Putstatic_Called:
"\<lbrakk> (D',b,t) = field P D F; P \<turnstile> C has F,Static:t in D; the(sh D') = (sfs,i) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Putstatic C F D)) P h stk loc C\<^sub>0 M\<^sub>0 pc (Called Cs) frs sh
    (None, h, (tl stk, loc, C\<^sub>0, M\<^sub>0, Suc pc, No_ics)#frs, sh(D':=Some ((sfs(F \<mapsto> hd stk)), i)))"

| exec_step_ind_Putstatic_Done:
"\<lbrakk> (D',b,t) = field P D F; P \<turnstile> C has F,Static:t in D;
   \<forall>Cs. ics \<noteq> Called Cs; sh D' = Some (sfs, Done) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Putstatic C F D)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (tl stk, loc, C\<^sub>0, M\<^sub>0, Suc pc, ics)#frs, sh(D':=Some ((sfs(F \<mapsto> hd stk)), Done)))"

| exec_step_ind_Putstatic_Init:
"\<lbrakk> (D',b,t) = field P D F; P \<turnstile> C has F,Static:t in D;
   \<forall>sfs. sh D' \<noteq> Some (sfs, Done); \<forall>Cs. ics \<noteq> Called Cs \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Putstatic C F D)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, Calling D' [])#frs, sh)"

| exec_step_ind_Checkcast:
"cast_ok P C h (hd stk)
  \<Longrightarrow> exec_step_ind (StepI (Checkcast C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, Suc pc, ics)#frs, sh)"

| exec_step_ind_Checkcast_Error:
"\<not>cast_ok P C h (hd stk)
  \<Longrightarrow> exec_step_ind (StepI (Checkcast C)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>addr_of_sys_xcpt ClassCast\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Invoke_Null:
"stk!n = Null
  \<Longrightarrow> exec_step_ind (StepI (Invoke M n)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>addr_of_sys_xcpt NullPointer\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Invoke_NoMethod:
"\<lbrakk> r = stk!n; C = fst(the(h(the_Addr r))); r \<noteq> Null;
   \<not>(\<exists>Ts T m D b. P \<turnstile> C sees M,b:Ts \<rightarrow> T = m in D) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Invoke M n)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>addr_of_sys_xcpt NoSuchMethodError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Invoke_Static:
"\<lbrakk> r = stk!n; C = fst(the(h(the_Addr r)));
   (D,b,Ts,T,mxs,mxl\<^sub>0,ins,xt)= method P C M; r \<noteq> Null;
   P \<turnstile> C sees M,Static:Ts \<rightarrow> T = m in D \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Invoke M n)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>addr_of_sys_xcpt IncompatibleClassChangeError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Invoke:
"\<lbrakk> ps = take n stk; r = stk!n; C = fst(the(h(the_Addr r)));
   (D,b,Ts,T,mxs,mxl\<^sub>0,ins,xt)= method P C M; r \<noteq> Null;
   P \<turnstile> C sees M,NonStatic:Ts \<rightarrow> T = m in D;
   f' = ([],[r]@(rev ps)@(replicate mxl\<^sub>0 undefined),D,M,0,No_ics) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Invoke M n)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, f'#(stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Invokestatic_NoMethod:
"\<lbrakk> (D,b,Ts,T,mxs,mxl\<^sub>0,ins,xt)= method P C M; \<not>(\<exists>Ts T m D b. P \<turnstile> C sees M,b:Ts \<rightarrow> T = m in D) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Invokestatic C M n)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>addr_of_sys_xcpt NoSuchMethodError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Invokestatic_NonStatic:
"\<lbrakk> (D,b,Ts,T,mxs,mxl\<^sub>0,ins,xt)= method P C M; P \<turnstile> C sees M,NonStatic:Ts \<rightarrow> T = m in D \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Invokestatic C M n)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>addr_of_sys_xcpt IncompatibleClassChangeError\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Invokestatic_Called:
"\<lbrakk> ps  = take n stk; (D,b,Ts,T,mxs,mxl\<^sub>0,ins,xt) = method P C M;
   P \<turnstile> C sees M,Static:Ts \<rightarrow> T = m in D;
   f'  = ([],(rev ps)@(replicate mxl\<^sub>0 undefined),D,M,0,No_ics) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Invokestatic C M n)) P h stk loc C\<^sub>0 M\<^sub>0 pc (Called Cs) frs sh
    (None, h, f'#(stk, loc, C\<^sub>0, M\<^sub>0, pc, No_ics)#frs, sh)"

| exec_step_ind_Invokestatic_Done:
"\<lbrakk> ps  = take n stk; (D,b,Ts,T,mxs,mxl\<^sub>0,ins,xt) = method P C M;
   P \<turnstile> C sees M,Static:Ts \<rightarrow> T = m in D;
   \<forall>Cs. ics \<noteq> Called Cs; sh D = Some (sfs, Done);
   f'  = ([],(rev ps)@(replicate mxl\<^sub>0 undefined),D,M,0,No_ics) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Invokestatic C M n)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, f'#(stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Invokestatic_Init:
"\<lbrakk> (D,b,Ts,T,mxs,mxl\<^sub>0,ins,xt) = method P C M;
   P \<turnstile> C sees M,Static:Ts \<rightarrow> T = m in D;
   \<forall>sfs. sh D \<noteq> Some (sfs, Done); \<forall>Cs. ics \<noteq> Called Cs \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepI (Invokestatic C M n)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, Calling D [])#frs, sh)"

| exec_step_ind_Return_Last_Init:
 "exec_step_ind (StepI Return) P h stk\<^sub>0 loc\<^sub>0 C\<^sub>0 clinit pc ics [] sh
    (None, h, [], sh(C\<^sub>0:=Some(fst(the(sh C\<^sub>0)), Done)))"

| exec_step_ind_Return_Last:
 "M\<^sub>0 \<noteq> clinit
   \<Longrightarrow> exec_step_ind (StepI Return) P h stk\<^sub>0 loc\<^sub>0 C\<^sub>0 M\<^sub>0 pc ics [] sh (None, h, [], sh)"

| exec_step_ind_Return_Init:
 "\<lbrakk> (D,b,Ts,T,m) = method P C\<^sub>0 clinit \<rbrakk>
   \<Longrightarrow> exec_step_ind (StepI Return) P h stk\<^sub>0 loc\<^sub>0 C\<^sub>0 clinit pc ics ((stk',loc',C',m',pc',ics')#frs') sh
     (None, h, (stk',loc',C',m',pc',ics')#frs', sh(C\<^sub>0:=Some(fst(the(sh C\<^sub>0)), Done)))"

| exec_step_ind_Return_NonStatic:
 "\<lbrakk> (D,NonStatic,Ts,T,m) = method P C\<^sub>0 M\<^sub>0; M\<^sub>0 \<noteq> clinit \<rbrakk>
   \<Longrightarrow> exec_step_ind (StepI Return) P h stk\<^sub>0 loc\<^sub>0 C\<^sub>0 M\<^sub>0 pc ics ((stk',loc',C',m',pc',ics')#frs') sh
     (None, h, ((hd stk\<^sub>0)#(drop (length Ts + 1) stk'),loc',C',m',Suc pc',ics')#frs', sh)"

| exec_step_ind_Return_Static:
 "\<lbrakk> (D,Static,Ts,T,m) = method P C\<^sub>0 M\<^sub>0; M\<^sub>0 \<noteq> clinit \<rbrakk>
   \<Longrightarrow> exec_step_ind (StepI Return) P h stk\<^sub>0 loc\<^sub>0 C\<^sub>0 M\<^sub>0 pc ics ((stk',loc',C',m',pc',ics')#frs') sh
     (None, h, ((hd stk\<^sub>0)#(drop (length Ts) stk'),loc',C',m',Suc pc',ics')#frs', sh)"

| exec_step_ind_Pop:
"exec_step_ind (StepI Pop) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
  (None, h, (tl stk, loc, C\<^sub>0, M\<^sub>0, Suc pc, ics)#frs, sh)"

| exec_step_ind_IAdd:
"exec_step_ind (StepI IAdd) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
  (None, h, (Intg (the_Intg (hd (tl stk)) + the_Intg (hd stk))#(tl (tl stk)), loc, C\<^sub>0, M\<^sub>0, Suc pc, ics)#frs, sh)"

| exec_step_ind_IfFalse_False:
"hd stk = Bool False
  \<Longrightarrow> exec_step_ind (StepI (IfFalse i)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (tl stk, loc, C\<^sub>0, M\<^sub>0, nat(int pc+i), ics)#frs, sh)"

| exec_step_ind_IfFalse_nFalse:
"hd stk \<noteq> Bool False
  \<Longrightarrow> exec_step_ind (StepI (IfFalse i)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (tl stk, loc, C\<^sub>0, M\<^sub>0, Suc pc, ics)#frs, sh)"

| exec_step_ind_CmpEq:
"exec_step_ind (StepI CmpEq) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (Bool (hd (tl stk) = hd stk) # tl (tl stk), loc, C\<^sub>0, M\<^sub>0, Suc pc, ics)#frs, sh)"

| exec_step_ind_Goto:
"exec_step_ind (StepI (Goto i)) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
   (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, nat(int pc+i), ics)#frs, sh)"

| exec_step_ind_Throw:
"hd stk \<noteq> Null
  \<Longrightarrow> exec_step_ind (StepI Throw) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>the_Addr (hd stk)\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Throw_Null:
"hd stk = Null
  \<Longrightarrow> exec_step_ind (StepI Throw) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>addr_of_sys_xcpt NullPointer\<rfloor>, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, ics)#frs, sh)"

| exec_step_ind_Init_None_Called:
"\<lbrakk> sh C = None \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepC C Cs) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, Calling C Cs)#frs, sh(C := Some (sblank P C, Prepared)))"

| exec_step_ind_Init_Done:
"sh C = Some (sfs, Done)
  \<Longrightarrow> exec_step_ind (StepC C Cs) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, Called Cs)#frs, sh)"

| exec_step_ind_Init_Processing:
"sh C = Some (sfs, Processing)
  \<Longrightarrow> exec_step_ind (StepC C Cs) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, Called Cs)#frs, sh)"

| exec_step_ind_Init_Error:
"\<lbrakk> sh C = Some (sfs, Error) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepC C Cs) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, Throwing Cs (addr_of_sys_xcpt NoClassDefFoundError))#frs, sh)"

| exec_step_ind_Init_Prepared_Object:
"\<lbrakk> sh C = Some (sfs, Prepared);
   sh' = sh(C:=Some(fst(the(sh C)), Processing));
   C = Object \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepC C Cs) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, Called (C#Cs))#frs, sh')"

| exec_step_ind_Init_Prepared_nObject:
"\<lbrakk> sh C = Some (sfs, Prepared);
   sh' = sh(C:=Some(fst(the(sh C)), Processing));
   C \<noteq> Object; D = fst(the(class P C)) \<rbrakk>
  \<Longrightarrow> exec_step_ind (StepC C Cs) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (stk, loc, C\<^sub>0, M\<^sub>0, pc, Calling D (C#Cs))#frs, sh')"

| exec_step_ind_Init:
"exec_step_ind (StepC2 C Cs) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, create_init_frame P C#(stk, loc, C\<^sub>0, M\<^sub>0, pc, Called Cs)#frs, sh)"

| exec_step_ind_InitThrow:
"exec_step_ind (StepT (C#Cs) a) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (None, h, (stk,loc,C\<^sub>0,M\<^sub>0,pc,Throwing Cs a)#frs, (sh(C \<mapsto> (fst(the(sh C)), Error))))"

| exec_step_ind_InitThrow_End:
"exec_step_ind (StepT [] a) P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh
    (\<lfloor>a\<rfloor>, h, (stk,loc,C\<^sub>0,M\<^sub>0,pc,No_ics)#frs, sh)"

(** ******* **)

inductive_cases exec_step_ind_cases [cases set]:
 "exec_step_ind (StepI (Load n)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (Store n)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (Push v)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (New C)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (Getfield F C)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (Getstatic C F D)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (Putfield F C)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (Putstatic C F D)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (Checkcast C)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (Invoke M n)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (Invokestatic C M n)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI Return) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI Pop) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI IAdd) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (IfFalse i)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI CmpEq) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI (Goto i)) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepI Throw) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepC C' Cs) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepC2 C' Cs) P h stk loc C M pc ics frs sh \<sigma>"
 "exec_step_ind (StepT Cs a) P h stk loc C M pc ics frs sh \<sigma>"

\<comment> \<open> Deriving @{term step_input} for @{term exec_step_ind} from @{term exec_step} arguments \<close>
fun exec_step_input :: "[jvm_prog, cname, mname, pc, init_call_status] \<Rightarrow> step_input" where
"exec_step_input P C M pc (Calling C' Cs) = StepC C' Cs" |
"exec_step_input P C M pc (Called (C'#Cs)) = StepC2 C' Cs" |
"exec_step_input P C M pc (Throwing Cs a) = StepT Cs a" |
"exec_step_input P C M pc ics = StepI (instrs_of P C M ! pc)"

lemma exec_step_input_StepTD[simp]:
assumes "exec_step_input P C M pc ics = StepT Cs a" shows "ics = Throwing Cs a"
using assms proof(cases ics)
  case (Called Cs) with assms show ?thesis by(cases Cs; simp)
qed(auto)

lemma exec_step_input_StepCD[simp]:
assumes "exec_step_input P C M pc ics = StepC C' Cs" shows "ics = Calling C' Cs"
using assms proof(cases ics)
  case (Called Cs) with assms show ?thesis by(cases Cs; simp)
qed(auto)

lemma exec_step_input_StepC2D[simp]:
assumes "exec_step_input P C M pc ics = StepC2 C' Cs" shows "ics = Called (C'#Cs)"
using assms proof(cases ics)
  case (Called Cs) with assms show ?thesis by(cases Cs; simp)
qed(auto)

lemma exec_step_input_StepID:
assumes "exec_step_input P C M pc ics = StepI i"
shows "(ics = Called [] \<or> ics = No_ics) \<and> instrs_of P C M ! pc = i"
using assms proof(cases ics)
  case (Called Cs) with assms show ?thesis by(cases Cs; simp)
qed(auto)

subsection "Equivalence of @{term exec_step} and @{term exec_step_input}"

lemma exec_step_imp_exec_step_ind:
assumes es: "exec_step P h stk loc C M pc ics frs sh = (xp', h', frs', sh')"
shows "exec_step_ind (exec_step_input P C M pc ics) P h stk loc C M pc ics frs sh (xp', h', frs', sh')"
proof(cases "exec_step_input P C M pc ics")
  case (StepT Cs a)
  then have "ics = Throwing Cs a" by simp
  then show ?thesis using exec_step_ind_InitThrow exec_step_ind_InitThrow_End StepT es
   by(cases Cs, auto)
next
  case (StepC C1 Cs)
  then have ics: "ics = Calling C1 Cs" by simp
  obtain D b Ts T m where lets: "method P C1 clinit = (D,b,Ts,T,m)" by(cases "method P C1 clinit")
  then obtain mxs mxl\<^sub>0 ins xt where m: "m = (mxs,mxl\<^sub>0,ins,xt)" by(cases m)
  show ?thesis
  proof(cases "sh C1")
    case None then show ?thesis
     using exec_step_ind_Init_None_Called ics assms by auto
  next
    case (Some a)
    then obtain sfs i where sfsi: "a = (sfs,i)" by(cases a)
    then show ?thesis using exec_step_ind_Init_Done exec_step_ind_Init_Processing
      exec_step_ind_Init_Error m lets Some ics assms
    proof(cases i)
      case Prepared
      show ?thesis
      using exec_step_ind_Init_Prepared_Object[where P=P] exec_step_ind_Init_Prepared_nObject
       sfsi m lets Prepared Some ics assms by(auto split: if_split_asm)
    qed(auto)
  qed
next
  case (StepC2 C1 Cs)
  then have ics: "ics = Called (C1#Cs)" by simp
  then show ?thesis using exec_step_ind_Init assms by auto
next
  case (StepI i)
  then have
    ics: "ics = Called [] \<or> ics = No_ics" and
    exec_instr: "exec_instr i P h stk loc C M pc ics frs sh = (xp', h', frs', sh')"
    using assms by(auto dest!: exec_step_input_StepID)
  show ?thesis
  proof(cases i)
    case (Load x1) then show ?thesis using exec_instr exec_step_ind_Load StepI by auto
  next
    case (Store x2) then show ?thesis using exec_instr exec_step_ind_Store StepI by auto
  next
    case (Push x3) then show ?thesis using exec_instr exec_step_ind_Push StepI by auto
  next
    case (New C1)
    then obtain sfs i where sfsi: "the(sh C1) = (sfs,i)" by(cases "the(sh C1)")
    then show ?thesis using exec_step_ind_New_Called exec_step_ind_NewOOM_Called
       exec_step_ind_New_Done exec_step_ind_NewOOM_Done
       exec_step_ind_New_Init sfsi New StepI exec_instr ics by(auto split: init_state.splits)
  next
    case (Getfield F1 C1)
    then obtain D fs D' b t where lets: "the(h(the_Addr (hd stk))) = (D,fs)"
      "field P C1 F1 = (D',b,t)" by(cases "the(h(the_Addr (hd stk)))", cases "field P C1 F1")
    then have "\<And>b' t'. P \<turnstile> D has F1,b':t' in C1 \<Longrightarrow> (D', b, t) = (C1, b', t')"
      using field_def2 has_field_idemp has_field_sees by fastforce
    then show ?thesis using exec_step_ind_Getfield_Null exec_step_ind_Getfield_NoField
       exec_step_ind_Getfield_Static exec_step_ind_Getfield lets Getfield StepI exec_instr
      by(auto split: if_split_asm staticb.splits) metis+
  next
    case (Getstatic C1 F1 D1)
    then obtain D' b t where lets: "field P D1 F1 = (D',b,t)" by(cases "field P D1 F1")
    then have field: "\<And>b' t'. P \<turnstile> C1 has F1,b':t' in D1 \<Longrightarrow> (D', b, t) = (D1, b', t')"
      using field_def2 has_field_idemp has_field_sees by fastforce
    show ?thesis
    proof(cases b)
      case NonStatic then show ?thesis
       using exec_step_ind_Getstatic_NoField exec_step_ind_Getstatic_NonStatic
        field lets Getstatic exec_instr StepI by(auto split: if_split_asm) fastforce
    next
      case Static show ?thesis
      proof(cases "ics = Called []")
        case True then show ?thesis using exec_step_ind_Getstatic_NoField
          exec_step_ind_Getstatic_Called exec_step_ind_Getstatic_Init
          Static field lets Getstatic exec_instr StepI ics
         by(auto simp: split_beta split: if_split_asm) metis
      next
        case False
        then have nCalled: "\<forall>Cs. ics \<noteq> Called Cs" using ics by simp
        show ?thesis
        proof(cases "sh D1")
          case None
          then have nDone: "\<forall>sfs. sh D1 \<noteq> Some(sfs, Done)" by simp
          then show ?thesis using exec_step_ind_Getstatic_NoField
            exec_step_ind_Getstatic_Init[where sh=sh, OF _ _ nDone nCalled]
            field lets None False Static Getstatic exec_instr StepI ics
           by(auto split: if_split_asm) metis
        next
          case (Some a)
          then obtain sfs i where sfsi: "a=(sfs,i)" by(cases a)
          show ?thesis using exec_step_ind_Getstatic_NoField
            exec_step_ind_Getstatic_Init sfsi False Static Some field lets Getstatic exec_instr
          proof(cases "i = Done")
            case True then show ?thesis using exec_step_ind_Getstatic_NoField
              exec_step_ind_Getstatic_Done[OF _ _ nCalled] exec_step_ind_Getstatic_Init
              sfsi False Static Some field lets Getstatic exec_instr StepI ics
             by(auto split: if_split_asm) metis
          next
            case nD: False
            then have nDone: "\<forall>sfs. sh D1 \<noteq> Some(sfs, Done)" using sfsi Some by simp
            show ?thesis using nD
            proof(cases i)
              case Processing then show ?thesis using exec_step_ind_Getstatic_NoField
                exec_step_ind_Getstatic_Init[where sh=sh, OF _ _ nDone nCalled]
                sfsi False Static Some field lets Getstatic exec_instr StepI ics
               by(auto split: if_split_asm) metis
            next
              case Prepared then show ?thesis using exec_step_ind_Getstatic_NoField
                exec_step_ind_Getstatic_Init[where sh=sh, OF _ _ nDone nCalled]
                sfsi False Static Some field lets Getstatic exec_instr StepI ics
               by(auto split: if_split_asm) metis
            next
              case Error then show ?thesis using exec_step_ind_Getstatic_NoField
                exec_step_ind_Getstatic_Init[where sh=sh, OF _ _ nDone nCalled]
                sfsi False Static Some field lets Getstatic exec_instr StepI ics
               by(auto split: if_split_asm) metis
            qed(simp)
          qed
        qed
      qed
    qed
  next
    case (Putfield F1 C1)
    then obtain D fs D' b t where lets: "the(h(the_Addr (hd(tl stk)))) = (D,fs)"
      "field P C1 F1 = (D',b,t)" by(cases "the(h(the_Addr (hd(tl stk))))", cases "field P C1 F1")
    then have "\<And>b' t'. P \<turnstile> D has F1,b':t' in C1 \<Longrightarrow> (D', b, t) = (C1, b', t')"
      using field_def2 has_field_idemp has_field_sees by fastforce
    then show ?thesis using exec_step_ind_Putfield_Null exec_step_ind_Putfield_NoField
       exec_step_ind_Putfield_Static exec_step_ind_Putfield lets Putfield exec_instr StepI
      by(auto split: if_split_asm staticb.splits) metis+
  next
    case (Putstatic C1 F1 D1)
    then obtain D' b t where lets: "field P D1 F1 = (D',b,t)" by(cases "field P D1 F1")
    then have field: "\<And>b' t'. P \<turnstile> C1 has F1,b':t' in D1 \<Longrightarrow> (D', b, t) = (D1, b', t')"
      using field_def2 has_field_idemp has_field_sees by fastforce
    show ?thesis
    proof(cases b)
      case NonStatic then show ?thesis
       using exec_step_ind_Putstatic_NoField exec_step_ind_Putstatic_NonStatic
        field lets Putstatic exec_instr StepI by(auto split: if_split_asm) fastforce
    next
      case Static show ?thesis
      proof(cases "ics = Called []")
        case True then show ?thesis using exec_step_ind_Putstatic_NoField
          exec_step_ind_Putstatic_Called exec_step_ind_Putstatic_Init
          Static field lets Putstatic exec_instr StepI ics
         by(cases "the(sh D1)", auto split: if_split_asm) metis
      next
        case False
        then have nCalled: "\<forall>Cs. ics \<noteq> Called Cs" using ics by simp
        show ?thesis
        proof(cases "sh D1")
          case None
          then have nDone: "\<forall>sfs. sh D1 \<noteq> Some(sfs, Done)" by simp
          then show ?thesis using exec_step_ind_Putstatic_NoField
            exec_step_ind_Putstatic_Init[where sh=sh, OF _ _ nDone nCalled]
            field lets None False Static Putstatic exec_instr StepI ics
           by(auto split: if_split_asm) metis
        next
          case (Some a)
          then obtain sfs i where sfsi: "a=(sfs,i)" by(cases a)
          show ?thesis using exec_step_ind_Putstatic_NoField
            exec_step_ind_Putstatic_Init sfsi False Static Some field lets Putstatic exec_instr
          proof(cases "i = Done")
            case True then show ?thesis using exec_step_ind_Putstatic_NoField
              exec_step_ind_Putstatic_Done[OF _ _ nCalled] exec_step_ind_Putstatic_Init
              sfsi False Static Some field lets Putstatic exec_instr StepI ics
             by(auto split: if_split_asm) metis
          next
            case nD: False
            then have nDone: "\<forall>sfs. sh D1 \<noteq> Some(sfs, Done)" using sfsi Some by simp
            show ?thesis using nD
            proof(cases i)
              case Processing then show ?thesis using exec_step_ind_Putstatic_NoField
                exec_step_ind_Putstatic_Init[where sh=sh, OF _ _ nDone nCalled]
                sfsi False Static Some field lets Putstatic exec_instr StepI ics
               by(auto split: if_split_asm) metis
            next
              case Prepared then show ?thesis using exec_step_ind_Putstatic_NoField
                exec_step_ind_Putstatic_Init[where sh=sh, OF _ _ nDone nCalled]
                sfsi False Static Some field lets Putstatic exec_instr StepI ics
               by(auto split: if_split_asm) metis
            next
              case Error then show ?thesis using exec_step_ind_Putstatic_NoField
                exec_step_ind_Putstatic_Init[where sh=sh, OF _ _ nDone nCalled]
                sfsi False Static Some field lets Putstatic exec_instr StepI ics
               by(auto split: if_split_asm) metis
            qed(simp)
          qed
        qed
      qed
    qed
  next
    case Checkcast then show ?thesis
     using exec_step_ind_Checkcast exec_step_ind_Checkcast_Error exec_instr StepI
       by(auto split: if_split_asm)
  next
    case (Invoke M1 n) show ?thesis
    proof(cases "stk!n = Null")
      case True then show ?thesis using exec_step_ind_Invoke_Null Invoke exec_instr StepI
       by clarsimp
    next
      case False
      let ?C = "cname_of h (the_Addr (stk ! n))"
      obtain D b Ts T m where method: "method P ?C M1 = (D,b,Ts,T,m)" by(cases "method P ?C M1")
      then obtain mxs mxl\<^sub>0 ins xt where "m = (mxs,mxl\<^sub>0,ins,xt)" by(cases m)
      then show ?thesis using exec_step_ind_Invoke_NoMethod
        exec_step_ind_Invoke_Static exec_step_ind_Invoke method False Invoke exec_instr StepI
       by(auto split: if_split_asm staticb.splits)
    qed
  next
    case (Invokestatic C1 M1 n)
    obtain D b Ts T m where lets: "method P C1 M1 = (D,b,Ts,T,m)" by(cases "method P C1 M1")
    then obtain mxs mxl\<^sub>0 ins xt where m: "m = (mxs,mxl\<^sub>0,ins,xt)" by(cases m)
    have method: "\<And>b' Ts' t' m' D'. P \<turnstile> C1 sees M1,b':Ts' \<rightarrow> t' = m' in D'
     \<Longrightarrow> (D,b,Ts,T,m) = (D',b',Ts',t',m')" using lets by auto
    show ?thesis
    proof(cases b)
      case NonStatic then show ?thesis
       using exec_step_ind_Invokestatic_NoMethod exec_step_ind_Invokestatic_NonStatic
        m method lets Invokestatic exec_instr StepI  by(auto split: if_split_asm)
    next
      case Static show ?thesis
      proof(cases "ics = Called []")
        case True then show ?thesis using exec_step_ind_Invokestatic_NoMethod
          exec_step_ind_Invokestatic_Called exec_step_ind_Invokestatic_Init
          Static m method lets Invokestatic exec_instr StepI ics
         by(auto split: if_split_asm)
      next
        case False
        then have nCalled: "\<forall>Cs. ics \<noteq> Called Cs" using ics by simp
        show ?thesis
        proof(cases "sh D")
          case None
          then have nDone: "\<forall>sfs. sh D \<noteq> Some(sfs, Done)" by simp
          show ?thesis using exec_step_ind_Invokestatic_NoMethod
            exec_step_ind_Invokestatic_Init[where sh=sh, OF _ _ nDone nCalled]
            method m lets None False Static Invokestatic exec_instr StepI ics
           by(auto split: if_split_asm)
        next
          case (Some a)
          then obtain sfs i where sfsi: "a=(sfs,i)" by(cases a)
          show ?thesis using exec_step_ind_Invokestatic_NoMethod
            exec_step_ind_Invokestatic_Init sfsi False Static Some method lets Invokestatic exec_instr
          proof(cases "i = Done")
            case True then show ?thesis using exec_step_ind_Invokestatic_NoMethod
              exec_step_ind_Invokestatic_Done[OF _ _ _ nCalled] exec_step_ind_Invokestatic_Init
              sfsi False Static Some m method lets Invokestatic exec_instr StepI ics
             by(auto split: if_split_asm)
          next
            case nD: False
            then have nDone: "\<forall>sfs. sh D \<noteq> Some(sfs, Done)" using sfsi Some by simp
            show ?thesis using nD
            proof(cases i)
              case Processing then show ?thesis using exec_step_ind_Invokestatic_NoMethod
                exec_step_ind_Invokestatic_Init[where sh=sh, OF _ _ nDone nCalled]
                sfsi False Static Some m method lets Invokestatic exec_instr StepI ics
               by(auto split: if_split_asm)
            next
              case Prepared then show ?thesis using exec_step_ind_Invokestatic_NoMethod
                exec_step_ind_Invokestatic_Init[where sh=sh, OF _ _ nDone nCalled]
                sfsi False Static Some m method lets Invokestatic exec_instr StepI ics
               by(auto split: if_split_asm)
            next
              case Error then show ?thesis using exec_step_ind_Invokestatic_NoMethod
                exec_step_ind_Invokestatic_Init[where sh=sh, OF _ _ nDone nCalled]
                sfsi False Static Some m method lets Invokestatic exec_instr StepI ics
               by(auto split: if_split_asm)
            qed(simp)
          qed
        qed
      qed
    qed
  next
    case Return
    obtain D b Ts T m where method: "method P C M = (D,b,Ts,T,m)" by(cases "method P C M")
    then obtain mxs mxl\<^sub>0 ins xt where "m = (mxs,mxl\<^sub>0,ins,xt)" by(cases m)
    then show ?thesis using exec_step_ind_Return_Last_Init exec_step_ind_Return_Last
      exec_step_ind_Return_Init exec_step_ind_Return_NonStatic exec_step_ind_Return_Static
       method Return exec_instr StepI ics
      by(auto split: if_split_asm staticb.splits bool.splits list.splits)
  next
    case Pop then show ?thesis using exec_instr StepI exec_step_ind_Pop by auto
  next
    case IAdd then show ?thesis using exec_instr StepI exec_step_ind_IAdd by auto
  next
    case Goto then show ?thesis using exec_instr StepI exec_step_ind_Goto by auto
  next
    case CmpEq then show ?thesis using exec_instr StepI exec_step_ind_CmpEq by auto
  next
    case (IfFalse x17) then show ?thesis
     using exec_instr StepI exec_step_ind_IfFalse_nFalse exec_step_ind_IfFalse_False
       exec_instr StepI by(auto split: val.splits staticb.splits)
  next
    case Throw then show ?thesis
     using exec_instr StepI exec_step_ind_Throw exec_step_ind_Throw_Null
       by(auto split: val.splits)
  qed
qed

lemma exec_step_ind_imp_exec_step:
assumes esi: "exec_step_ind si P h stk loc C M pc ics frs sh (xp', h', frs', sh')"
  and si: "exec_step_input P C M pc ics = si"
shows "exec_step P h stk loc C M pc ics frs sh = (xp', h', frs', sh')"
proof -
  have StepI:
   "\<And>P C M pc Cs i . exec_step_input P C M pc (Called Cs) = StepI i
           \<Longrightarrow> instrs_of P C M ! pc = i \<and> Cs = []"
  proof -
    fix P C M pc Cs i show "exec_step_input P C M pc (Called Cs) = StepI i
           \<Longrightarrow> instrs_of P C M ! pc = i \<and> Cs = []" by(cases Cs; simp)
  qed
  have StepC:
   "\<And>P C M pc ics C' Cs. exec_step_input P C M pc ics = StepC C' Cs \<Longrightarrow> ics = Calling C' Cs"
     by simp
  have StepT:
   "\<And>P C M pc ics Cs a. exec_step_input P C M pc ics = StepT Cs a \<Longrightarrow> ics = Throwing Cs a"
     by simp
  show ?thesis using assms
  proof(induct rule: exec_step_ind.induct)
    case (exec_step_ind_NewOOM_Done sh C obj h ics P stk loc C\<^sub>0 M\<^sub>0 pc frs)
    then show ?case by(cases ics, auto)
  next
    case (exec_step_ind_New_Done sh C obj h a ics P stk loc C\<^sub>0 M\<^sub>0 pc frs)
    then show ?case by(cases ics, auto)
  next
    case (exec_step_ind_New_Init sh C ics P h stk loc C\<^sub>0 M\<^sub>0 pc frs)
    then show ?case by(cases ics, auto split: init_state.splits)
  next
    case (exec_step_ind_Getfield_NoField v stk D fs h P F C loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases "the (h (the_Addr (hd stk)))", cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Getfield_Static v stk D fs h P F t C loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case
     by(cases "the (h (the_Addr (hd stk)))", cases "fst(snd(field P C F))",
        cases ics, auto simp: split_beta dest: has_field_sees[OF has_field_idemp] dest!: StepI)
  next
    case (exec_step_ind_Getfield v stk D fs h D' b t P C F loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case
     by(cases "the (h (the_Addr (hd stk)))",
        cases ics; fastforce simp: split_beta dest: has_field_sees[OF has_field_idemp] dest!: StepI)
  next
    case (exec_step_ind_Getstatic_NonStatic P C F t D h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case
     by(cases ics; fastforce simp: split_beta split: staticb.splits
                             dest: has_field_sees[OF has_field_idemp] dest!: StepI)
  next
    case exec_step_ind_Getstatic_Called
    then show ?case by(fastforce simp: split_beta split: staticb.splits dest!: StepI
                                 dest: has_field_sees[OF has_field_idemp])
  next
    case (exec_step_ind_Getstatic_Done D' b t P D F C ics sh sfs v h stk loc C\<^sub>0 M\<^sub>0 pc frs)
    then show ?case by(cases ics, auto simp: split_beta split: staticb.splits
                                       dest: has_field_sees[OF has_field_idemp])
  next
    case (exec_step_ind_Getstatic_Init D' b t P D F C sh ics h stk loc C\<^sub>0 M\<^sub>0 pc frs)
    then show ?case
       by(cases ics, auto simp: split_beta split: init_state.splits staticb.splits
                          dest: has_field_sees[OF has_field_idemp])
  next
    case (exec_step_ind_Putfield_NoField r stk a D fs h P F C loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases "the (h (the_Addr (hd(tl stk))))", cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Putfield_Static r stk a D fs h P F t C loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case
     by(cases "the (h (the_Addr (hd(tl stk))))", cases "fst(snd(field P C F))",
        cases ics, auto simp: split_beta dest: has_field_sees[OF has_field_idemp] dest!: StepI)
  next
    case (exec_step_ind_Putfield v stk r a D fs h D' b t P C F loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case
     by(cases "the (h (the_Addr (hd(tl stk))))",
        cases ics; fastforce simp: split_beta dest: has_field_sees[OF has_field_idemp] dest!: StepI)
  next
    case (exec_step_ind_Putstatic_NonStatic P C F t D h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case
     by(cases ics; fastforce simp: split_beta split: staticb.splits
                             dest: has_field_sees[OF has_field_idemp] dest!: StepI)
  next
    case exec_step_ind_Putstatic_Called
    then show ?case by(fastforce simp: split_beta split: staticb.splits dest!: StepI
                                 dest: has_field_sees[OF has_field_idemp])
  next
    case (exec_step_ind_Putstatic_Done D' b t P D F C ics sh sfs h stk loc C\<^sub>0 M\<^sub>0 pc frs)
    then show ?case by(cases ics, auto simp: split_beta split: staticb.splits
                                       dest: has_field_sees[OF has_field_idemp])
  next
    case (exec_step_ind_Putstatic_Init D' b t P D F C sh ics h stk loc C\<^sub>0 M\<^sub>0 pc frs)
    then show ?case
     by(cases ics, auto simp: split_beta split: staticb.splits init_state.splits
                        dest: has_field_sees[OF has_field_idemp])
  next
    case (exec_step_ind_Invoke ps n stk r C h D b Ts T mxs mxl\<^sub>0 ins xt P M m f' loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics; fastforce dest!: StepI)
  next
    case (exec_step_ind_Invokestatic_Called ps n stk D b Ts T mxs mxl\<^sub>0 ins xt P C M m ics ics' sh)
    then show ?case by(cases ics; fastforce dest!: StepI)
  next
    case (exec_step_ind_Invokestatic_Done ps n stk D b Ts T mxs mxl\<^sub>0 ins xt P C M m ics sh sfs f')
    then show ?case by(cases ics; fastforce)
  next
    case (exec_step_ind_Invokestatic_Init D b Ts T mxs mxl\<^sub>0 ins xt P C M m sh ics n h stk loc C\<^sub>0 M\<^sub>0 pc frs)
    then show ?case by(cases ics; fastforce split: init_state.splits)
  next
    case (exec_step_ind_Return_NonStatic D Ts T m P C\<^sub>0 M\<^sub>0 h stk\<^sub>0 loc\<^sub>0 pc ics stk' loc' C' m' pc' ics' frs' sh)
    then show ?case by(cases "method P C\<^sub>0 M\<^sub>0", cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Return_Static D Ts T m P C\<^sub>0 M\<^sub>0 h stk\<^sub>0 loc\<^sub>0 pc ics stk' loc' C' m' pc' ics' frs' sh)
    then show ?case by(cases "method P C\<^sub>0 M\<^sub>0", cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_IfFalse_nFalse stk i P h loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases "hd stk"; cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Throw_Null stk P h loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases "hd stk"; cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Init C Cs P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then have "ics = Called (C#Cs)" by simp
    then show ?case by auto
  (***)
  next
    case (exec_step_ind_Load n P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Store n P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Push v P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_NewOOM_Called h C P stk loc C\<^sub>0 M\<^sub>0 pc frs sh ics')
    then show ?case by(auto dest!: StepI)
  next
    case (exec_step_ind_New_Called h a C P stk loc C\<^sub>0 M\<^sub>0 pc frs sh ics')
    then show ?case by(auto dest!: StepI)
  next
    case (exec_step_ind_Getfield_Null stk F C P h loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Getstatic_NoField P C F D h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Putfield_Null stk F C P h loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Putstatic_NoField P C F D h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Checkcast P C h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Checkcast_Error P C h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Invoke_Null stk n M P h loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Invoke_NoMethod r stk n C h P M loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Invoke_Static r stk n C h D b Ts T mxs mxl\<^sub>0 ins xt P M m loc C\<^sub>0 M\<^sub>0 pc ics)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Invokestatic_NoMethod D b Ts T mxs mxl\<^sub>0 ins xt P C M n h stk loc C\<^sub>0 M\<^sub>0 pc ics)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Invokestatic_NonStatic D b Ts T mxs mxl\<^sub>0 ins xt P C M m n h stk loc C\<^sub>0 M\<^sub>0 pc ics)
    then show ?case by(cases ics, auto dest!: StepI)
  next
  case (exec_step_ind_Return_Last_Init P h stk\<^sub>0 loc\<^sub>0 C\<^sub>0 pc ics sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Return_Last M\<^sub>0 P h stk\<^sub>0 loc\<^sub>0 C\<^sub>0 pc ics sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
  case (exec_step_ind_Return_Init D b Ts T m P C\<^sub>0 h stk\<^sub>0 loc\<^sub>0 pc ics stk' loc' C' m' pc' ics')
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Pop P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_IAdd P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_IfFalse_False stk i P h loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_CmpEq P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Goto i P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Throw stk P h loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(cases ics, auto dest!: StepI)
  next
    case (exec_step_ind_Init_None_Called sh C Cs P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs)
    then show ?case by(auto dest!: StepC)
  next
    case (exec_step_ind_Init_Done sh C sfs Cs P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs)
    then show ?case by(auto dest!: StepC)
  next
    case (exec_step_ind_Init_Processing sh C sfs Cs P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs)
    then show ?case by(auto dest!: StepC)
  next
    case (exec_step_ind_Init_Error sh C sfs Cs P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs)
    then show ?case by(auto dest!: StepC)
  next
    case (exec_step_ind_Init_Prepared_Object sh C sfs sh' Cs P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs)
    then show ?case by(auto dest!: StepC)
  next
    case (exec_step_ind_Init_Prepared_nObject sh C sfs sh' D P Cs h stk loc C\<^sub>0 M\<^sub>0 pc ics frs)
    then show ?case by(auto dest!: StepC)
  next
    case (exec_step_ind_InitThrow C Cs a P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(auto dest!: StepT)
  next
    case (exec_step_ind_InitThrow_End a P h stk loc C\<^sub>0 M\<^sub>0 pc ics frs sh)
    then show ?case by(auto dest!: StepT)
  qed
qed

\<comment> \<open> @{term exec_step} and @{term exec_step_ind} reach the same result given equivalent input \<close>
lemma exec_step_ind_equiv:
 "exec_step P h stk loc C M pc ics frs sh = (xp', h', frs', sh')
   = exec_step_ind (exec_step_input P C M pc ics) P h stk loc C M pc ics frs sh (xp', h', frs', sh')"
 using exec_step_imp_exec_step_ind exec_step_ind_imp_exec_step by auto

end


(*  Title:      HOL/Auth/n_germanSimp_lemma_inv__44_on_rules.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_germanSimp Protocol Case Study*}

theory n_germanSimp_lemma_inv__44_on_rules imports n_germanSimp_lemma_on_inv__44
begin
section{*All lemmas on causal relation between inv__44*}
lemma lemma_inv__44_on_rules:
  assumes b1: "r \<in> rules N" and b2: "(\<exists> p__Inv4. p__Inv4\<le>N\<and>f=inv__44  p__Inv4)"
  shows "invHoldForRule s f r (invariants N)"
  proof -
  have c1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__0 N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__1 N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntE N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
  apply (cut_tac b1, auto) done
    moreover {
      assume d1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_StoreVsinv__44) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqSVsinv__44) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__0 N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqE__part__0Vsinv__44) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqE__part__1 N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqE__part__1Vsinv__44) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__0Vsinv__44) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInv__part__1Vsinv__44) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInvAckVsinv__44) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvInvAckVsinv__44) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntSVsinv__44) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntE N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntEVsinv__44) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntSVsinv__44) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntEVsinv__44) done
    }

  ultimately show "invHoldForRule s f r (invariants N)"
  by satx
qed

end


(*  Title:      HOL/Auth/n_german_lemma_on_inv__30.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_german Protocol Case Study*}

theory n_german_lemma_on_inv__30 imports n_german_base
begin
section{*All lemmas on causal relation between inv__30 and some rule r*}
lemma n_RecvReqSVsinv__30:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqS N i)" and
a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_RecvReqS N i" apply fastforce done
from a2 obtain p__Inv2 where a2:"p__Inv2\<le>N\<and>f=inv__30  p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i~=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed

lemma n_RecvReqEVsinv__30:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_RecvReqE N i)" and
a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_RecvReqE N i" apply fastforce done
from a2 obtain p__Inv2 where a2:"p__Inv2\<le>N\<and>f=inv__30  p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i~=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed

lemma n_SendInv__part__0Vsinv__30:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__0  i)" and
a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_SendInv__part__0  i" apply fastforce done
from a2 obtain p__Inv2 where a2:"p__Inv2\<le>N\<and>f=inv__30  p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i~=p__Inv2)"
  have "?P2 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed

lemma n_SendInv__part__1Vsinv__30:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_SendInv__part__1  i)" and
a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_SendInv__part__1  i" apply fastforce done
from a2 obtain p__Inv2 where a2:"p__Inv2\<le>N\<and>f=inv__30  p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i~=p__Inv2)"
  have "?P2 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed

lemma n_RecvInvAckVsinv__30:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)" and
a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_RecvInvAck  i" apply fastforce done
from a2 obtain p__Inv2 where a2:"p__Inv2\<le>N\<and>f=inv__30  p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "?P3 s"
  apply (cut_tac a1 a2 b1, simp, rule_tac x="(neg (andForm (eqn (IVar (Para (Ident ''InvSet'') p__Inv2)) (Const true)) (eqn (IVar (Field (Para (Ident ''Chan3'') p__Inv2) ''Cmd'')) (Const InvAck))))" in exI, auto) done
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i~=p__Inv2)"
  have "?P2 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed

lemma n_SendGntSVsinv__30:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_SendGntS  i)" and
a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_SendGntS  i" apply fastforce done
from a2 obtain p__Inv2 where a2:"p__Inv2\<le>N\<and>f=inv__30  p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i~=p__Inv2)"
  have "?P2 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed

lemma n_SendGntEVsinv__30:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_SendGntE N i)" and
a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_SendGntE N i" apply fastforce done
from a2 obtain p__Inv2 where a2:"p__Inv2\<le>N\<and>f=inv__30  p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i~=p__Inv2)"
  have "?P2 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed

lemma n_SendReqE__part__1Vsinv__30:
  assumes a1: "\<exists> i. i\<le>N\<and>r=n_SendReqE__part__1  i" and
  a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
  shows "invHoldForRule s f r (invariants N)"
  apply (rule noEffectOnRule, cut_tac a1 a2, auto) done

lemma n_StoreVsinv__30:
  assumes a1: "\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d" and
  a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
  shows "invHoldForRule s f r (invariants N)"
  apply (rule noEffectOnRule, cut_tac a1 a2, auto) done

lemma n_RecvGntSVsinv__30:
  assumes a1: "\<exists> i. i\<le>N\<and>r=n_RecvGntS  i" and
  a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
  shows "invHoldForRule s f r (invariants N)"
  apply (rule noEffectOnRule, cut_tac a1 a2, auto) done

lemma n_RecvGntEVsinv__30:
  assumes a1: "\<exists> i. i\<le>N\<and>r=n_RecvGntE  i" and
  a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
  shows "invHoldForRule s f r (invariants N)"
  apply (rule noEffectOnRule, cut_tac a1 a2, auto) done

lemma n_SendInvAckVsinv__30:
  assumes a1: "\<exists> i. i\<le>N\<and>r=n_SendInvAck  i" and
  a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
  shows "invHoldForRule s f r (invariants N)"
  apply (rule noEffectOnRule, cut_tac a1 a2, auto) done

lemma n_SendReqE__part__0Vsinv__30:
  assumes a1: "\<exists> i. i\<le>N\<and>r=n_SendReqE__part__0  i" and
  a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
  shows "invHoldForRule s f r (invariants N)"
  apply (rule noEffectOnRule, cut_tac a1 a2, auto) done

lemma n_SendReqSVsinv__30:
  assumes a1: "\<exists> i. i\<le>N\<and>r=n_SendReqS  i" and
  a2: "(\<exists> p__Inv2. p__Inv2\<le>N\<and>f=inv__30  p__Inv2)"
  shows "invHoldForRule s f r (invariants N)"
  apply (rule noEffectOnRule, cut_tac a1 a2, auto) done

end


(*  Title:      Jinja/J/execute_WellType.thy
    Author:     Christoph Petzinger
    Copyright   2004 Technische Universitaet Muenchen
*)

header {* \isaheader{Code Generation For WellType} *}

theory execute_WellType
imports
  WellType Examples
begin

(* Replace WT_WTs.WTCond with new intros WT_WTs.WTCond1 and WT_WTs.WTCond2 *)

lemma WTCond1:
  "\<lbrakk>P,E \<turnstile> e :: Boolean;  P,E \<turnstile> e\<^sub>1::T\<^sub>1;  P,E \<turnstile> e\<^sub>2::T\<^sub>2; P \<turnstile> T\<^sub>1 \<le> T\<^sub>2;
    P \<turnstile> T\<^sub>2 \<le> T\<^sub>1 \<longrightarrow> T\<^sub>2 = T\<^sub>1 \<rbrakk> \<Longrightarrow> P,E \<turnstile> if (e) e\<^sub>1 else e\<^sub>2 :: T\<^sub>2"
by (fastforce)

lemma WTCond2:
  "\<lbrakk>P,E \<turnstile> e :: Boolean;  P,E \<turnstile> e\<^sub>1::T\<^sub>1;  P,E \<turnstile> e\<^sub>2::T\<^sub>2; P \<turnstile> T\<^sub>2 \<le> T\<^sub>1;
    P \<turnstile> T\<^sub>1 \<le> T\<^sub>2 \<longrightarrow> T\<^sub>1 = T\<^sub>2 \<rbrakk> \<Longrightarrow> P,E \<turnstile> if (e) e\<^sub>1 else e\<^sub>2 :: T\<^sub>1"
by (fastforce)

lemmas [code_pred_intro] =
  WT_WTs.WTNew
  WT_WTs.WTCast
  WT_WTs.WTVal
  WT_WTs.WTVar
  WT_WTs.WTBinOpEq
  WT_WTs.WTBinOpAdd
  WT_WTs.WTLAss
  WT_WTs.WTFAcc
  WT_WTs.WTFAss
  WT_WTs.WTCall
  WT_WTs.WTBlock
  WT_WTs.WTSeq

declare
  WTCond1 [code_pred_intro WTCond1]
  WTCond2 [code_pred_intro WTCond2]

lemmas [code_pred_intro] =
  WT_WTs.WTWhile
  WT_WTs.WTThrow
  WT_WTs.WTTry
  WT_WTs.WTNil
  WT_WTs.WTCons

code_pred
  (modes: i \<Rightarrow> i \<Rightarrow> i \<Rightarrow> i \<Rightarrow> bool as type_check, i \<Rightarrow> i \<Rightarrow> i \<Rightarrow> o \<Rightarrow> bool as infer_type)
  WT
proof -
  case WT
  from WT.prems show thesis
  proof(cases (no_simp))
    case (WTCond E e e1 T1 e2 T2 T)
    from `x \<turnstile> T1 \<le> T2 \<or> x \<turnstile> T2 \<le> T1` show thesis
    proof
      assume "x \<turnstile> T1 \<le> T2"
      with `x \<turnstile> T1 \<le> T2 \<longrightarrow> T = T2` have "T = T2" ..
      from `xa = E` `xb = if (e) e1 else e2` `xc = T` `x,E \<turnstile> e :: Boolean`
        `x,E \<turnstile> e1 :: T1` `x,E \<turnstile> e2 :: T2` `x \<turnstile> T1 \<le> T2` `x \<turnstile> T2 \<le> T1 \<longrightarrow> T = T1`
      show ?thesis unfolding `T = T2` by(rule WTCond1[OF refl])
    next
      assume "x \<turnstile> T2 \<le> T1"
      with `x \<turnstile> T2 \<le> T1 \<longrightarrow> T = T1` have "T = T1" ..
      from `xa = E` `xb = if (e) e1 else e2` `xc = T` `x,E \<turnstile> e :: Boolean`
        `x,E \<turnstile> e1 :: T1` `x,E \<turnstile> e2 :: T2` `x \<turnstile> T2 \<le> T1` `x \<turnstile> T1 \<le> T2 \<longrightarrow> T = T2`
      show ?thesis unfolding `T = T1` by(rule WTCond2[OF refl])
    qed
  qed(assumption|erule (2) that[OF refl])+
next
  case WTs
  from WTs.prems show thesis
    by(cases (no_simp))(assumption|erule (2) that[OF refl])+
qed

notation infer_type ("_,_ \<turnstile> _ :: '_" [51,51,51]100)

definition test1 where "test1 = [],empty \<turnstile> testExpr1 :: _"
definition test2 where "test2 = [], empty  \<turnstile> testExpr2 :: _"
definition test3 where "test3 = [], empty(''V'' \<mapsto> Integer)  \<turnstile> testExpr3 :: _"
definition test4 where "test4 = [], empty(''V'' \<mapsto> Integer)  \<turnstile> testExpr4 :: _"
definition test5 where "test5 = [classObject, (''C'',(''Object'',[(''F'',Integer)],[]))], empty  \<turnstile> testExpr5 :: _"
definition test6 where "test6 = [classObject, classI], empty  \<turnstile> testExpr6 :: _"

ML_val {*
  val SOME(@{code Integer}, _) = Predicate.yield @{code test1};
  val SOME(@{code Integer}, _) = Predicate.yield @{code test2};
  val SOME(@{code Integer}, _) = Predicate.yield @{code test3};
  val SOME(@{code Void}, _) = Predicate.yield @{code test4};
  val SOME(@{code Void}, _) = Predicate.yield @{code test5};
  val SOME(@{code Integer}, _) = Predicate.yield @{code test6};
*}

definition testmb_isNull where "testmb_isNull = [classObject, classA], empty([this] [\<mapsto>] [Class ''A'']) \<turnstile> mb_isNull :: _"
definition testmb_add where "testmb_add = [classObject, classA], empty([this,''i''] [\<mapsto>] [Class ''A'',Integer]) \<turnstile> mb_add :: _"
definition testmb_mult_cond where "testmb_mult_cond = [classObject, classA], empty([this,''j''] [\<mapsto>] [Class ''A'',Integer]) \<turnstile> mb_mult_cond :: _"
definition testmb_mult_block where "testmb_mult_block = [classObject, classA], empty([this,''i'',''j'',''temp''] [\<mapsto>] [Class ''A'',Integer,Integer,Integer]) \<turnstile> mb_mult_block :: _"
definition testmb_mult where "testmb_mult = [classObject, classA], empty([this,''i'',''j''] [\<mapsto>] [Class ''A'',Integer,Integer]) \<turnstile> mb_mult :: _"

ML_val {*
  val SOME(@{code Boolean}, _) = Predicate.yield @{code testmb_isNull};
  val SOME(@{code Integer}, _) = Predicate.yield @{code testmb_add};
  val SOME(@{code Boolean}, _) = Predicate.yield @{code testmb_mult_cond};
  val SOME(@{code Void}, _) = Predicate.yield @{code testmb_mult_block};
  val SOME(@{code Integer}, _) = Predicate.yield @{code testmb_mult};
*}

definition test where "test = [classObject, classA], empty \<turnstile> testExpr_ClassA :: _"

ML_val {*
  val SOME(@{code Integer}, _) = Predicate.yield @{code test};
*}

end


(*
 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
 *
 * SPDX-License-Identifier: BSD-2-Clause
 *)

theory WhileLoopVarsPreserved imports
  "AutoCorres.AutoCorres"
begin

external_file "while_loop_vars_preserved.c"
install_C_file "while_loop_vars_preserved.c"

autocorres [ts_force nondet = loop] "while_loop_vars_preserved.c"

context while_loop_vars_preserved begin

lemma "\<lbrace> \<lambda>s. True \<rbrace> loop' var1 var2 var3 var4  \<lbrace> \<lambda>r s. r = var1 + var2 + var3 + var4 \<rbrace>"
  apply (unfold loop'_def)
  apply (subst whileLoop_add_inv [where I="\<lambda>(meow, woof, neigh, ii, squeek) s.
              ii = (var1 + var2 + var3 + var4 - (meow + woof + neigh + squeek))"
       and M="\<lambda>((meow, woof, neigh, ii, squeek), s).
                   unat meow + unat woof + unat neigh + unat squeek"])
  apply wp
  apply (auto simp: word_gt_0)
  done

end

end