(* Title: Jinja/J/WellForm.thy
ID: $Id: WellForm.html 1910 2004-05-19 04:46:04Z kleing $
Author: Tobias Nipkow
Copyright 2003 Technische Universitaet Muenchen
*)
header {* \isaheader{Generic Well-formedness of programs} *}
theory WellForm = TypeRel + SystemClasses:
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 Jinja 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"
constdefs
wf_fdecl :: "'m prog => fdecl => bool"
"wf_fdecl P ≡ λ(F,T). is_type P T"
wf_mdecl :: "'m wf_mdecl_test => 'm wf_mdecl_test"
"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)"
wf_cdecl :: "'m wf_mdecl_test => 'm prog => 'm cdecl => bool"
"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.
∀D' Ts' T' m'. P \<turnstile> D sees M:Ts' -> T' = m' in D' -->
P \<turnstile> Ts' [≤] Ts ∧ P \<turnstile> T ≤ T'))"
wf_syscls :: "'m prog => bool"
"wf_syscls P ≡ {Object} ∪ sys_xcpts ⊆ set(map fst P)"
wf_prog :: "'m wf_mdecl_test => 'm prog => bool"
"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 is_class_Object [simp]:
"wf_prog wf_md P ==> is_class P Object"
(*<*)by (simp add: is_class_def)(*>*)
(* Unused
lemma is_class_supclass:
assumes wf: "wf_prog wf_md P" and sub: "P \<turnstile> C \<preceq>* D"
shows "is_class P C ==> is_class P D"
using sub apply(induct)
apply assumption
apply(fastsimp simp:wf_cdecl_def subcls1_def is_class_def
dest:class_wf[OF _ wf])
done
This is NOT true because P \<turnstile> NT ≤ Class C for any Class C
lemma is_type_suptype: "[| wf_prog p P; is_type P T; P \<turnstile> T ≤ T' |]
==> is_type P T'"
*)
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 subcls1_wfD:
"[| P \<turnstile> C \<prec>1 D; wf_prog wf_md P |] ==> D ≠ C ∧ (D,C) ∉ (subcls1 P)+"
(*<*)
apply( frule r_into_trancl)
apply( drule subcls1D)
apply(clarify)
apply( drule (1) class_wf)
apply( unfold wf_cdecl_def)
apply(force simp add: reflcl_trancl [THEN sym] simp del: reflcl_trancl)
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; (C,D) ∈ (subcls1 P)+ |] ==> (D,C) ∉ (subcls1 P)+"
(*<*)
apply(erule tranclE)
apply(fast dest!: subcls1_wfD )
apply(fast dest!: subcls1_wfD intro: trancl_trans)
done
(*>*)
lemma subcls_irrefl:
"[| wf_prog wf_md P; (C,D) ∈ (subcls1 P)+ |] ==> C ≠ D"
(*<*)
apply (erule trancl_trans_induct)
apply (auto dest: subcls1_wfD subcls_asym)
done
(*>*)
lemma acyclic_subcls1:
"wf_prog wf_md P ==> acyclic (subcls1 P)"
(*<*)
apply (unfold acyclic_def)
apply (fast dest: subcls_irrefl)
done
(*>*)
lemma wf_subcls1:
"wf_prog wf_md P ==> wf ((subcls1 P)¯)"
(*<*)
apply (rule finite_acyclic_wf)
apply ( subst finite_converse)
apply ( rule finite_subcls1)
apply (subst acyclic_converse)
apply (erule acyclic_subcls1)
done
(*>*)
lemma single_valued_subcls1:
"wf_prog wf_md G ==> single_valued (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. (C,D) ∈ (subcls1 P)+ --> 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 wf_trancl)
apply(simp only: trancl_converse)
apply(erule_tac a = C in wf_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
(*>*)
(* FIXME can't we prove this one directly?? *)
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_rtrancl_into_rtrancl)
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 ⊆ types 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 ∈ types P" ..
qed
(*>*)
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(fastsimp simp:wf_cdecl_def dest!:class_wf dest:map_of_SomeD)
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 rtranclD)
apply( erule disjE)
apply( fastsimp)
apply( erule conjE)
apply( erule trancl_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 simp
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 auto
apply(drule (1) bspec, simp)
apply(erule_tac x=D in allE, erule_tac x=Ts in allE, erule_tac x=T in allE)
apply(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 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 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 ⊆ types 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 (drule 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_syscls:
"set SystemClasses ⊆ set P ==> wf_syscls P"
apply (simp add: image_def SystemClasses_def wf_syscls_def sys_xcpts_def
ObjectC_def NullPointerC_def ClassCastC_def OutOfMemoryC_def)
apply(rule conjI)
apply force
apply (rule allI, case_tac x)
apply (force)+
done
*)
end
lemma class_wf:
[| class P C = ⌊c⌋; wf_prog wf_md P |] ==> wf_cdecl wf_md P (C, c)
lemma class_Object:
wf_prog wf_md P ==> EX C fs ms. class P Object = ⌊(C, fs, ms)⌋
lemma is_class_Object:
wf_prog wf_md P ==> is_class P Object
lemma is_class_xcpt:
[| C : sys_xcpts; wf_prog wf_md P |] ==> is_class P C
lemma subcls1_wfD:
[| subcls1 P C D; wf_prog wf_md P |] ==> D ~= C & (D, C) ~: (subcls1 P)^+
lemma wf_cdecl_supD:
[| wf_cdecl wf_md P (C, D, r); C ~= Object |] ==> is_class P D
lemma subcls_asym:
[| wf_prog wf_md P; (C, D) : (subcls1 P)^+ |] ==> (D, C) ~: (subcls1 P)^+
lemma subcls_irrefl:
[| wf_prog wf_md P; (C, D) : (subcls1 P)^+ |] ==> C ~= D
lemma acyclic_subcls1:
wf_prog wf_md P ==> acyclic (subcls1 P)
lemma wf_subcls1:
wf_prog wf_md P ==> wf ((subcls1 P)^-1)
lemma single_valued_subcls1:
wf_prog wf_md G ==> single_valued (subcls1 G)
lemma subcls_induct:
[| wf_prog wf_md P; !!C. ALL D. (C, D) : (subcls1 P)^+ --> Q D ==> Q C |] ==> Q C
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 = ⌊(D, fs, ms)⌋ & wf_cdecl wf_md P (C, D, fs, ms) & subcls1 P C D & is_class P D & Q D |] ==> Q C |] ==> Q C
lemma subcls1_induct:
[| wf_prog wf_md P; is_class P C; Q Object; !!C D. [| C ~= Object; subcls1 P C D; is_class P D; Q D |] ==> Q C |] ==> Q C
lemma subcls_C_Object:
[| is_class P C; wf_prog wf_md P |] ==> subcls P C Object
lemma
[| wf_prog wf_md P; (C, S, fs, ms) : set P; (M, Ts, T, m) : set ms |] ==> set Ts <= types P
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)
lemma sees_method_mono:
[| subcls P C' C; wf_prog wf_md P; P \<turnstile> C sees M: Ts->T = m in D |] ==> EX D' Ts' T' m'. P \<turnstile> C' sees M: Ts'->T' = m' in D' & widens P Ts Ts' & widen P T' T
lemma sees_method_mono2:
[| subcls P C' 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' |] ==> widens P Ts Ts' & widen P T' T
lemma
[| wf_prog wf_md P; is_class P C; class P C = ⌊(D, fs, ms)⌋ |] ==> EX Mm. P \<turnstile> C sees_methods Mm & (ALL (M, Ts, T, m):set ms. Mm M = ⌊((Ts, T, m), C)⌋)
lemma
[| wf_prog wf_md P; (C, S, fs, ms) : set P; (M, Ts, T, m) : set ms |] ==> P \<turnstile> C sees M: Ts->T = m in C
lemma Call_lemma:
[| P \<turnstile> C sees M: Ts->T = m in D; subcls P C' C; wf_prog wf_md P |] ==> EX D' Ts' T' m'. P \<turnstile> C' sees M: Ts'->T' = m' in D' & widens P Ts Ts' & widen P T' T & subcls P C' D' & is_type P T' & (ALL T:set Ts'. is_type P T) & wf_md P D' (M, Ts', T', m')
lemma
[| wf_prog A P; !!wf_md C M Ts Ca T m bd. [| wf_prog wf_md P; P \<turnstile> Ca sees M: Ts->T = m in Ca; set Ts <= types P; bd = (M, Ts, T, m); A P Ca bd |] ==> B P Ca bd |] ==> wf_prog B P
lemma wf_Fields_Ex:
[| wf_prog wf_md P; is_class P C |] ==> EX FDTs. P \<turnstile> C has_fields FDTs
lemma has_fields_types:
[| P \<turnstile> C has_fields FDTs; (FD, T) : set FDTs; wf_prog wf_md P |] ==> is_type P T
lemma sees_field_is_type:
[| P \<turnstile> C sees F:T in D; wf_prog wf_md P |] ==> is_type P T