Theory WellType

(*  Title:      JinjaThreads/J/WellType.thy
    Author:     Tobias Nipkow, Andreas Lochbihler
*)

section ‹Well-typedness of Jinja expressions›

theory WellType
imports
  Expr
  State
  "../Common/ExternalCallWF"
  "../Common/WellForm"
  "../Common/SemiType"
begin

declare Listn.lesub_list_impl_same_size[simp del]
declare listE_length [simp del]

type_synonym 
  env  = "vname  ty"

inductive
  WT :: "(ty  ty  ty  bool)  'addr J_prog  env  'addr expr  ty  bool" ("_,_,_  _ :: _"   [51,51,51,51]50)
  and WTs :: "(ty  ty  ty  bool)  'addr J_prog  env  'addr expr list  ty list  bool" 
    ("_,_,_  _ [::] _"   [51,51,51,51]50)
  for is_lub :: "ty  ty  ty  bool" (" lub'((_,/ _)') = _" [51,51,51] 50)
  and P :: "'addr J_prog"
where

  WTNew:
  "is_class P C  
  is_lub,P,E  new C :: Class C"

| WTNewArray:
  " is_lub,P,E  e :: Integer; is_type P (T⌊⌉)  
  is_lub,P,E  newA Te :: T⌊⌉"

| WTCast:
  " is_lub,P,E  e :: T; P  U  T  P  T  U; is_type P U 
   is_lub,P,E  Cast U e :: U"

| WTInstanceOf:
  " is_lub,P,E  e :: T; P  U  T  P  T  U; is_type P U; is_refT U 
   is_lub,P,E  e instanceof U :: Boolean"

| WTVal:
  "typeof v = Some T 
  is_lub,P,E  Val v :: T"

| WTVar:
  "E V = Some T 
  is_lub,P,E  Var V :: T"

| WTBinOp:
  " is_lub,P,E  e1 :: T1; is_lub,P,E  e2 :: T2; P  T1«bop»T2 :: T 
   is_lub,P,E  e1«bop»e2 :: T"

| WTLAss:
  " E V = Some T;  is_lub,P,E  e :: T';  P  T'  T;  V  this 
   is_lub,P,E  V:=e :: Void"

| WTAAcc:
  " is_lub,P,E  a :: T⌊⌉; is_lub,P,E  i :: Integer 
   is_lub,P,E  ai :: T"

| WTAAss:
  " is_lub,P,E  a :: T⌊⌉; is_lub,P,E  i :: Integer; is_lub,P,E  e :: T'; P  T'  T 
   is_lub,P,E  ai := e :: Void"

| WTALength:
  "is_lub,P,E  a :: T⌊⌉  is_lub,P,E  a∙length :: Integer"

| WTFAcc:
  " is_lub,P,E  e :: U; class_type_of' U = C; P  C sees F:T (fm) in D 
   is_lub,P,E  eF{D} :: T"

| WTFAss:
  " is_lub,P,E  e1 :: U; class_type_of' U = C; P  C sees F:T (fm) in D; is_lub,P,E  e2 :: T'; P  T'  T 
   is_lub,P,E  e1F{D}:=e2 :: Void"

| WTCAS:
  " is_lub,P,E  e1 :: U; class_type_of' U = C; P  C sees F:T (fm) in D; volatile fm; 
     is_lub,P,E  e2 :: T'; P  T'  T; is_lub,P,E  e3 :: T''; P  T''  T 
    is_lub,P,E  e1∙compareAndSwap(DF, e2, e3) :: Boolean"

| WTCall:
  " is_lub,P,E  e :: U; class_type_of' U = C; P  C sees M:Ts  T = meth in D;
     is_lub,P,E  es [::] Ts'; P  Ts' [≤] Ts 
   is_lub,P,E  eM(es) :: T"

| WTBlock:
  " is_type P T;  is_lub,P,E(V  T)  e :: T'; case vo of None  True | v  T'. typeof v = T'  P  T'  T 
    is_lub,P,E  {V:T=vo; e} :: T'"

