Theory WellForm

(*  Title:      Jinja/J/WellForm.thy

    Author:     Tobias Nipkow
    Copyright   2003 Technische Universitaet Muenchen

section ‹Generic Well-formedness of programs›

theory WellForm imports TypeRel SystemClasses 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 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.

type_synonym 'm wf_mdecl_test = "'m prog  cname  'm mdecl  bool"

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

definition wf_mdecl :: "'m wf_mdecl_test  'm wf_mdecl_test"
  "wf_mdecl wf_md P C  λ(M,Ts,T,mb).
  (Tset 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"
  "wf_cdecl wf_md P    λ(C,(D,fs,ms)).
  (fset fs. wf_fdecl P f)   distinct_fst fs 
  (mset ms. wf_mdecl wf_md P C m)   distinct_fst ms 
  (C  Object 
   is_class P D  ¬ P  D * C 
   ((M,Ts,T,m)set ms.
      D' Ts' T' m'. P  D sees M:Ts'  T' = m' in D' 
                       P  Ts' [≤] Ts  P  T  T'))"

definition wf_syscls :: "'m prog  bool"
  "wf_syscls P    {Object}  sys_xcpts  set(map fst P)"

definition 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)"
(*<*)by (unfold wf_prog_def class_def) (fast dest: map_of_SomeD)(*>*)

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

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 ⊢ C ≼* D"
shows "is_class P C ⟹ is_class P D"
using sub proof(induct)
  case step then show ?case
    by(auto simp:wf_cdecl_def is_class_def dest!:class_wf[OF _ wf] subcls1D)
qed simp

This is NOT true because P ⊢ NT ≤ Class C for any Class C
lemma is_type_suptype: "⟦ wf_prog p P; is_type P T; P ⊢ T ≤ T' ⟧
 ⟹ is_type P T'"

lemma is_class_xcpt:
  " C  sys_xcpts; wf_prog wf_md P   is_class P C"
by (fastforce intro!: map_of_SomeI
              simp add: wf_prog_def wf_syscls_def is_class_def class_def)

lemma subcls1_wfD:
assumes sub1: "P  C 1 D" and wf: "wf_prog wf_md P"
shows "D  C  (D,C)  (subcls1 P)+"
proof -
  obtain fs ms where "C  Object" and cls: "class P C = (D, fs, ms)"
    using subcls1D[OF sub1] by clarify
  then show ?thesis using wf class_wf[OF cls wf] r_into_trancl[OF sub1]
    by(force simp add: wf_cdecl_def reflcl_trancl [THEN sym]
             simp del: reflcl_trancl)

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)+"
(*<*)by(erule tranclE; fast dest!: subcls1_wfD intro: trancl_trans)(*>*)

lemma subcls_irrefl:
  " wf_prog wf_md P; (C,D)  (subcls1 P)+   C  D"
(*<*)by (erule trancl_trans_induct) (auto dest: subcls1_wfD subcls_asym)(*>*)

lemma acyclic_subcls1:
  "wf_prog wf_md P  acyclic (subcls1 P)"
(*<*)by (unfold acyclic_def) (fast dest: subcls_irrefl)(*>*)

lemma wf_subcls1:
  "wf_prog wf_md P  wf ((subcls1 P)¯)"
