Theory J1WellForm

Up to index of Isabelle/HOL/JinjaThreads

theory J1WellForm
imports J1

(*  Title:      JinjaThreads/Compiler/WellType1.thy
    Author:     Andreas Lochbihler, Tobias Nipkow
*)

header {* \isaheader{Well-Formedness of Intermediate Language} *}

theory J1WellForm
imports "../J/JWellForm" J1
begin

subsection "Well-Typedness"

types 
  env1  = "ty list"   --"type environment indexed by variable number"

inductive WT1 :: "J1_prog => env1 => expr1 => ty => bool" ("_,_ \<turnstile>1 _ :: _"   [51,0,0,51] 50)
  and WTs1 :: "J1_prog => env1 => expr1 list => ty list => bool" ("_,_ \<turnstile>1 _ [::] _"   [51,0,0,51]50)
  for P :: J1_prog
  where

  WT1New:
  "is_class P C  ==>
  P,E \<turnstile>1 new C :: Class C"

| WT1NewArray:
  "[| P,E \<turnstile>1 e :: Integer; is_type P T |] ==>
  P,E \<turnstile>1 newA T⌊e⌉ :: T⌊⌉"

| WT1Cast:
  "[| P,E \<turnstile>1 e :: T; P \<turnstile> U ≤ T ∨ P \<turnstile> T ≤ U; is_type P U |]
  ==> P,E \<turnstile>1 Cast U e :: U"

| WT1Val:
  "typeof v = Some T ==>
  P,E \<turnstile>1 Val v :: T"

| WT1Var:
  "[| E!V = T; V < size E |] ==>
  P,E \<turnstile>1 Var V :: T"

| WT1BinOp:
  "[| P,E \<turnstile>1 e1 :: T1; P,E \<turnstile>1 e2 :: T2; P \<turnstile> T1«bop»T2 :: T |]
  ==> P,E \<turnstile>1 e1«bop»e2 :: T"

| WT1LAss:
  "[| E!i = T;  i < size E; P,E \<turnstile>1 e :: T';  P \<turnstile> T' ≤ T |]
  ==> P,E \<turnstile>1 i:=e :: Void"

| WT1AAcc:
  "[| P,E \<turnstile>1 a :: T⌊⌉; P,E \<turnstile>1 i :: Integer |]
  ==> P,E \<turnstile>1 a⌊i⌉ :: T"

| WT1AAss:
  "[| P,E \<turnstile>1 a :: T⌊⌉; P,E \<turnstile>1 i :: Integer; P,E \<turnstile>1 e :: T'; P \<turnstile> T' ≤ T |]
  ==> P,E \<turnstile>1 a⌊i⌉ := e :: Void"

| WT1ALength:
  "P,E \<turnstile>1 a :: T⌊⌉ ==> P,E \<turnstile>1 a•length :: Integer"

| WTFAcc1:
  "[| P,E \<turnstile>1 e :: Class C;  P \<turnstile> C sees F:T in D |]
  ==> P,E \<turnstile>1 e•F{D} :: T"

| WTFAss1:
  "[| P,E \<turnstile>1 e1 :: Class C;  P \<turnstile> C sees F:T in D;  P,E \<turnstile>1 e2 :: T';  P \<turnstile> T' ≤ T |]
  ==> P,E \<turnstile>1 e1•F{D} := e2 :: Void"

| WT1Call:
  "[| P,E \<turnstile>1 e :: Class C; ¬ is_external_call P (Class C) M; P \<turnstile> C sees M:Ts -> T = m in D;
     P,E \<turnstile>1 es [::] Ts'; P \<turnstile> Ts' [≤] Ts |]
  ==> P,E \<turnstile>1 e•M(es) :: T"

| WT1External:
  "[| P,E \<turnstile>1 e :: T; P,E \<turnstile>1 es [::] Ts; P \<turnstile> T•M(Ts) :: U |]
  ==> P,E \<turnstile>1 e•M(es) :: U"

