Theory WellForm

Up to index of Isabelle/HOL/JinjaThreads

theory WellForm
imports SystemClasses ExternalCall

(*  Title:      JinjaThreads/Common/WellForm.thy
    Author:     Tobias Nipkow, Andreas Lochbihler

    Based on the Jinja theory Common/WellForm.thy by Tobias Nipkow
*)

header {* \isaheader{Generic Well-formedness of programs} *}

theory WellForm imports SystemClasses ExternalCall begin

text {*\noindent This theory defines global well-formedness conditions
for programs but does not look inside method bodies.  Hence it works
for both Jinja and JVM programs. Well-typing of expressions is defined
elsewhere (in theory @{text WellType}).

Because JinjaThreads does not have method overloading, its policy for method
overriding is the classical one: \emph{covariant in the result type
but contravariant in the argument types.} This means the result type
of the overriding method becomes more specific, the argument types
become more general.
*}

types 'm wf_mdecl_test = "'m prog => cname => 'm mdecl => bool"

definition wf_extCall :: "'m prog => cname => mname => bool" where
  "wf_extCall P C M ≡
   ∀D. P \<turnstile> D \<preceq>* C ∨ P \<turnstile> C \<preceq>* D --> ¬ is_external_call P (Class D) M"

definition wf_fdecl :: "'m prog => fdecl => bool"
where "wf_fdecl P ≡ λ(F,T). is_type P T"

definition wf_mdecl :: "'m wf_mdecl_test => 'm wf_mdecl_test"
where "wf_mdecl wf_md P C ≡ λ(M,Ts,T,mb). (∀T∈set Ts. is_type P T) ∧ is_type P T ∧ wf_md P C (M,Ts,T,mb)"

definition wf_cdecl :: "'m wf_mdecl_test => 'm prog => 'm cdecl => bool"
where
  "wf_cdecl wf_md P  ≡  λ(C,(D,fs,ms)).
  (∀f∈set fs. wf_fdecl P f) ∧  distinct_fst fs ∧
  (∀m∈set ms. wf_mdecl wf_md P C m) ∧  distinct_fst ms ∧
  (C ≠ Object -->
   is_class P D ∧ ¬ P \<turnstile> D \<preceq>* C ∧
   (∀(M,Ts,T,m)∈set ms. wf_extCall P C M ∧
      (∀D' Ts' T' m'. P \<turnstile> D sees M:Ts' -> T' = m' in D' -->
                       P \<turnstile> Ts' [≤] Ts ∧ P \<turnstile> T ≤ T'))) ∧
  (C = Object --> (fs = []) ∧ (ms = [])) ∧ (* require object to implement no fields/methods because of array subtype of Object *)

  (C = Thread --> (∃m. (run, [], Void, m) ∈ set ms))"

definition wf_syscls :: "'m prog => bool"
where "wf_syscls P ≡ {Object, Throwable, Thread} ∪ sys_xcpts ⊆ set(map fst P) ∧ (∀C ∈ sys_xcpts. P \<turnstile> C \<preceq>* Throwable)"

definition wf_prog :: "'m wf_mdecl_test => 'm prog => bool"
where "wf_prog wf_md P  ≡  wf_syscls P ∧ (∀c ∈ set P. wf_cdecl wf_md P c) ∧ distinct_fst P"

subsection{* Well-formedness lemmas *}

lemma class_wf: 
  "[|class P C = Some c; wf_prog wf_md P|] ==> wf_cdecl wf_md P (C,c)"
(*<*)
apply (unfold wf_prog_def class_def)
apply (fast dest: map_of_SomeD)
done
(*>*)


lemma class_Object [simp]: 
  "wf_prog wf_md P ==> ∃C fs ms. class P Object = Some (C,fs,ms)"
(*<*)
apply (unfold wf_prog_def wf_syscls_def class_def)
apply (auto simp: map_of_SomeI)
done
(*>*)

lemma class_Thread [simp]: 
  "wf_prog wf_md P ==> ∃C fs ms. class P Thread = Some (C,fs,ms)"
(*<*)
apply (unfold wf_prog_def wf_syscls_def class_def)
apply (auto simp: map_of_SomeI)
done
(*>*)

lemma is_class_Object [simp]:
  "wf_prog wf_md P ==> is_class P Object"
(*<*)by (simp add: is_class_def)(*>*)

lemma is_class_Thread [simp]:
  "wf_prog wf_md P ==> is_class P Thread"