proof -
  assume wf: "wf_prog wf_md P"
  have "finite (subcls1 P)" by(rule finite_subcls1)
  then have fin': "finite ((subcls1 P)¯)" by(subst finite_converse)

  from wf have "acyclic (subcls1 P)" by(rule acyclic_subcls1)
  then have acyc': "acyclic ((subcls1 P)¯)" by (subst acyclic_converse)

  from fin' acyc' show ?thesis by (rule finite_acyclic_wf)

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 then have wf: "wf_prog wf_md P" by assumption
  have wf':"wf (((subcls1 P)+)¯)" using wf_trancl[OF wf_subcls1[OF wf]]
    by(simp only: trancl_converse)
  show ?thesis using wf_induct[where a = C and P = Q, OF wf' p] by simp

lemma subcls1_induct_aux:
assumes "is_class P C" and wf: "wf_prog wf_md P" and QObj: "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  C 1 D  is_class P D  Q D  Q C 
   Q C"
  (is "PROP ?P  _")
proof -
  assume p: "PROP ?P"
  have "class P C  None  Q C"
  proof(induct rule: subcls_induct[OF wf])
    case (1 C)
    have "class P C  None  Q C"
    proof(cases "C = Object")
      case True
      then show ?thesis using QObj by fast
      case False
      assume nNone: "class P C  None"
      then have is_cls: "is_class P C" by(simp add: is_class_def)
      obtain D fs ms where cls: "class P C = (D, fs, ms)" using nNone by safe
      also have wfC: "wf_cdecl wf_md P (C, D, fs, ms)" by(rule class_wf[OF cls wf])
      moreover have D: "is_class P D" by(rule wf_cdecl_supD[OF wfC False])
      moreover have "P  C 1 D" by(rule subcls1I[OF cls False])
      moreover have "class P D  None" using D by(simp add: is_class_def)
      ultimately show ?thesis using 1 by (auto intro: p[OF False is_cls])
  then show "class P C  None  Q C" by simp
  thus ?thesis using assms by(unfold is_class_def) simp

(* 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  C 1 D; is_class P D; Q D  Q C 
   Q C"
(*<*)by (erule (2) subcls1_induct_aux) blast(*>*)

lemma subcls_C_Object:
assumes "class": "is_class P C" and wf: "wf_prog wf_md P"
shows "P  C * Object"
using wf "class"
proof(induct rule: subcls1_induct)
  case Subcls
  then show ?case by(simp add: converse_rtrancl_into_rtrancl)
qed fast

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"
  from assms 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" ..

subsection‹Well-formedness and method lookup›

lemma sees_wf_mdecl:
assumes wf: "wf_prog wf_md P" and sees: "P  C sees M:TsT = m in D"
shows "wf_mdecl wf_md P D (M,Ts,T,m)"
using wf visible_method_exists[OF sees]
by(fastforce simp:wf_cdecl_def dest!:class_wf dest:map_of_SomeD)

lemma sees_method_mono [rule_format (no_asm)]: 
assumes sub: "P  C' * C" and wf: "wf_prog wf_md P"
shows "D Ts T m. P  C sees M:TsT = m in D 
     (D' Ts' T' m'. P  C' sees M:Ts'T' = m' in D'  P  Ts [≤] Ts'  P  T'  T)"
  (is "D Ts T m. ?P C D Ts T m  ?Q C' D Ts T m")
proof(rule disjE[OF rtranclD[OF sub]])
  assume "C' = C"
  then show ?thesis using assms by fastforce
  assume "C'  C  (C', C)  (subcls1 P)+"
  then have neq: "C'  C" and subcls1: "(C', C)  (subcls1 P)+" by simp+
  show ?thesis proof(induct rule: trancl_trans_induct[OF subcls1])
    case (2 x y z)
    then have zy: "D Ts T m. ?P z D Ts T m  ?Q y D Ts T m" by blast
    have "D Ts T m. ?P z D Ts T m  ?Q x D Ts T m"
    proof -
      fix D Ts T m assume P: "?P z D Ts T m"
      then show "?Q x D Ts T m" using zy[OF P] 2(2)
        by(fast elim: widen_trans widens_trans)
    then show ?case by blast
    case (1 x y)
    have "D Ts T m. ?P y D Ts T m  ?Q x D Ts T m"
    proof -
      fix D Ts T m assume P: "?P y D Ts T m"
      then obtain Mm where sees: "P  y sees_methods Mm" and
                           M: "Mm M = ((Ts, T, m), D)"
        by(clarsimp simp:Method_def)
      obtain fs ms where nObj: "x  Object" and
                         cls: "class P x = (y, fs, ms)"
        using subcls1D[OF 1] by clarsimp
      have x_meth: "P  x sees_methods Mm ++ (map_option (λm. (m, x))  map_of ms)"
        using sees_methods_rec[OF cls nObj sees] by simp
      show "?Q x D Ts T m" proof(cases "map_of ms M")
        case None
        then have "m'. P  x sees M :  TsT = m' in D" using M x_meth
          by(fastforce simp add:Method_def map_add_def split:option.split)
        then show ?thesis by auto
        case (Some a)
        then obtain Ts' T' m' where a: "a = (Ts',T',m')" by(cases a)
        then have "(m' Mm. P  y sees_methods Mm  Mm M = ((Ts, T, m'), D))
               P  Ts [≤] Ts'  P  T'  T"
          using nObj class_wf[OF cls wf] map_of_SomeD[OF Some]
          by(clarsimp simp: wf_cdecl_def Method_def) fast
        then show ?thesis using Some a sees M x_meth
          by(fastforce simp:Method_def map_add_def split:option.split)
    then show ?case by simp

lemma sees_method_mono2:
  " P  C' * C; wf_prog wf_md P;
     P  C sees M:TsT = m in D; P  C' sees M:Ts'T' = m' in D' 
   P  Ts [≤] Ts'  P  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  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) (fastforce dest:map_of_SomeD)
  with Object show ?case by(fastforce intro!: sees_methods_Object map_of_SomeI)
  case Subcls
  with wf have "distinct_fst ms"
    by (unfold class_def wf_prog_def wf_cdecl_def) (fastforce dest:map_of_SomeD)
  with Subcls show ?case
    by(fastforce elim:sees_methods_rec dest:subcls1D map_of_SomeI

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  C sees M:TsT = 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 assms "class" show ?thesis
    by(bestsimp simp:Method_def dest:mdecls_visible)

lemma Call_lemma:
assumes sees: "P  C sees M:TsT = m in D" and sub: "P  C' * C" and wf: "wf_prog wf_md P"
shows "D' Ts' T' m'.
       P  C' sees M:Ts'T' = m' in D'  P  Ts [≤] Ts'  P  T'  T  P  C' * D'
        is_type P T'  (Tset Ts'. is_type P T)  wf_md P D' (M,Ts',T',m')"
using assms sees_method_mono[OF sub wf sees]
by(fastforce intro:sees_method_decl_above dest:sees_wf_mdecl
             simp: wf_mdecl_def)

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  C sees M:TsT = 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 -
  have "c. cset P  wf_cdecl A P c  wf_cdecl B P c"
  proof -
    fix c assume "cset P" and "wf_cdecl A P c"
    then show "wf_cdecl B P c"
     using rule[OF wf mdecl_visible[OF wf] is_type_pTs[OF wf]]
     by (auto simp: wf_cdecl_def wf_mdecl_def)
  then show ?thesis using wf by (clarsimp simp: wf_prog_def)

subsection‹Well-formedness and field lookup›

lemma wf_Fields_Ex:
assumes wf: "wf_prog wf_md P" and "is_class P C"
shows "FDTs. P  C has_fields FDTs"
using assms proof(induct rule:subcls1_induct)
  case Object
  then show ?case using class_Object[OF wf]
    by(blast intro:has_fields_Object)
  case Subcls
  then show ?case by(blast intro:has_fields_rec dest:subcls1D)

lemma has_fields_types:
  " P  C has_fields FDTs; (FD,T)  set FDTs; wf_prog wf_md P   is_type P T"
proof(induct rule:Fields.induct)
qed(fastforce dest!: class_wf simp: wf_cdecl_def wf_fdecl_def)+

lemma sees_field_is_type:
  " P  C sees F:T in D; wf_prog wf_md P   is_type P T"
by(fastforce 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"
by (force simp add: image_def SystemClasses_def wf_syscls_def sys_xcpts_def
                 ObjectC_def NullPointerC_def ClassCastC_def OutOfMemoryC_def)