| WT1Block:
  "[| is_type P T;  P,E@[T] \<turnstile>1 e :: T'; case vo of None => True | ⌊v⌋ => ∃T'. typeof v = ⌊T'⌋ ∧ P \<turnstile> T' ≤ T |]
  ==>  P,E \<turnstile>1 {V:T=vo; e} :: T'"

| WT1Synchronized:
  "[| P,E \<turnstile>1 o' :: T; is_refT T; T ≠ NT; P,E@[Class Object] \<turnstile>1 e :: T' |]
  ==> P,E \<turnstile>1 syncV (o') e :: T'"

| WT1Seq:
  "[| P,E \<turnstile>1 e1::T1;  P,E \<turnstile>1 e2::T2 |]
  ==>  P,E \<turnstile>1 e1;;e2 :: T2"

| WT1Cond:
  "[| P,E \<turnstile>1 e :: Boolean;  P,E \<turnstile>1 e1::T1;  P,E \<turnstile>1 e2::T2;
     P \<turnstile> T1 ≤ T2 ∨ P \<turnstile> T2 ≤ T1;  P \<turnstile> T1 ≤ T2 --> T = T2;  P \<turnstile> T2 ≤ T1 --> T = T1 |]
  ==> P,E \<turnstile>1 if (e) e1 else e2 :: T"

| WT1While:
  "[| P,E \<turnstile>1 e :: Boolean;  P,E \<turnstile>1 c::T |]
  ==> P,E \<turnstile>1 while (e) c :: Void"

| WT1Throw:
  "[| P,E \<turnstile>1 e :: Class C; P \<turnstile> C \<preceq>* Throwable |] ==> 
  P,E \<turnstile>1 throw e :: Void"

| WT1Try:
  "[| P,E \<turnstile>1 e1 :: T;  P,E@[Class C] \<turnstile>1 e2 :: T; is_class P C |]
  ==> P,E \<turnstile>1 try e1 catch(C V) e2 :: T"

| WT1Nil: "P,E \<turnstile>1 [] [::] []"

| WT1Cons: "[| P,E \<turnstile>1 e :: T; P,E \<turnstile>1 es [::] Ts |] ==> P,E \<turnstile>1 e#es [::] T#Ts"

declare WT1_WTs1.intros[intro!]
declare WT1Nil[iff]
declare WT1Call[rule del, intro]
declare WT1External[rule del, intro]

inductive_cases WT1_WTs1_cases[elim!]:
  "P,E \<turnstile>1 Val v :: T"
  "P,E \<turnstile>1 Var i :: T"
  "P,E \<turnstile>1 Cast D e :: T"
  "P,E \<turnstile>1 i:=e :: T"
  "P,E \<turnstile>1 {i:U=vo; e} :: T"
  "P,E \<turnstile>1 e1;;e2 :: T"
  "P,E \<turnstile>1 if (e) e1 else e2 :: T"
  "P,E \<turnstile>1 while (e) c :: T"
  "P,E \<turnstile>1 throw e :: T"
  "P,E \<turnstile>1 try e1 catch(C i) e2 :: T"
  "P,E \<turnstile>1 e•F{D} :: T"
  "P,E \<turnstile>1 e1•F{D}:=e2 :: T"
  "P,E \<turnstile>1 e1 «bop» e2 :: T"
  "P,E \<turnstile>1 new C :: T"
  "P,E \<turnstile>1 newA T'⌊e⌉ :: T"
  "P,E \<turnstile>1 a⌊i⌉ := e :: T"
  "P,E \<turnstile>1 a⌊i⌉ :: T"
  "P,E \<turnstile>1 a•length :: T"
  "P,E \<turnstile>1 e•M(es) :: T"
  "P,E \<turnstile>1 syncV (o') e :: T"
  "P,E \<turnstile>1 insyncV (a) e :: T"
  "P,E \<turnstile>1 [] [::] Ts"
  "P,E \<turnstile>1 e#es [::] Ts"