(*<*)by (simp add: is_class_def)(*>*)

lemma is_class_xcpt:
  "[| C ∈ sys_xcpts; wf_prog wf_md P |] ==> is_class P C"
(*<*)
  apply (simp add: wf_prog_def wf_syscls_def is_class_def class_def)
  apply (fastsimp intro!: map_of_SomeI)
  done
(*>*)

lemma xcpt_subcls_Throwable:
  "[| C ∈ sys_xcpts; wf_prog wf_md P |] ==> P \<turnstile> C \<preceq>* Throwable"
by (simp add: wf_prog_def wf_syscls_def is_class_def class_def)


lemma subcls1_wfD:
  "[| P \<turnstile> C \<prec>1 D; wf_prog wf_md P |] ==> D ≠ C ∧ ¬ (subcls1 P)++ D C"
apply( frule tranclp.r_into_trancl[where r="subcls1 P"])
apply( drule subcls1D)
apply(clarify)
apply( drule (1) class_wf)
apply( unfold wf_cdecl_def)
apply(rule conjI)
 apply(force)
apply(unfold reflcl_tranclp[symmetric, where r="subcls1 P"])
apply(blast)
done


lemma wf_cdecl_supD: 
  "[|wf_cdecl wf_md P (C,D,r); C ≠ Object|] ==> is_class P D"
(*<*)by (auto simp: wf_cdecl_def)(*>*)


lemma subcls_asym:
  "[| wf_prog wf_md P; (subcls1 P)++ C D |] ==> ¬ (subcls1 P)++ D C"
(*<*)
apply(erule tranclp.cases)
apply(fast dest!: subcls1_wfD )
apply(fast dest!: subcls1_wfD intro: tranclp_trans)
done
(*>*)


lemma subcls_irrefl:
  "[| wf_prog wf_md P; (subcls1 P)++ C D|] ==> C ≠ D"
(*<*)
apply (erule tranclp_trans_induct)
apply  (auto dest: subcls1_wfD subcls_asym)
done
(*>*)

lemma acyclicP_def:
  "acyclicP r <-> (∀x. ¬ r^++ x x)"
  unfolding acyclic_def trancl_def
by(auto)

lemma acyclic_subcls1:
  "wf_prog wf_md P ==> acyclicP (subcls1 P)"
(*<*)
apply (unfold acyclicP_def)
apply (fast dest: subcls_irrefl)
done
(*>*)



lemma wf_subcls1:
  "wf_prog wf_md P ==> wfP ((subcls1 P)¯¯)"
unfolding wfP_def
apply (rule finite_acyclic_wf)
 apply(subst finite_converse[unfolded converse_def, symmetric])
 apply(simp)
 apply(rule finite_subcls1)
apply(subst acyclic_converse[unfolded converse_def, symmetric])
apply(simp)
apply (erule acyclic_subcls1)
done
(*>*)


lemma single_valued_subcls1:
  "wf_prog wf_md G ==> single_valuedP (subcls1 G)"
(*<*)
by(auto simp:wf_prog_def distinct_fst_def single_valued_def dest!:subcls1D)
(*>*)


lemma subcls_induct: 
  "[| wf_prog wf_md P; !!C. ∀D. (subcls1 P)++ C D --> Q D ==> Q C |] ==> Q C"
(*<*)
  (is "?A ==> PROP ?P ==> _")
proof -
  assume p: "PROP ?P"
  assume ?A thus ?thesis apply -
apply(drule wf_subcls1)
apply(drule wfP_trancl)
apply(simp only: tranclp_converse)
apply(erule_tac a = C in wfP_induct)
apply(rule p)
apply(auto)
done
qed
(*>*)


lemma subcls1_induct_aux:
  "[| is_class P C; wf_prog wf_md P; Q Object;
    !!C D fs ms.
    [| C ≠ Object; is_class P C; class P C = Some (D,fs,ms) ∧
      wf_cdecl wf_md P (C,D,fs,ms) ∧ P \<turnstile> C \<prec>1 D ∧ is_class P D ∧ Q D|] ==> Q C |]
  ==> Q C"
(*<*)
  (is "?A ==> ?B ==> ?C ==> PROP ?P ==> _")
proof -
  assume p: "PROP ?P"
  assume ?A ?B ?C thus ?thesis apply -