| WTSynchronized:
  " is_lub,P,E  o' :: T; is_refT T; T  NT; is_lub,P,E  e :: T' 
   is_lub,P,E  sync(o') e :: T'"

― ‹Note that insync is not statically typable.›

| WTSeq:
  " is_lub,P,E  e1::T1;  is_lub,P,E  e2::T2 
    is_lub,P,E  e1;;e2 :: T2"

| WTCond:
  " is_lub,P,E  e :: Boolean;  is_lub,P,E  e1::T1;  is_lub,P,E  e2::T2;  lub(T1, T2) = T 
   is_lub,P,E  if (e) e1 else e2 :: T"

| WTWhile:
  " is_lub,P,E  e :: Boolean;  is_lub,P,E  c::T 
   is_lub,P,E  while (e) c :: Void"

| WTThrow:
  " is_lub,P,E  e :: Class C; P  C * Throwable   
  is_lub,P,E  throw e :: Void"

| WTTry:
  " is_lub,P,E  e1 :: T;  is_lub,P,E(V  Class C)  e2 :: T; P  C * Throwable 
   is_lub,P,E  try e1 catch(C V) e2 :: T"

| WTNil: "is_lub,P,E  [] [::] []"

| WTCons: " is_lub,P,E  e :: T; is_lub,P,E  es [::] Ts   is_lub,P,E  e#es [::] T#Ts"

abbreviation WT' :: "'addr J_prog  env  'addr expr  ty  bool" ("_,_  _ :: _" [51,51,51] 50)
where "WT' P  WT (TypeRel.is_lub P) P"

abbreviation WTs' :: "'addr J_prog  env  'addr expr list  ty list  bool" ("_,_  _ [::] _" [51,51,51] 50)
where "WTs' P  WTs (TypeRel.is_lub P) P"

declare WT_WTs.intros[intro!]

inductive_simps WTs_iffs [iff]:
  "is_lub',P,E  [] [::] Ts"
  "is_lub',P,E  e#es [::] T#Ts"
  "is_lub',P,E  e#es [::] Ts"

lemma WTs_conv_list_all2: 
  fixes is_lub 
  shows "is_lub,P,E  es [::] Ts = list_all2 (WT is_lub P E) es Ts"
by(induct es arbitrary: Ts)(auto simp add: list_all2_Cons1 elim: WTs.cases)

lemma WTs_append [iff]: "is_lub Ts. (is_lub,P,E  es1 @ es2 [::] Ts) =
  (Ts1 Ts2. Ts = Ts1 @ Ts2  is_lub,P,E  es1 [::] Ts1  is_lub,P,E  es2[::]Ts2)"
by(auto simp add: WTs_conv_list_all2 list_all2_append1 dest: list_all2_lengthD[symmetric])

inductive_simps WT_iffs [iff]:
  "is_lub',P,E  Val v :: T"
  "is_lub',P,E  Var V :: T"
  "is_lub',P,E  e1;;e2 :: T2"
  "is_lub',P,E  {V:T=vo; e} :: T'"

inductive_cases WT_elim_cases[elim!]:
  "is_lub',P,E  V :=e :: T"
  "is_lub',P,E  sync(o') e :: T"
  "is_lub',P,E  if (e) e1 else e2 :: T"
  "is_lub',P,E  while (e) c :: T"
  "is_lub',P,E  throw e :: T"
  "is_lub',P,E  try e1 catch(C V) e2 :: T"
  "is_lub',P,E  Cast D e :: T"
  "is_lub',P,E  e instanceof U :: T"
  "is_lub',P,E  aF{D} :: T"
  "is_lub',P,E  aF{D} := v :: T"
  "is_lub',P,E  e∙compareAndSwap(DF, e', e'') :: T"
  "is_lub',P,E  e1 «bop» e2 :: T"
  "is_lub',P,E  new C :: T"
  "is_lub',P,E  newA Te :: T'"
  "is_lub',P,E  ai := e :: T"
  "is_lub',P,E  ai :: T"
  "is_lub',P,E  a∙length :: T"
  "is_lub',P,E  eM(ps) :: T"
  "is_lub',P,E  sync(o') e :: T"
  "is_lub',P,E  insync(a) e :: T"

lemma fixes is_lub :: "ty  ty  ty  bool" (" lub'((_,/ _)') = _" [51,51,51] 50)
  assumes is_lub_unique: "T1 T2 T3 T4.   lub(T1, T2) = T3;  lub(T1, T2) = T4   T3 = T4"
  shows WT_unique: " is_lub,P,E  e :: T; is_lub,P,E  e :: T'   T = T'"
  and WTs_unique: " is_lub,P,E  es [::] Ts; is_lub,P,E  es [::] Ts'   Ts = Ts'"
apply(induct arbitrary: T' and Ts' rule: WT_WTs.inducts)
apply blast
apply blast
apply blast
apply blast
apply fastforce
apply fastforce
apply(fastforce dest: WT_binop_fun)
apply fastforce
apply fastforce
apply fastforce
apply fastforce
apply(fastforce dest: sees_field_fun)
apply(fastforce dest: sees_field_fun)
apply blast
apply(fastforce dest: sees_method_fun)
apply fastforce
apply fastforce
apply fastforce
apply(blast dest: is_lub_unique)
apply fastforce
apply fastforce
apply blast
apply fastforce
apply fastforce
done

lemma fixes is_lub
  shows wt_env_mono: "is_lub,P,E  e :: T  (E'. E m E'  is_lub,P,E'  e :: T)"
  and wts_env_mono: "is_lub,P,E  es [::] Ts  (E'. E m E'  is_lub,P,E'  es [::] Ts)"
apply(induct rule: WT_WTs.inducts)
apply(simp add: WTNew)
apply(simp add: WTNewArray)
apply(fastforce simp: WTCast)
apply(fastforce simp: WTInstanceOf)
apply(fastforce simp: WTVal)
apply(simp add: WTVar map_le_def dom_def)
apply(fastforce simp: WTBinOp)
apply(force simp:map_le_def)
apply(simp add: WTAAcc)
apply(simp add: WTAAss, fastforce)
apply(simp add: WTALength, fastforce)
apply(fastforce simp: WTFAcc)
apply(fastforce simp: WTFAss del:WT_WTs.intros WT_elim_cases)
apply blast
apply(fastforce)
apply(fastforce simp: map_le_def WTBlock)
apply(fastforce simp: WTSynchronized)
apply(fastforce simp: WTSeq)
apply(fastforce simp: WTCond)
apply(fastforce simp: WTWhile)
apply(fastforce simp: WTThrow)
apply(fastforce simp: WTTry map_le_def dom_def)
apply(fastforce)+
done

lemma fixes is_lub
  shows WT_fv: "is_lub,P,E  e :: T  fv e  dom E"
  and WT_fvs: "is_lub,P,E  es [::] Ts  fvs es  dom E"
apply(induct rule:WT_WTs.inducts)
apply(simp_all del: fun_upd_apply)
apply fast+
done

lemma fixes is_lub
  shows WT_expr_locks: "is_lub,P,E  e :: T  expr_locks e = (λad. 0)"
  and WTs_expr_lockss: "is_lub,P,E  es [::] Ts  expr_lockss es = (λad. 0)"
by(induct rule: WT_WTs.inducts)(auto)

lemma
  fixes is_lub :: "ty  ty  ty  bool" (" lub'((_,/ _)') = _" [51,51,51] 50)
  assumes is_lub_is_type: "T1 T2 T3.   lub(T1, T2) = T3; is_type P T1; is_type P T2   is_type P T3"
  and wf: "wf_prog wf_md P"
  shows WT_is_type: " is_lub,P,E  e :: T; ran E  types P   is_type P T"
  and WTs_is_type: " is_lub,P,E  es [::] Ts; ran E  types P   set Ts  types P"
apply(induct rule: WT_WTs.inducts)
apply simp
apply simp
apply simp
apply simp
apply (simp add:typeof_lit_is_type)
apply (fastforce intro:nth_mem simp add: ran_def)
apply(simp add: WT_binop_is_type)
apply(simp)
apply(simp del: is_type_array add: is_type_ArrayD)
apply(simp)
apply(simp)
apply(simp add:sees_field_is_type[OF _ wf])
apply(simp)
apply simp
apply(fastforce dest: sees_wf_mdecl[OF wf] simp:wf_mdecl_def)
apply(fastforce simp add: ran_def split: if_split_asm)
apply(simp add: is_class_Object[OF wf])
apply(simp)
apply(simp)
apply(fastforce intro: is_lub_is_type)
apply(simp)
apply(simp)
apply simp
apply simp
apply simp
done

lemma
  fixes is_lub1 :: "ty  ty  ty  bool" ("⊢1 lub'((_,/ _)') = _" [51,51,51] 50)
  and is_lub2 :: "ty  ty  ty  bool" ("⊢2 lub'((_,/ _)') = _" [51,51,51] 50)
  assumes wf: "wf_prog wf_md P"
  and is_lub1_into_is_lub2: "T1 T2 T3.  ⊢1 lub(T1, T2) = T3; is_type P T1; is_type P T2   ⊢2 lub(T1, T2) = T3"
  and is_lub2_is_type: "T1 T2 T3.  ⊢2 lub(T1, T2) = T3; is_type P T1; is_type P T2   is_type P T3"
  shows WT_change_is_lub: " is_lub1,P,E  e :: T; ran E  types P   is_lub2,P,E  e :: T"
  and WTs_change_is_lub: " is_lub1,P,E  es [::] Ts; ran E  types P   is_lub2,P,E  es [::] Ts"
proof(induct rule: WT_WTs.inducts)
  case (WTBlock U E V e' T vo)
  from is_type P U ran E  types P
  have "ran (E(V  U))  types P" by(auto simp add: ran_def)
  hence "is_lub2,P,E(V  U)  e' :: T" by(rule WTBlock)
  with is_type P U show ?case
    using case vo of None  True | v  T'. typeof v = T'  P  T'  U by auto
next
  case (WTCond E e e1 T1 e2 T2 T)
  from ran E  types P have "is_lub2,P,E  e :: Boolean" "is_lub2,P,E  e1 :: T1" "is_lub2,P,E  e2 :: T2"
    by(rule WTCond)+
  moreover from is_lub2_is_type wf is_lub2,P,E  e1 :: T1 ran E  types P
  have "is_type P T1" by(rule WT_is_type)
  from is_lub2_is_type wf is_lub2,P,E  e2 :: T2 ran E  types P
  have "is_type P T2" by(rule WT_is_type)
  with ⊢1 lub(T1, T2) = T is_type P T1
  have "⊢2 lub(T1, T2) = T" by(rule is_lub1_into_is_lub2)
  ultimately show ?case ..
next
  case (WTTry E e1 T V C e2)
  from ran E  types P have "is_lub2,P,E  e1 :: T" by(rule WTTry)
  moreover from P  C * Throwable have "is_class P C"
    by(rule is_class_sub_Throwable[OF wf])
  with ran E  types P have "ran (E(V  Class C))  types P"
    by(auto simp add: ran_def)
  hence "is_lub2,P,E(V  Class C)  e2 :: T" by(rule WTTry)
  ultimately show ?case using P  C * Throwable ..
qed auto

subsection ‹Code generator setup›

lemma WTBlock_code:
  "is_lub.  is_type P T; is_lub,P,E(V  T)  e :: T'; 
     case vo of None  True | v  case typeof v of None  False | Some T'  P  T'  T 
    is_lub,P,E  {V:T=vo; e} :: T'"
by(auto)

lemmas [code_pred_intro] =
  WTNew WTNewArray WTCast WTInstanceOf WTVal WTVar WTBinOp WTLAss WTAAcc WTAAss WTALength WTFAcc WTFAss WTCAS WTCall 
declare 
  WTBlock_code [code_pred_intro WTBlock']
lemmas [code_pred_intro] =
  WTSynchronized WTSeq WTCond WTWhile WTThrow WTTry
  WTNil WTCons

code_pred
  (modes:
    (i ⇒ i ⇒ o ⇒ bool) ⇒ i ⇒ i ⇒ i ⇒ o ⇒ bool, 
    (i ⇒ i ⇒ o ⇒ bool) ⇒ i ⇒ i ⇒ i ⇒ i ⇒ bool)
  [detect_switches, skip_proof]
  WT
proof -
  case WT
  from WT.prems show thesis
  proof cases
    case (WTBlock T V e vo)
    thus thesis using WT.WTBlock'[OF refl refl refl, of V T vo e] by(auto)
  qed(assumption|erule WT.that[OF refl refl refl]|rule refl)+
next
  case WTs
  from WTs.prems WTs.that show thesis by cases blast+
qed

inductive is_lub_sup :: "'m prog  ty  ty  ty  bool"
for P T1 T2 T3
where
  "sup P T1 T2 = OK T3  is_lub_sup P T1 T2 T3"

code_pred
  (modes: i ⇒ i ⇒ i ⇒ o ⇒ bool, i ⇒ i ⇒ i ⇒ i ⇒ bool)
  is_lub_sup
.

definition WT_code :: "'addr J_prog  env  'addr expr  ty  bool" ("_,_  _ ::'' _" [51,51,51] 50)
where "WT_code P  WT (is_lub_sup P) P"

definition WTs_code :: "'addr J_prog  env  'addr expr list  ty list  bool" ("_,_  _ [::''] _" [51,51,51] 50)
where "WTs_code P  WTs (is_lub_sup P) P"

lemma assumes wf: "wf_prog wf_md P"
  shows WT_code_into_WT: 
  " P,E  e ::' T; ran E  types P   P,E  e :: T"

  and WTs_code_into_WTs:
  " P,E  es [::'] Ts; ran E  types P   P,E  es [::] Ts"
proof -
  assume ran: "ran E  types P"
  { assume wt: "P,E  e ::' T"
    show "P,E  e :: T"
      by(rule WT_change_is_lub[OF wf _ _ wt[unfolded WT_code_def] ran])(blast elim!: is_lub_sup.cases intro: sup_is_lubI[OF wf] is_lub_is_type[OF wf])+ }
  { assume wts: "P,E  es [::'] Ts"
    show "P,E  es [::] Ts"
      by(rule WTs_change_is_lub[OF wf _ _ wts[unfolded WTs_code_def] ran])(blast elim!: is_lub_sup.cases intro: sup_is_lubI[OF wf] is_lub_is_type[OF wf])+ }
qed

lemma assumes wf: "wf_prog wf_md P"
  shows WT_into_WT_code: 
  " P,E  e :: T; ran E  types P   P,E  e ::' T"

  and WT_into_WTs_code_OK:
  " P,E  es [::] Ts; ran E  types P   P,E  es [::'] Ts"
proof -
  assume ran: "ran E  types P"
  { assume wt: "P,E  e :: T"
    show "P,E  e ::' T" unfolding WT_code_def
      by(rule WT_change_is_lub[OF wf _ _ wt ran])(blast intro!: is_lub_sup.intros intro: is_lub_subD[OF wf] sup_is_type[OF wf] elim!: is_lub_sup.cases)+ }
  { assume wts: "P,E  es [::] Ts"
    show "P,E  es [::'] Ts" unfolding WTs_code_def
      by(rule WTs_change_is_lub[OF wf _ _ wts ran])(blast intro!: is_lub_sup.intros intro: is_lub_subD[OF wf] sup_is_type[OF wf] elim!: is_lub_sup.cases)+ }
qed

theorem WT_eq_WT_code:
  assumes "wf_prog wf_md P"
  and "ran E  types P"
  shows "P,E  e :: T  P,E  e ::' T"
using assms by(blast intro: WT_code_into_WT WT_into_WT_code)

code_pred
  (modes: i ⇒ i ⇒ i ⇒ i ⇒ bool, i ⇒ i ⇒ i ⇒ o ⇒ bool)
  [inductify]
  WT_code 
.

code_pred
  (modes: i ⇒ i ⇒ i ⇒ i ⇒ bool, i ⇒ i ⇒ i ⇒ o ⇒ bool)
  [inductify]
  WTs_code 
.

end