Theory BVNoTypeError

(*  Title:      HOL/MicroJava/BV/BVNoTypeError.thy
    Author:     Gerwin Klein
*)

section Welltyped Programs produce no Type Errors

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

text 
  Some simple lemmas about the type testing functions of the
  defensive JVM:

lemma typeof_NoneD [simp,dest]:
  "typeof (λv. None) v = Some x  ¬isAddr v"
  by (cases v) auto

lemma isRef_def2:
  "isRef v = (v = Null  (loc. v = Addr loc))"
  by (cases v) (auto simp add: isRef_def)

lemma app'Store[simp]:
  "app' (Store idx, G, pc, maxs, rT, (ST,LT)) = (T ST'. ST = T#ST'  idx < length LT)"
  by (cases ST) auto

lemma app'GetField[simp]:
  "app' (Getfield F C, G, pc, maxs, rT, (ST,LT)) =  
  (oT vT ST'. ST = oT#ST'  is_class G C   
  field (G,C) F = Some (C,vT)  G  oT  Class C)"
  by (cases ST) auto

lemma app'PutField[simp]:
"app' (Putfield F C, G,  pc, maxs, rT, (ST,LT)) = 
 (vT vT' oT ST'. ST = vT#oT#ST'  is_class G C  
  field (G,C) F = Some (C, vT')  
  G  oT  Class C  G  vT  vT')"
  apply rule
  defer
  apply clarsimp
  apply (cases ST)
  apply simp
  apply (cases "tl ST")
  apply auto
  done

lemma app'Checkcast[simp]:
"app' (Checkcast C, G, pc, maxs, rT, (ST,LT)) =
 (rT ST'. ST = RefT rT#ST'  is_class G C)"
apply rule
defer
apply clarsimp
apply (cases ST)
apply simp
apply (cases "hd ST")
defer 
apply simp
apply simp
done


lemma app'Pop[simp]: 
  "app' (Pop, G, pc, maxs, rT, (ST,LT)) = (T ST'. ST = T#ST')"
  by (cases ST) auto


lemma app'Dup[simp]:
  "app' (Dup, G, pc, maxs, rT, (ST,LT)) =
  (T ST'. ST = T#ST'  length ST < maxs)"
  by (cases ST) auto
 

lemma app'Dup_x1[simp]:
  "app' (Dup_x1, G, pc, maxs, rT, (ST,LT)) = 
  (T1 T2 ST'. ST = T1#T2#ST'  length ST < maxs)"
  by (cases ST, simp, cases "tl ST", auto)

  
lemma app'Dup_x2[simp]:
  "app' (Dup_x2, G, pc, maxs, rT, (ST,LT)) = 
  (T1 T2 T3 ST'. ST = T1#T2#T3#ST'  length ST < maxs)"
  by (cases ST, simp, cases "tl ST", simp, cases "tl (tl ST)", auto)


lemma app'Swap[simp]:
  "app' (Swap, G, pc, maxs, rT, (ST,LT)) = (T1 T2 ST'. ST = T1#T2#ST')" 
  by (cases ST, simp, cases "tl ST", auto)

  
lemma app'IAdd[simp]:
  "app' (IAdd, G, pc, maxs, rT, (ST,LT)) = 
  (ST'. ST = PrimT Integer#PrimT Integer#ST')"
  apply (cases ST)
  apply simp
  apply simp
  apply (case_tac a)
  apply auto
  apply (rename_tac prim_ty, case_tac prim_ty)
  apply auto
  apply (rename_tac prim_ty, case_tac prim_ty)
  apply auto
  apply (case_tac list)
  apply auto
  apply (case_tac a)
  apply auto
  apply (rename_tac prim_ty, case_tac prim_ty)
  apply auto
  done
 

lemma app'Ifcmpeq[simp]:
  "app' (Ifcmpeq b, G, pc, maxs, rT, (ST,LT)) =
  (T1 T2 ST'. ST = T1#T2#ST'  0  b + int pc  
  ((p. T1 = PrimT p  T1 = T2)  
  (r r'. T1 = RefT r  T2 = RefT r')))" 
  apply auto
  apply (cases ST)
  apply simp
  apply (cases "tl ST")
  apply (case_tac a)
  apply auto
  done
  

lemma app'Return[simp]:
  "app' (Return, G, pc, maxs, rT, (ST,LT)) = 
  (T ST'. ST = T#ST' G  T  rT)" 
  by (cases ST) auto


lemma app'Throw[simp]:
  "app' (Throw, G, pc, maxs, rT, (ST,LT)) = 
  (ST' r. ST = RefT r#ST')"
  apply (cases ST)
  apply simp
  apply (cases "hd ST")
  apply auto
  done

  
lemma app'Invoke[simp]:
"app' (Invoke C mn fpTs, G, pc, maxs, rT, ST, LT) = 
 (apTs X ST' mD' rT' b'.
  ST = (rev apTs) @ X # ST'  
  length apTs = length fpTs  is_class G C 
  ((aT,fT)set(zip apTs fpTs). G  aT  fT)  
  method (G,C) (mn,fpTs) = Some (mD', rT', b')  G  X  Class C)"
  (is "?app ST LT = ?P ST LT")
proof
  assume "?P ST LT" thus "?app ST LT" by (auto simp add: list_all2_iff)
next  
  assume app: "?app ST LT"
  hence l: "length fpTs < length ST" by simp
  obtain xs ys where xs: "ST = xs @ ys" "length xs = length fpTs"
  proof -
    have "ST = take (length fpTs) ST @ drop (length fpTs) ST" by simp
    moreover from l have "length (take (length fpTs) ST) = length fpTs"
      by simp
    ultimately show ?thesis ..
  qed
  obtain apTs where
    "ST = (rev apTs) @ ys" and "length apTs = length fpTs"
  proof -
    from xs(1) have "ST = rev (rev xs) @ ys" by simp
    then show thesis by (rule that) (simp add: xs(2))
  qed
  moreover
  from l xs obtain X ST' where "ys = X#ST'" by (auto simp add: neq_Nil_conv)
  ultimately
  have "ST = (rev apTs) @ X # ST'" "length apTs = length fpTs" by auto
  with app
  show "?P ST LT"
    apply (clarsimp simp add: list_all2_iff)
    apply (intro exI conjI)
    apply auto
    done
qed

lemma approx_loc_len [simp]:
  "approx_loc G hp loc LT  length loc = length LT"
  by (simp add: approx_loc_def list_all2_iff)

lemma approx_stk_len [simp]:
  "approx_stk G hp stk ST  length stk = length ST"
  by (simp add: approx_stk_def)

lemma isRefI [intro, simp]: "G,hp  v ::≼ RefT T  isRef v"
  apply (drule conf_RefTD)
  apply (auto simp add: isRef_def)
  done

lemma isIntgI [intro, simp]: "G,hp  v ::≼ PrimT Integer  isIntg v"
  apply (unfold conf_def)
  apply auto
  apply (erule widen.cases)
  apply auto
  apply (cases v)
  apply auto
  done

lemma list_all2_approx:
  "list_all2 (approx_val G hp) s (map OK S) = list_all2 (conf G hp) s S"
  apply (induct S arbitrary: s)
  apply (auto simp add: list_all2_Cons2 approx_val_def)
  done

lemma list_all2_conf_widen:
  "wf_prog mb G 
  list_all2 (conf G hp) a b 
  list_all2 (λx y. G  x  y) b c 
  list_all2 (conf G hp) a c"
  apply (rule list_all2_trans)
  defer
  apply assumption
  apply assumption
  apply (drule conf_widen, assumption+)
  done


text 
  The main theorem: welltyped programs do not produce type errors if they
  are started in a conformant state.

theorem no_type_error:
  assumes welltyped: "wt_jvm_prog G Phi" and conforms: "G,Phi ⊢JVM s "
  shows "exec_d G (Normal s)  TypeError"
proof -
  from welltyped obtain mb where wf: "wf_prog mb G" by (fast dest: wt_jvm_progD)
  
  obtain xcp hp frs where s [simp]: "s = (xcp, hp, frs)" by (cases s)

  from conforms have "xcp  None  frs = []  check G s" 
    by (unfold correct_state_def check_def) auto
  moreover {
    assume "¬(xcp  None  frs = [])"
    then obtain stk loc C sig pc frs' where
      xcp [simp]: "xcp = None" and
      frs [simp]: "frs = (stk,loc,C,sig,pc)#frs'" 
      by (clarsimp simp add: neq_Nil_conv)

    from conforms obtain  ST LT rT maxs maxl ins et where
      hconf:  "G ⊢h hp " and
      "class":  "is_class G C" and
      meth:   "method (G, C) sig = Some (C, rT, maxs, maxl, ins, et)" and
      phi:    "Phi C sig ! pc = Some (ST,LT)" and
      frame:  "correct_frame G hp (ST,LT) maxl ins (stk,loc,C,sig,pc)" and
      frames: "correct_frames G hp Phi rT sig frs'"
      by (auto simp add: correct_state_def)

    from frame obtain
      stk: "approx_stk G hp stk ST" and
      loc: "approx_loc G hp loc LT" and
      pc:  "pc < length ins" and
      len: "length loc = length (snd sig) + maxl + 1"
      by (auto simp add: correct_frame_def)

    note approx_val_def [simp]

    from welltyped meth conforms
    have "wt_instr (ins!pc) G rT (Phi C sig) maxs (length ins) et pc"
      by simp (rule wt_jvm_prog_impl_wt_instr_cor)    
    then obtain
      app': "app (ins!pc) G maxs rT pc et (Phi C sig!pc) " and
      eff: "(pc', s')set (eff (ins ! pc) G pc et (Phi C sig ! pc)). pc' < length ins"
      by (simp add: wt_instr_def phi) blast

    from eff 
    have pc': "pc'  set (succs (ins!pc) pc). pc' < length ins"
      by (simp add: eff_def) blast

    from app' phi
    have app:
      "xcpt_app (ins!pc) G pc et  app' (ins!pc, G, pc, maxs, rT, (ST,LT))"
      by (clarsimp simp add: app_def)

    with eff stk loc pc'
    have "check_instr (ins!pc) G hp stk loc C sig pc maxs frs'"
    proof (cases "ins!pc")
      case (Getfield F C) 
      with app stk loc phi obtain v vT stk' where
        "class": "is_class G C" and
        field: "field (G, C) F = Some (C, vT)" and
        stk:   "stk = v # stk'" and
        conf:  "G,hp  v ::≼ Class C"
        apply clarsimp
        apply (blast dest: conf_widen [OF wf])
        done
      from conf have isRef: "isRef v" ..
      moreover {
        assume "v  Null" 
        with conf field isRef wf
        have "D vs. hp (the_Addr v) = Some (D,vs)  G  D ≼C C" 
          by (auto dest!: non_np_objD)
      }
      ultimately show ?thesis using Getfield field "class" stk hconf wf
        apply clarsimp
        apply (fastforce dest!: hconfD widen_cfs_fields oconf_objD)
        done
    next
      case (Putfield F C)
      with app stk loc phi obtain v ref vT stk' where
        "class": "is_class G C" and
        field: "field (G, C) F = Some (C, vT)" and
        stk:   "stk = v # ref # stk'" and
        confv: "G,hp  v ::≼ vT" and
        confr: "G,hp  ref ::≼ Class C"
        apply clarsimp
        apply (blast dest: conf_widen [OF wf])
        done
      from confr have isRef: "isRef ref" ..
      moreover {
        assume "ref  Null" 
        with confr field isRef wf
        have "D vs. hp (the_Addr ref) = Some (D,vs)  G  D ≼C C"
          by (auto dest: non_np_objD)
      }
      ultimately show ?thesis using Putfield field "class" stk confv
        by clarsimp
    next      
      case (Invoke C mn ps)
      with app
      obtain apTs X ST' where
        ST: "ST = rev apTs @ X # ST'" and
        ps: "length apTs = length ps" and
        w:   "(x, y)set (zip apTs ps). G  x  y" and
        C:   "G  X  Class C" and
        mth: "method (G, C) (mn, ps)  None"
        by (simp del: app'.simps) blast
        
      from ST stk
      obtain aps x stk' where
        stk': "stk = aps @ x # stk'" and
        aps: "approx_stk G hp aps (rev apTs)" and
        x: "G,hp  x ::≼ X" and        
        l: "length aps = length apTs"
        by (auto dest!: approx_stk_append)
      
      from stk' l ps 
      have [simp]: "stk!length ps = x" by (simp add: nth_append)
      from stk' l ps
      have [simp]: "take (length ps) stk = aps" by simp
      from w ps
      have widen: "list_all2 (λx y. G  x  y) apTs ps"
        by (simp add: list_all2_iff) 

      from stk' l ps have "length ps < length stk" by simp
      moreover
      from wf x C 
      have x: "G,hp  x ::≼ Class C" by (rule conf_widen) 
      hence "isRef x" by simp
      moreover
      { assume "x  Null"
        with x
        obtain D fs where
          hp: "hp (the_Addr x) = Some (D,fs)" and
          D:  "G  D ≼C C"
          by (auto dest: non_npD)
        hence "hp (the_Addr x)  None" (is ?P1) by simp
        moreover
        from wf mth hp D
        have "method (G, cname_of hp x) (mn, ps)  None" (is ?P2)
          by (auto dest: subcls_widen_methd)
        moreover
        from aps have "list_all2 (conf G hp) aps (rev apTs)"
          by (simp add: list_all2_approx approx_stk_def approx_loc_def)        
        hence "list_all2 (conf G hp) (rev aps) (rev (rev apTs))"
          by (simp only: list_all2_rev)
        hence "list_all2 (conf G hp) (rev aps) apTs" by simp
        from wf this widen
        have "list_all2 (conf G hp) (rev aps) ps" (is ?P3)
          by (rule list_all2_conf_widen) 
        ultimately
        have "?P1  ?P2  ?P3" by blast
      }
      moreover 
      note Invoke
      ultimately
      show ?thesis by simp
    next
      case Return with stk app phi meth frames 
      show ?thesis        
        apply clarsimp
        apply (drule conf_widen [OF wf], assumption)
        apply (clarsimp simp add: neq_Nil_conv isRef_def2)
        done
    qed auto
    hence "check G s" by (simp add: check_def meth pc)
  } ultimately
  have "check G s" by blast
  thus "exec_d G (Normal s)  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:
  "wt_jvm_prog G Phi  G,Phi ⊢JVM s   G  s ─jvm→ t 
   G  (Normal s) ─jvmd→ (Normal t)"
  apply (unfold exec_all_def) 
  apply (erule rtrancl_induct)
   apply (simp add: exec_all_d_def)
  apply simp
  apply (fold exec_all_def)
  apply (frule BV_correct, assumption+)
  apply (drule no_type_error, assumption, drule no_type_error_commutes, simp)
  apply (simp add: exec_all_d_def)
  apply (rule rtrancl_trans, assumption)
  apply blast
  done


lemma neq_TypeError_eq [simp]: "s  TypeError = (s'. s = Normal s')"
  by (cases s, auto)

theorem no_type_errors:
  "wt_jvm_prog G Phi  G,Phi ⊢JVM s 
   G  (Normal s) ─jvmd→ t  t  TypeError"
  apply (unfold exec_all_d_def)   
  apply (erule rtrancl_induct)
   apply simp
  apply (fold exec_all_d_def)
  apply (auto dest: defensive_imp_aggressive BV_correct no_type_error)
  done

corollary no_type_errors_initial:
  fixes G ("Γ") and Phi ("Φ")
  assumes wt: "wt_jvm_prog Γ Φ"  
  assumes is_class: "is_class Γ C"
    and "method": "method (Γ,C) (m,[]) = Some (C, b)"
    and m: "m  init"
  defines start: "s  start_state Γ C m"

  assumes s: "Γ  (Normal s) ─jvmd→ t" 
  shows "t  TypeError"
proof -
  from wt is_class "method" have "Γ,Φ ⊢JVM s "
    unfolding start by (rule BV_correct_initial)
  from wt this s show ?thesis by (rule no_type_errors)
qed

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 G ("Γ") and Phi ("Φ")
  assumes wt: "wt_jvm_prog Γ Φ" and *: "Γ,Φ ⊢JVM s " 
  shows "Γ  (Normal s) ─jvmd→ (Normal t) = Γ  s ─jvm→ t"
  apply rule
   apply (erule defensive_imp_aggressive, rule welltyped_aggressive_imp_defensive)
    apply (rule wt)
   apply (rule *)
  apply assumption
  done

corollary welltyped_initial_commutes:
  fixes G ("Γ") and Phi ("Φ")
  assumes wt: "wt_jvm_prog Γ Φ"  
  assumes is_class: "is_class Γ C"
    and "method": "method (Γ,C) (m,[]) = Some (C, b)"
    and m: "m  init"
  defines start: "s  start_state Γ C m"
  shows "Γ  (Normal s) ─jvmd→ (Normal t) = Γ  s ─jvm→ t"
proof -
  from wt is_class "method" have "Γ,Φ ⊢JVM s "
    unfolding start by (rule BV_correct_initial)
  with wt show ?thesis by (rule welltyped_commutes)
qed
 
end