apply(unfold is_class_def)
apply( rule impE)
prefer 2
apply(   assumption)
prefer 2
apply(  assumption)
apply( erule thin_rl)
apply( rule subcls_induct)
apply(  assumption)
apply( rule impI)
apply( case_tac "C = Object")
apply(  fast)
apply safe
apply( frule (1) class_wf)
apply( frule (1) wf_cdecl_supD)

apply( subgoal_tac "P \<turnstile> C \<prec>1 a")
apply( erule_tac [2] subcls1I)
apply(  rule p)
apply (unfold is_class_def)
apply auto
done
qed
(*>*)

lemma subcls1_induct [consumes 2, case_names Object Subcls]:
  "[| wf_prog wf_md P; is_class P C; Q Object;
    !!C D. [|C ≠ Object; P \<turnstile> C \<prec>1 D; is_class P D; Q D|] ==> Q C |]
  ==> Q C"
(*<*)
  apply (erule subcls1_induct_aux, assumption, assumption)
  apply blast
  done
(*>*)


lemma subcls_C_Object:
  "[| is_class P C; wf_prog wf_md P |] ==> P \<turnstile> C \<preceq>* Object"
(*<*)
apply(erule (1) subcls1_induct)
 apply( fast)
apply(erule (1) converse_rtranclp_into_rtranclp)
done
(*>*)

lemma converse_subcls_is_class:
  assumes wf: "wf_prog wf_md P"
  shows "[| P \<turnstile> C \<preceq>* D; is_class P C |] ==> is_class P D"
proof(induct rule: rtranclp_induct)
  assume "is_class P C"
  thus "is_class P C" .
next
  fix D E
  assume PDE: "P \<turnstile> D \<prec>1 E"
    and IH: "is_class P C ==> is_class P D"
    and iPC: "is_class P C"
  have "is_class P D" by (rule IH[OF iPC])
  with PDE obtain fsD MsD where classD: "class P D = ⌊(E, fsD, MsD)⌋"
    by(auto simp add: is_class_def elim!: subcls1.cases)
  thus "is_class P E" using wf PDE
    apply -
    apply(erule subcls1.cases, clarsimp)
    apply(clarsimp simp: wf_prog_def)
    apply(drule_tac x="(D, E, fsD, MsD)" in bspec)
    apply(clarsimp simp add: class_def)
    apply(erule map_of_is_SomeD)
    apply(erule_tac C="D" in wf_cdecl_supD)
    .
qed

lemma is_class_is_subcls:
  "wf_prog m P ==> is_class P C = P \<turnstile> C \<preceq>* Object"
(*<*)by (fastsimp simp:is_class_def
                  elim: subcls_C_Object converse_rtranclpE subcls1I
                  dest: subcls1D)
(*>*)

lemma subcls_antisym:
  "[|wf_prog m P; P \<turnstile> C \<preceq>* D; P \<turnstile> D \<preceq>* C|] ==> C = D"
apply(drule acyclic_subcls1)
apply(drule acyclic_impl_antisym_rtrancl)
apply(drule antisymD)
apply(unfold Transitive_Closure.rtrancl_def)
apply(auto)
done

lemma is_type_pTs:
assumes "wf_prog wf_md P" and "(C,S,fs,ms) ∈ set P" and "(M,Ts,T,m) ∈ set ms"
shows "set Ts ⊆ is_type P"
(*<*)
proof
  from prems have "wf_mdecl wf_md P C (M,Ts,T,m)" 
    by (unfold wf_prog_def wf_cdecl_def) auto  
  hence "∀t ∈ set Ts. is_type P t" by (unfold wf_mdecl_def) auto
  moreover fix t assume "t ∈ set Ts"
  ultimately have "is_type P t" by blast
  thus "t ∈ is_type P" by(simp add: mem_def)
qed
(*>*)

lemma widen_asym_1: 
  assumes wfP: "wf_prog wf_md P"
  shows "P \<turnstile> C ≤ D ==> C = D ∨ ¬ (P \<turnstile> D ≤ C)"
proof (erule widen.induct)
  fix T
  show "T = T ∨ ¬ (P \<turnstile> T ≤ T)" by simp