lemma WTs1_same_size: "P,E \<turnstile>1 es [::] Ts ==> size es = size Ts"
by (induct es arbitrary: Ts) auto

lemma WTs1_snoc_cases:
  assumes wt: "P,E \<turnstile>1 es @ [e] [::] Ts"
  obtains T Ts' where "P,E \<turnstile>1 es [::] Ts'" "P,E \<turnstile>1 e :: T"
proof -
  from wt have "∃T Ts'. P,E \<turnstile>1 es [::] Ts' ∧ P,E \<turnstile>1 e :: T"
    by(induct es arbitrary: Ts) auto
  thus thesis by(auto intro: that)
qed

lemma WTs1_append:
  assumes wt: "P,Env \<turnstile>1 es @ es' [::] Ts"
  obtains Ts' Ts'' where "P,Env \<turnstile>1 es [::] Ts'" "P,Env \<turnstile>1 es' [::] Ts''"
proof -
  from wt have "∃Ts' Ts''. P,Env \<turnstile>1 es [::] Ts' ∧ P,Env \<turnstile>1 es' [::] Ts''"
    by(induct es arbitrary: Ts) auto
  thus ?thesis by(auto intro: that)
qed

lemma WT1_not_contains_insync: "P,E \<turnstile>1 e :: T ==> ¬ contains_insync e"
  and WTs1_not_contains_insyncs: "P,E \<turnstile>1 es [::] Ts ==> ¬ contains_insyncs es"
by(induct rule: WT1_WTs1.inducts) auto

lemma WT1_expr_locks: "P,E \<turnstile>1 e :: T ==> expr_locks e = (λa. 0)"
  and WTs1_expr_lockss: "P,E \<turnstile>1 es [::] Ts ==> expr_lockss es = (λa. 0)"
by(induct rule: WT1_WTs1.inducts)(auto)

lemma assumes wf: "wf_prog wfmd P"
  shows WT1_unique: "P,E \<turnstile>1 e :: T1 ==> P,E \<turnstile>1 e :: T2 ==> T1 = T2" 
  and WTs1_unique: "P,E \<turnstile>1 es [::] Ts1 ==> P,E \<turnstile>1 es [::] Ts2 ==> Ts1 = Ts2"
apply(induct arbitrary: T2 and Ts2 rule:WT1_WTs1.inducts)
apply blast
apply blast
apply blast
apply clarsimp
apply blast
apply(blast dest: WT_binop_fun)
apply blast
apply blast
apply blast
apply blast
apply (blast dest:sees_field_idemp sees_field_fun)
apply blast

apply(erule WT1_WTs1_cases)
 apply (blast dest:sees_method_idemp sees_method_fun)
apply(fastsimp dest: external_WT_is_external_call list_all2_lengthD WTs1_same_size)

apply(fastsimp dest: external_WT_is_external_call list_all2_lengthD WTs1_same_size external_WT_determ)
apply blast
apply blast
apply blast
apply blast
apply blast
apply blast
apply blast
apply blast
apply blast
done

lemma assumes wf: "wf_prog p P"
  shows WT1_is_type: "P,E \<turnstile>1 e :: T ==> set E ⊆ is_type P ==> is_type P T"
  and "P,E \<turnstile>1 es [::] Ts ==> set E ⊆ is_type P ==> set Ts ⊆ is_type P"
apply(induct rule:WT1_WTs1.inducts)
apply simp
apply simp
apply simp
apply (simp add:typeof_lit_is_type)
apply (fastsimp intro:nth_mem simp add: mem_def)
apply(simp add: WT_binop_is_type)
apply(simp)
apply(simp)
apply(simp)
apply(simp)
apply (simp add:sees_field_is_type[OF _ wf])
apply simp
apply(fastsimp dest!: sees_wf_mdecl[OF wf] simp:wf_mdecl_def)
apply(fastsimp dest: WT_external_is_type)
apply(simp add: mem_def)
apply(simp add: is_class_Object[OF wf] mem_def)
apply simp
apply blast
apply simp
apply simp
apply simp
apply simp
apply(simp add: mem_def)
done