next
  fix C D
  assume CscD: "P \<turnstile> C \<preceq>* D"
  then have CpscD: "C = D ∨ (C ≠ D ∧ (subcls1 P)++ C D)" by (simp add: rtranclpD)
  { assume "P \<turnstile> D \<preceq>* C"
    then have DpscC: "D = C ∨ (D ≠ C ∧ (subcls1 P)++ D C)" by (simp add: rtranclpD)
    { assume "(subcls1 P)++ D C"
      with wfP have CnscD: "¬ (subcls1 P)++ C D" by (rule subcls_asym)
      with CpscD have "C = D" by simp
    }
    with DpscC have "C = D" by blast
  }
  hence "Class C = Class D ∨ ¬ (P \<turnstile> D \<preceq>* C)" by blast
  thus "Class C = Class D ∨ ¬ P \<turnstile> Class D ≤ Class C" by simp
next
  fix C
  show "NT = Class C ∨ ¬ P \<turnstile> Class C ≤ NT" by simp
next
  fix A
  { assume "P \<turnstile> A⌊⌉ ≤ NT"
    hence "A⌊⌉ = NT" by fastsimp
    hence "False" by simp }
  hence "¬ (P \<turnstile> A⌊⌉ ≤ NT)" by blast
  thus "NT = A⌊⌉ ∨ ¬ P \<turnstile> A⌊⌉ ≤ NT" by simp
next
  fix A
  show "A⌊⌉ = Class Object ∨ ¬ P \<turnstile> Class Object ≤ A⌊⌉"
    by(auto dest: Object_widen)
next
  fix A B
  assume AsU: "P \<turnstile> A ≤ B" and BnpscA: "A = B ∨ ¬ P \<turnstile> B ≤ A"
  { assume "P \<turnstile> B⌊⌉ ≤ A⌊⌉"
    hence "P \<turnstile> B ≤ A" by (auto dest: Array_Array_widen)
    with BnpscA have "A = B" by blast
    hence "A⌊⌉ = B⌊⌉" by simp }
  thus "A⌊⌉ = B⌊⌉ ∨ ¬ P \<turnstile> B⌊⌉ ≤ A⌊⌉" by blast
qed

lemma widen_asym: "[| wf_prog wf_md P; P \<turnstile> C ≤ D; C ≠ D |] ==> ¬ (P \<turnstile> D ≤ C)"
proof -
  assume wfP: "wf_prog wf_md P" and CsD: "P \<turnstile> C ≤ D" and CneqD: "C ≠ D"
  from wfP CsD have "C = D ∨ ¬ (P \<turnstile> D ≤ C)" by (rule widen_asym_1)
  with CneqD show ?thesis by simp
qed

lemma widen_antisym:
  "[| wf_prog m P; P \<turnstile> T ≤ U; P \<turnstile> U ≤ T |] ==> T = U"
by(auto dest: widen_asym)

lemma widen_C_Object: "[| wf_prog wf_md P; is_class P C |] ==> P \<turnstile> Class C ≤ Class Object"
by(simp add: subcls_C_Object)

lemma is_refType_widen_Object:
  assumes wfP: "wf_prog wfmc P"
  shows "[| is_type P A; is_refT A |] ==> P \<turnstile> A ≤ Class Object"
by(induct A)(auto elim: refTE intro: subcls_C_Object[OF _ wfP] widen_array_object)

subsection{* Well-formedness and method lookup *}

lemma sees_wf_mdecl:
  "[| wf_prog wf_md P; P \<turnstile> C sees M:Ts->T = m in D |] ==> wf_mdecl wf_md P D (M,Ts,T,m)"
(*<*)
apply(drule visible_method_exists)
apply(clarify)
apply(drule class_wf, assumption)
apply(drule map_of_SomeD)
apply(simp add: wf_cdecl_def)
done
(*>*)


lemma sees_method_mono [rule_format (no_asm)]: 
  "[| P \<turnstile> C' \<preceq>* C; wf_prog wf_md P |] ==>
  ∀D Ts T m. P \<turnstile> C sees M:Ts->T = m in D -->
     (∃D' Ts' T' m'. P \<turnstile> C' sees M:Ts'->T' = m' in D' ∧ P \<turnstile> Ts [≤] Ts' ∧ P \<turnstile> T' ≤ T)"
apply( drule rtranclpD)
apply( erule disjE)
apply(  fastsimp intro: widen_refl widens_refl)
apply( erule conjE)
apply( erule tranclp_trans_induct)
prefer 2
apply(  clarify)
apply(  drule spec, drule spec, drule spec, drule spec, erule (1) impE)
apply clarify
apply(  fast elim: widen_trans widens_trans)
apply( clarify)
apply( drule subcls1D)
apply( clarify)
apply(clarsimp simp:Method_def)
apply(frule (2) sees_methods_rec)
apply(rule refl)
apply(case_tac "map_of ms M")
apply(rule_tac x = D in exI)
apply(rule_tac x = Ts in exI)
apply(rule_tac x = T in exI)
apply(clarsimp simp add: widens_refl)
apply(rule_tac x = m in exI)
apply(fastsimp simp add:map_add_def split:option.split)
apply clarsimp
apply(rename_tac Ts' T' m')
apply( drule (1) class_wf)
apply( unfold wf_cdecl_def Method_def)
apply( frule map_of_SomeD)
apply(clarsimp)
apply(drule (1) bspec)+
apply clarsimp
apply( erule_tac x=D in allE, erule_tac x=Ts in allE, erule_tac x=T in allE, fastsimp simp:map_add_def split:option.split)
done
(*>*)


lemma sees_method_mono2:
  "[| P \<turnstile> C' \<preceq>* C; wf_prog wf_md P;
     P \<turnstile> C sees M:Ts->T = m in D; P \<turnstile> C' sees M:Ts'->T' = m' in D' |]
  ==> P \<turnstile> Ts [≤] Ts' ∧ P \<turnstile> T' ≤ T"
(*<*)by(blast dest:sees_method_mono sees_method_fun)(*>*)


lemma mdecls_visible:
assumes wf: "wf_prog wf_md P" and "class": "is_class P C"
shows "!!D fs ms. class P C = Some(D,fs,ms)
         ==> ∃Mm. P \<turnstile> C sees_methods Mm ∧ (∀(M,Ts,T,m) ∈ set ms. Mm M = Some((Ts,T,m),C))"
(*<*)
using wf "class"
proof (induct rule:subcls1_induct)
  case Object
  with wf have "distinct_fst ms"
    by (unfold class_def wf_prog_def wf_cdecl_def) (fastsimp dest:map_of_SomeD)
  with Object show ?case by(fastsimp intro!: sees_methods_Object map_of_SomeI)
next
  case Subcls
  with wf have "distinct_fst ms"
    by (unfold class_def wf_prog_def wf_cdecl_def) (fastsimp dest:map_of_SomeD)
  with Subcls show ?case
    by(fastsimp elim:sees_methods_rec dest:subcls1D map_of_SomeI
                simp:is_class_def)
qed
(*>*)


lemma mdecl_visible:
assumes wf: "wf_prog wf_md P" and C: "(C,S,fs,ms) ∈ set P" and  m: "(M,Ts,T,m) ∈ set ms"
shows "P \<turnstile> C sees M:Ts->T = m in C"
(*<*)
proof -
  from wf C have "class": "class P C = Some (S,fs,ms)"
    by (auto simp add: wf_prog_def class_def is_class_def intro: map_of_SomeI)
  from "class" have "is_class P C" by(auto simp:is_class_def)                   
  with prems "class" show ?thesis
    by(bestsimp simp:Method_def dest:mdecls_visible)
qed
(*>*)

lemma external_call_not_sees:
  assumes wf: "wf_prog wf_md P"
  and sees: "P \<turnstile> C sees_methods Mm" "Mm M = ⌊mthd⌋"
  and subcls: "P \<turnstile> C \<preceq>* C' ∨ P \<turnstile> C' \<preceq>* C"
  and ext: "is_external_call P (Class C') M"
  shows False
using sees subcls
proof(induct rule: Methods.induct)
  case (sees_methods_Object D' fs ms Mm)
  from `class P Object = ⌊(D', fs, ms)⌋` wf
  have "wf_cdecl wf_md P (Object, (D', fs, ms))" by(rule class_wf)
  hence "ms = []" by(simp add: wf_cdecl_def)
  with `Mm = Option.map (λm. (m, Object)) o map_of ms` `Mm M = ⌊mthd⌋`
  show False by simp
next
  case (sees_methods_rec C D' fs ms Mm Mm')
  from `class P C = ⌊(D', fs, ms)⌋` wf have wfC: "wf_cdecl wf_md P (C, D', fs, ms)" by(rule class_wf)
  show False
  proof(cases "map_of ms M")
    case (Some a)
    moreover obtain Ts T meth where a: "a = (Ts, T, meth)" by(cases a)
    ultimately have "(M, Ts, T, meth) ∈ set ms" by(auto dest: map_of_SomeD)
    with wfC `C ≠ Object` have "wf_extCall P C M" by(auto simp add: wf_cdecl_def)
    with `P \<turnstile> C \<preceq>* C' ∨ P \<turnstile> C' \<preceq>* C` `is_external_call P (Class C') M`
    show False by(auto simp add: wf_extCall_def)
  next
    case None
    with `Mm' = Mm ++ (Option.map (λm. (m, C)) o map_of ms)` `Mm' M = ⌊mthd⌋`
    have "Mm M = ⌊mthd⌋" by auto
    moreover from `class P C = ⌊(D', fs, ms)⌋` `C ≠ Object`
    have CsubD': "P \<turnstile> C \<prec>1 D'" by(rule subcls1I)
    from `P \<turnstile> C \<preceq>* C' ∨ P \<turnstile> C' \<preceq>* C` have "P \<turnstile> D' \<preceq>* C' ∨ P \<turnstile> C' \<preceq>* D'"
    proof
      assume "P \<turnstile> C \<preceq>* C'"
      thus ?thesis
      proof(cases rule: converse_rtranclpE[consumes 1])
        assume "C = C'"
        with CsubD' show ?thesis by auto
      next
        fix D
        assume "P \<turnstile> C \<prec>1 D" "P \<turnstile> D \<preceq>* C'"
        with CsubD' show ?thesis by(auto elim!: subcls1.cases)
      qed
    next
      assume "P \<turnstile> C' \<preceq>* C"
      with CsubD' show ?thesis by(blast intro: rtranclp.rtrancl_into_rtrancl)
    qed
    ultimately show False by(rule `[|Mm M = ⌊mthd⌋; P \<turnstile> D' \<preceq>* C' ∨ P \<turnstile> C' \<preceq>* D'|] ==> False`)
  qed
qed

lemma external_call_not_sees_method:
  "[| wf_prog wf_md P; P \<turnstile> C sees M: Ts -> T = mthd in D; is_external_call P (Class C') M; P \<turnstile> C \<preceq>* C' ∨ P \<turnstile> C' \<preceq>* C |]
  ==> False"
by(auto simp add: Method_def elim: external_call_not_sees)
   
lemma Call_lemma:
  "[| P \<turnstile> C sees M:Ts->T = m in D; P \<turnstile> C' \<preceq>* C; wf_prog wf_md P |]
  ==> ∃D' Ts' T' m'.
       P \<turnstile> C' sees M:Ts'->T' = m' in D' ∧ P \<turnstile> Ts [≤] Ts' ∧ P \<turnstile> T' ≤ T ∧ P \<turnstile> C' \<preceq>* D'
       ∧ is_type P T' ∧ (∀T∈set Ts'. is_type P T) ∧ wf_md P D' (M,Ts',T',m')"
apply(frule (2) sees_method_mono)
apply(fastsimp intro:sees_method_decl_above dest:sees_wf_mdecl
               simp: wf_mdecl_def)
done

lemma sub_Thread_sees_run:
  assumes wf: "wf_prog wf_md P"
  and PCThread: "P \<turnstile> C \<preceq>* Thread"
  shows "∃D mthd. P \<turnstile> C sees run: []->Void = mthd in D"
proof -
  from class_Thread[OF wf] obtain T' fsT MsT
    where classT: "class P Thread = ⌊(T', fsT, MsT)⌋" by blast
  with wf have wfcThread: "wf_cdecl wf_md P (Thread, T', fsT, MsT)"
    by(auto dest: map_of_is_SomeD bspec simp add: wf_prog_def class_def)
  then obtain mrunT where runThread: "(run, [], Void, mrunT) ∈ set MsT"
    by(auto simp add: wf_cdecl_def)
  moreover have "∃MmT. P \<turnstile> Thread sees_methods MmT ∧
                       (∀(M,Ts,T,m) ∈ set MsT. MmT M = Some((Ts,T,m),Thread))"
    by(rule mdecls_visible[OF wf is_class_Thread[OF wf] classT])
  then obtain MmT where ThreadMmT: "P \<turnstile> Thread sees_methods MmT"
    and MmT: "∀(M,Ts,T,m) ∈ set MsT. MmT M = Some((Ts,T,m),Thread)"
    by blast
  ultimately obtain mthd
    where "MmT run = ⌊(([], Void, mthd), Thread)⌋"
    by(fastsimp)
  with ThreadMmT have Tseesrun: "P \<turnstile> Thread sees run: []->Void = mthd in Thread"
    by(auto simp add: Method_def)
  from sees_method_mono[OF PCThread wf Tseesrun] show ?thesis by auto
qed

lemma wf_Object_method_empty:
  assumes wf: "wf_prog wf_md P"
  and sees: "P \<turnstile> Object sees M: Ts->T = m in D"
  shows False
proof -
  from wf obtain O' fs ms
    where classO: "class P Object = ⌊(O', fs, ms)⌋"
    by(fastsimp dest!: is_class_Object simp add: is_class_def)
  from wf classO have "ms = []"
    by(auto simp add: wf_prog_def wf_cdecl_def class_def dest: map_of_is_SomeD bspec)
  with classO sees show False
    by(auto elim: Methods.cases simp: Method_def)
qed

lemma wf_prog_lift:
  assumes wf: "wf_prog (λP C bd. A P C bd) P"
  and rule:
  "!!wf_md C M Ts C T m bd.
   wf_prog wf_md P ==>
   P \<turnstile> C sees M:Ts->T = m in C ==>   
   set Ts ⊆  is_type P ==>
   bd = (M,Ts,T,m) ==>
   A P C bd ==>
   B P C bd"
  shows "wf_prog (λP C bd. B P C bd) P"
(*<*)
proof -
  from wf show ?thesis
    apply (unfold wf_prog_def wf_cdecl_def)
    apply clarsimp
    apply (drule bspec, assumption)
    apply (unfold wf_mdecl_def)
    apply clarsimp
    apply (drule bspec, assumption)
    apply clarsimp
    apply (frule mdecl_visible [OF wf], assumption+)
    apply (frule is_type_pTs [OF wf], assumption+)
    apply(rule rule[OF wf], assumption+)
    apply auto
    done
qed


subsection{* Well-formedness and field lookup *}

lemma wf_Fields_Ex:
  "[| wf_prog wf_md P; is_class P C |] ==> ∃FDTs. P \<turnstile> C has_fields FDTs"
(*<*)
apply(frule class_Object)
apply(erule (1) subcls1_induct)
 apply(blast intro:has_fields_Object)
apply(blast intro:has_fields_rec dest:subcls1D)
done
(*>*)


lemma has_fields_types:
  "[| P \<turnstile> C has_fields FDTs; (FD,T) ∈ set FDTs; wf_prog wf_md P |] ==> is_type P T"
(*<*)
apply(induct rule:Fields.induct)
 apply(fastsimp dest!: class_wf simp: wf_cdecl_def wf_fdecl_def)
apply(fastsimp dest!: class_wf simp: wf_cdecl_def wf_fdecl_def)
done
(*>*)


lemma sees_field_is_type:
  "[| P \<turnstile> C sees F:T in D; wf_prog wf_md P |] ==> is_type P T"
(*<*)
by(fastsimp simp: sees_field_def
            elim: has_fields_types map_of_SomeD[OF map_of_remap_SomeD])
(*>*)

lemma wf_Object_field_empty:
  assumes wf: "wf_prog wf_md P"
  shows "P \<turnstile> Object has_fields []"
proof -
  from wf obtain O' fs ms where classO: "class P Object = ⌊(O', fs, ms)⌋"
    by -(drule is_class_Object,auto simp add: is_class_def)
  from wf classO have "fs = []"
    by(auto simp add: wf_prog_def wf_cdecl_def class_def dest: map_of_is_SomeD bspec)
  with classO show ?thesis
    by(auto intro: has_fields_Object)