lemma blocks1_WT:
  "[| P,Env @ Ts \<turnstile>1 body :: T; set Ts ⊆ is_type P |] ==> P,Env \<turnstile>1 blocks1 (length Env) Ts body :: T"
proof(induct n"length Env" Ts body arbitrary: Env rule: blocks1.induct)
  case 1 thus ?case by simp
next
  case (2 n T' Ts e)
  note IH = `!!Env. [|P,Env @ Ts \<turnstile>1 e :: T; set Ts ⊆ is_type P; Suc n = length Env|]
              ==> P,Env \<turnstile>1 blocks1 (length Env) Ts e :: T`
  from `set (T' # Ts) ⊆ is_type P` have "set Ts ⊆ is_type P" "is_type P T'" by(auto simp add: mem_def)
  moreover from `P,Env @ T' # Ts \<turnstile>1 e :: T` have "P,(Env @ [T']) @ Ts \<turnstile>1 e :: T" by simp
  note IH[OF this] `n = length Env`
  ultimately show ?case by auto
qed

subsection{* Well-formedness*}

--"Indices in blocks increase by 1"

consts
  \<B> :: "expr1 => nat => bool"
  \<B>s :: "expr1 list => nat => bool"
primrec
"\<B> (new C) i = True"
"\<B> (newA T⌊e⌉) i = \<B> e i"
"\<B> (Cast C e) i = \<B> e i"
"\<B> (Val v) i = True"
"\<B> (e1 «bop» e2) i = (\<B> e1 i ∧ \<B> e2 i)"
"\<B> (Var j) i = True"
"\<B> (j:=e) i = \<B> e i"
"\<B> (a⌊j⌉) i = (\<B> a i ∧ \<B> j i)"
"\<B> (a⌊j⌉:=e) i = (\<B> a i ∧ \<B> j i ∧ \<B> e i)"
"\<B> (a•length) i = \<B> a i"
"\<B> (e•F{D}) i = \<B> e i"
"\<B> (e1•F{D} := e2) i = (\<B> e1 i ∧ \<B> e2 i)"
"\<B> (e•M(es)) i = (\<B> e i ∧ \<B>s es i)"
"\<B> ({j:T=vo; e}) i = (i = j ∧ \<B> e (i+1))"
"\<B> (syncV (o') e) i = (i = V ∧ \<B> o' i ∧ \<B> e (i+1))"
"\<B> (insyncV (a) e) i = (i = V ∧ \<B> e (i+1))"
"\<B> (e1;;e2) i = (\<B> e1 i ∧ \<B> e2 i)"
"\<B> (if (e) e1 else e2) i = (\<B> e i ∧ \<B> e1 i ∧ \<B> e2 i)"
"\<B> (throw e) i = \<B> e i"
"\<B> (while (e) c) i = (\<B> e i ∧ \<B> c i)"
"\<B> (try e1 catch(C j) e2) i = (\<B> e1 i ∧ i=j ∧ \<B> e2 (i+1))"

"\<B>s [] i = True"
"\<B>s (e#es) i = (\<B> e i ∧ \<B>s es i)"

lemma Bs_append [simp]: "\<B>s (es @ es') n <-> \<B>s es n ∧ \<B>s es' n"
by(induct es) auto

lemma Bs_map_Val [simp]: "\<B>s (map Val vs) n"
by(induct vs) auto

lemma B_blocks1 [intro]: "\<B> body (n + length Ts) ==> \<B> (blocks1 n Ts body) n"
by(induct n Ts body rule: blocks1.induct)(auto)

lemma B_extRet2J [simp]: "\<B> (extRet2J va) n"
by(cases va) auto

lemma B_inline_call: "[| \<B> e n; !!n. \<B> e' n |] ==> \<B> (inline_call e' e) n"
  and Bs_inline_calls: "[| \<B>s es n; !!n. \<B> e' n |] ==> \<B>s (inline_calls e' es) n"
by(induct e and es arbitrary: n and n) auto

lemma red1_preserves_B: "[| P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩; \<B> e n|] ==> \<B> e' n"
  and reds1_preserves_Bs: "[| P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩; \<B>s es n|] ==> \<B>s es' n"
by(induct arbitrary: n and n rule: red1_reds1.inducts)(auto)


primrec syncvars :: "('a, 'a) exp => bool"
  and syncvarss :: "('a, 'a) exp list => bool"
where
  "syncvars (new C) = True"
| "syncvars (newA T⌊e⌉) = syncvars e"
| "syncvars (Cast T e) = syncvars e"
| "syncvars (Val v) = True"
| "syncvars (e1 «bop» e2) = (syncvars e1 ∧ syncvars e2)"
| "syncvars (Var V) = True"
| "syncvars (V:=e) = syncvars e"
| "syncvars (a⌊i⌉) = (syncvars a ∧ syncvars i)"
| "syncvars (a⌊i⌉ := e) = (syncvars a ∧ syncvars i ∧ syncvars e)"
| "syncvars (a•length) = syncvars a"
| "syncvars (e•F{D}) = syncvars e"
| "syncvars (e•F{D} := e2) = (syncvars e ∧ syncvars e2)"
| "syncvars (e•M(es)) = (syncvars e ∧ syncvarss es)"
| "syncvars {V:T=vo;e} = syncvars e"
| "syncvars (syncV (e1) e2) = (syncvars e1 ∧ syncvars e2 ∧ V ∉ fv e2)"
| "syncvars (insyncV (a) e) = (syncvars e ∧ V ∉ fv e)"
| "syncvars (e1;;e2) = (syncvars e1 ∧ syncvars e2)"
| "syncvars (if (b) e1 else e2) = (syncvars b ∧ syncvars e1 ∧ syncvars e2)"
| "syncvars (while (b) c) = (syncvars b ∧ syncvars c)"
| "syncvars (throw e) = syncvars e"
| "syncvars (try e1 catch(C V) e2) = (syncvars e1 ∧ syncvars e2)"

| "syncvarss [] = True"
| "syncvarss (e#es) = (syncvars e ∧ syncvarss es)"

lemma syncvarss_append [simp]: "syncvarss (es @ es') <-> syncvarss es ∧ syncvarss es'"
by(induct es) auto

lemma syncvarss_map_Val [simp]: "syncvarss (map Val vs)"
by(induct vs) auto

definition bsok :: "expr1 => nat => bool"
where "bsok e n ≡ \<B> e n ∧ expr_locks e = (λad. 0)"

definition bsoks :: "expr1 list => nat => bool"
where "bsoks es n ≡ \<B>s es n ∧ expr_lockss es = (λad. 0)"

lemma bsok_simps [simp]:
  "bsok (new C) n = True"
  "bsok (newA T⌊e⌉) n = bsok e n"
  "bsok (Cast T e) n = bsok e n"
  "bsok (e1 «bop» e2) n = (bsok e1 n ∧ bsok e2 n)"
  "bsok (Var V) n = True"
  "bsok (Val v) n = True"
  "bsok (V := e) n = bsok e n"
  "bsok (a⌊i⌉) n = (bsok a n ∧ bsok i n)"
  "bsok (a⌊i⌉ := e) n = (bsok a n ∧ bsok i n ∧ bsok e n)"
  "bsok (a•length) n = bsok a n"
  "bsok (e•F{D}) n = bsok e n"
  "bsok (e•F{D} := e') n = (bsok e n ∧ bsok e' n)"
  "bsok (e•M(ps)) n = (bsok e n ∧ bsoks ps n)"
  "bsok {V:T=vo; e} n = (bsok e (Suc n) ∧ V = n)"
  "bsok (syncV (e) e') n = (bsok e n ∧ bsok e' (Suc n) ∧ V = n)"
  "bsok (insyncV (ad) e) n = False"
  "bsok (e;; e') n = (bsok e n ∧ bsok e' n)"
  "bsok (if (e) e1 else e2) n = (bsok e n ∧ bsok e1 n ∧ bsok e2 n)"
  "bsok (while (b) c) n = (bsok b n ∧ bsok c n)"
  "bsok (throw e) n = bsok e n"
  "bsok (try e catch(C V) e') n = (bsok e n ∧ bsok e' (Suc n) ∧ V = n)"
  and bsoks_simps [simp]:
  "bsoks [] n = True"
  "bsoks (e # es) n = (bsok e n ∧ bsoks es n)"
by(auto simp add: bsok_def bsoks_def expand_fun_eq)

lemma WT1_fv: "[| P,E \<turnstile>1 e :: T; \<B> e (length E); syncvars e |] ==> fv e ⊆ {0..<length E}"
  and WTs1_fvs: "[| P,E \<turnstile>1 es [::] Ts; \<B>s es (length E); syncvarss es |] ==> fvs es ⊆ {0..<length E}"
proof(induct rule: WT1_WTs1.inducts)
  case (WT1Synchronized E e1 T e2 T' V)
  note IH1 = `[|\<B> e1 (length E); syncvars e1|] ==> fv e1 ⊆ {0..<length E}`
  note IH2 = `[|\<B> e2 (length (E @ [Class Object])); syncvars e2|] ==> fv e2 ⊆ {0..<length (E @ [Class Object])}`
  from `\<B> (syncV (e1) e2) (length E)` have [simp]: "V = length E"
    and B1: "\<B> e1 (length E)" and B2: "\<B> e2 (Suc (length E))" by auto
  from `syncvars (syncV (e1) e2)` have sync1: "syncvars e1" and sync2: "syncvars e2" and V: "V ∉ fv e2" by auto
  have "fv e2 ⊆ {0..<length E}"
  proof
    fix x
    assume x: "x ∈ fv e2"
    with V have "x ≠ length E" by auto
    moreover from IH2 B2 sync2 have "fv e2 ⊆ {0..<Suc (length E)}" by auto
    with x have "x < Suc (length E)" by auto
    ultimately show "x ∈ {0..<length E}" by auto
  qed
  with IH1[OF B1 sync1] show ?case by(auto)
next
  case (WT1Cond E e e1 T1 e2 T2 T)
  thus ?case by(auto del: subsetI)
qed fastsimp+


definition wf_J1_mdecl :: "J1_prog => cname => expr1 mdecl => bool"
where
  "wf_J1_mdecl P C  ≡  λ(M,Ts,T,body).
    (∃T'. P,Class C#Ts \<turnstile>1 body :: T' ∧ P \<turnstile> T' ≤ T) ∧
    \<D> body ⌊{..size Ts}⌋ ∧ \<B> body (size Ts + 1) ∧ syncvars body"

lemma wf_J1_mdecl[simp]:
  "wf_J1_mdecl P C (M,Ts,T,body) ≡
    ((∃T'. P,Class C#Ts \<turnstile>1 body :: T' ∧ P \<turnstile> T' ≤ T) ∧
     \<D> body ⌊{..size Ts}⌋ ∧ \<B> body (size Ts + 1)) ∧ syncvars body"
by (simp add:wf_J1_mdecl_def)

abbreviation wf_J1_prog :: "J1_prog => bool"
where "wf_J1_prog == wf_prog wf_J1_mdecl"

end