qed

lemma wf_Object_not_has_field [dest]:
  "[| P \<turnstile> Object has F:T in D; wf_prog wf_md P |] ==> False"
by(auto dest: wf_Object_field_empty has_fields_fun simp add: has_field_def)


lemma wf_has_field_mono2:
  assumes wf: "wf_prog wf_md P"
  and has: "P \<turnstile> C has F:T in E"
  shows "[| P \<turnstile> C \<preceq>* D; P \<turnstile> D \<preceq>* E |] ==> P \<turnstile> D has F:T in E"
proof(induct rule: rtranclp_induct)
  case base show ?case using has .
next
  case (step D D')
  note DsubD' = `P \<turnstile> D \<prec>1 D'`
  from DsubD' obtain rest where classD: "class P D = ⌊(D', rest)⌋"
    and DObj: "D ≠ Object" by(auto elim!: subcls1.cases)
  from DsubD' `P \<turnstile> D' \<preceq>* E` have DsubE: "P \<turnstile> D \<preceq>* E" and DsubE2: "(subcls1 P)^++ D E"
    by(rule converse_rtranclp_into_rtranclp rtranclp_into_tranclp2)+
  from wf DsubE2 have DnE: "D ≠ E" by(rule subcls_irrefl)
  from DsubE have hasD: "P \<turnstile> D has F:T in E" by(rule `P \<turnstile> D \<preceq>* E ==> P \<turnstile> D has F:T in E`)
  then obtain FDTs where hasf: "P \<turnstile> D has_fields FDTs" and FE: "map_of FDTs (F, E) = ⌊T⌋"
    unfolding has_field_def by blast
  from hasf show ?case
  proof cases
    case has_fields_Object with DObj show ?thesis by simp
  next
    case (has_fields_rec DD DD' fs ms FDTs' FDTs'')
    with classD have [simp]: "DD = D" "FDTs'' = FDTs" "DD' = D'" "rest = (fs, ms)"
      and hasf': "P \<turnstile> D' has_fields FDTs'"
      and FDTs: "FDTs = map (λ(F, T). ((F, D), T)) fs @ FDTs'" by auto
    from FDTs FE DnE hasf' show ?thesis by(auto dest: map_of_SomeD simp add: has_field_def)
  qed
qed

lemma wf_has_field_idemp:
  "[| wf_prog wf_md P; P \<turnstile> C has F:T in D |] ==> P \<turnstile> D has F:T in D"
apply(frule has_field_decl_above)
apply(erule (2) wf_has_field_mono2)
apply(rule rtranclp.rtrancl_refl)
done

lemma map_of_remap_conv:
  "[| distinct_fst fs; map_of (map (λ(F, y). ((F, D), y)) fs) (F, D) = ⌊T⌋ |]
  ==> map_of (map (λ((F, D), T). (F, D, T)) (map (λ(F, y). ((F, D), y)) fs)) F = ⌊(D, T)⌋"
apply(induct fs)
apply auto
done

lemma has_field_idemp_sees_field:
  assumes wf: "wf_prog wf_md P"
  and has: "P \<turnstile> D has F:T in D"
  shows "P \<turnstile> D sees F:T in D"
proof -
  from has obtain FDTs where hasf: "P \<turnstile> D has_fields FDTs"
    and FD: "map_of FDTs (F, D) = ⌊T⌋" unfolding has_field_def by blast
  from hasf have "map_of (map (λ((F, D), T). (F, D, T)) FDTs) F = ⌊(D, T)⌋"
  proof cases
    case (has_fields_Object D' fs ms FDTs')
    from `class P Object = ⌊(D', fs, ms)⌋` wf
    have "wf_cdecl wf_md P (Object, D', fs, ms)" by(rule class_wf)
    hence "distinct_fst fs" by(simp add: wf_cdecl_def)
    with FD has_fields_Object show ?thesis by(auto intro: map_of_remap_conv simp del: map_map)
  next
    case (has_fields_rec DD D' fs ms FDTs' FDTs'')
    hence [simp]: "DD = D" "FDTs'' = FDTs" "FDTs = map (λ(F, T). ((F, D), T)) fs @ FDTs'"
      and classD: "class P D = ⌊(D', fs, ms)⌋" and DnObj: "D ≠ Object"
      and hasf': "P \<turnstile> D' has_fields FDTs'" by auto
    from `class P D = ⌊(D', fs, ms)⌋` wf
    have "wf_cdecl wf_md P (D, D', fs, ms)" by(rule class_wf)
    hence "distinct_fst fs" by(simp add: wf_cdecl_def)
    moreover have "map_of FDTs' (F, D) = None"
    proof(rule ccontr)
      assume "map_of FDTs' (F, D) ≠ None"
      then obtain T' where "map_of FDTs' (F, D) = ⌊T'⌋" by(auto)
      with hasf' have "P \<turnstile> D' \<preceq>* D" by(auto dest!: map_of_SomeD intro: has_fields_decl_above)
      with classD DnObj have "(subcls1 P)^++ D D"
        by(auto intro: subcls1.intros rtranclp_into_tranclp2)
      with wf show False by(auto dest: subcls_irrefl)
    qed
    ultimately show ?thesis using FD hasf'
      by(auto simp add: map_add_Some_iff intro: map_of_remap_conv simp del: map_map)
  qed
  with hasf show ?thesis unfolding sees_field_def by blast
qed

end