Theory WellType

(*  Title:      HOL/Bali/WellType.thy
    Author:     David von Oheimb
*)
subsection ‹Well-typedness of Java programs›

theory WellType
imports DeclConcepts
begin

text ‹
improvements over Java Specification 1.0:
\begin{itemize}
\item methods of Object can be called upon references of interface or array type
\end{itemize}
simplifications:
\begin{itemize}
\item the type rules include all static checks on statements and expressions, 
      e.g. definedness of names (of parameters, locals, fields, methods)
\end{itemize}
design issues:
\begin{itemize}
\item unified type judgment for statements, variables, expressions, 
      expression lists
\item statements are typed like expressions with dummy type Void
\item the typing rules take an extra argument that is capable of determining 
  the dynamic type of objects. Therefore, they can be used for both 
  checking static types and determining runtime types in transition semantics.
\end{itemize}
›

type_synonym lenv
        = "(lname, ty) table"  ― ‹local variables, including This and Result›

record env = 
         prg:: "prog"    ― ‹program›
         cls:: "qtname"  ― ‹current package and class name›
         lcl:: "lenv"    ― ‹local environment›     
  
translations
  (type) "lenv" <= (type) "(lname, ty) table"
  (type) "lenv" <= (type) "lname  ty option"
  (type) "env" <= (type) "prg::prog,cls::qtname,lcl::lenv"
  (type) "env" <= (type) "prg::prog,cls::qtname,lcl::lenv,::'a"


abbreviation
  pkg :: "env  pname" ― ‹select the current package from an environment›
  where "pkg e == pid (cls e)"

subsubsection "Static overloading: maximally specific methods "

type_synonym
  emhead = "ref_ty × mhead"

― ‹Some mnemotic selectors for emhead›
definition
  "declrefT" :: "emhead  ref_ty"
  where "declrefT = fst"

definition
  "mhd" :: "emhead  mhead"
  where "mhd  snd"

lemma declrefT_simp[simp]:"declrefT (r,m) = r"
by (simp add: declrefT_def)

lemma mhd_simp[simp]:"mhd (r,m) = m"
by (simp add: mhd_def)

lemma static_mhd_simp[simp]: "static (mhd m) = is_static m"
by (cases m) (simp add: member_is_static_simp mhd_def)

lemma mhd_resTy_simp [simp]: "resTy (mhd m) = resTy m"
by (cases m) simp

lemma mhd_is_static_simp [simp]: "is_static (mhd m) = is_static m"
by (cases m) simp

lemma mhd_accmodi_simp [simp]: "accmodi (mhd m) = accmodi m"
by (cases m) simp

definition
  cmheads :: "prog  qtname  qtname  sig  emhead set"
  where "cmheads G S C = (λsig. (λ(Cls,mthd). (ClassT Cls,(mhead mthd))) ` set_option (accmethd G S C sig))"

definition
  Objectmheads :: "prog  qtname  sig  emhead set" where
  "Objectmheads G S =
    (λsig. (λ(Cls,mthd). (ClassT Cls,(mhead mthd))) 
      ` set_option (filter_tab (λsig m. accmodi m  Private) (accmethd G S Object) sig))"

definition
  accObjectmheads :: "prog  qtname  ref_ty  sig  emhead set"
where
  "accObjectmheads G S T =
    (if GRefT T accessible_in (pid S)
     then Objectmheads G S
     else (λsig. {}))"

primrec mheads :: "prog  qtname  ref_ty  sig  emhead set"
where
  "mheads G S  NullT     = (λsig. {})"
| "mheads G S (IfaceT I) = (λsig. (λ(I,h).(IfaceT I,h)) 
                           ` accimethds G (pid S) I sig  
                             accObjectmheads G S (IfaceT I) sig)"
| "mheads G S (ClassT C) = cmheads G S C"
| "mheads G S (ArrayT T) = accObjectmheads G S (ArrayT T)"

definition
  ― ‹applicable methods, cf. 15.11.2.1›
  appl_methds :: "prog  qtname   ref_ty  sig  (emhead × ty list) set" where
  "appl_methds G S rt = (λ sig. 
      {(mh,pTs') |mh pTs'. mh  mheads G S rt name=name sig,parTs=pTs'  
                           G(parTs sig)[≼]pTs'})"

definition
  ― ‹more specific methods, cf. 15.11.2.2›
  more_spec :: "prog  emhead × ty list  emhead × ty list  bool" where
  "more_spec G = (λ(mh,pTs). λ(mh',pTs'). GpTs[≼]pTs')"
(*more_spec G ≡λ((d,h),pTs). λ((d',h'),pTs'). G⊢RefT d≼RefT d'∧G⊢pTs[≼]pTs'*)

definition
  ― ‹maximally specific methods, cf. 15.11.2.2›
  max_spec :: "prog  qtname  ref_ty  sig  (emhead × ty list) set" where
  "max_spec G S rt sig = {m. m appl_methds G S rt sig 
                          (m'appl_methds G S rt sig. more_spec G m' m  m'=m)}"


lemma max_spec2appl_meths: 
  "x  max_spec G S T sig  x  appl_methds G S T sig" 
by (auto simp: max_spec_def)

lemma appl_methsD: "(mh,pTs')appl_methds G S T name=mn,parTs=pTs   
   mh  mheads G S T name=mn,parTs=pTs'  GpTs[≼]pTs'"
by (auto simp: appl_methds_def)

lemma max_spec2mheads: 
"max_spec G S rt name=mn,parTs=pTs = insert (mh, pTs') A 
  mh  mheads G S rt name=mn,parTs=pTs'  GpTs[≼]pTs'"
apply (auto dest: equalityD2 subsetD max_spec2appl_meths appl_methsD)
done


definition
  empty_dt :: "dyn_ty"
  where "empty_dt = (λa. None)"

definition
  invmode :: "('a::type)member_scheme  expr  inv_mode" where
  "invmode m e = (if is_static m 
                  then Static 
                  else if e=Super then SuperM else IntVir)"

lemma invmode_nonstatic [simp]: 
  "invmode access=a,static=False,=x (Acc (LVar e)) = IntVir"
apply (unfold invmode_def)
apply (simp (no_asm) add: member_is_static_simp)
done


lemma invmode_Static_eq [simp]: "(invmode m e = Static) = is_static m"
apply (unfold invmode_def)
apply (simp (no_asm))
done


lemma invmode_IntVir_eq: "(invmode m e = IntVir) = (¬(is_static m)  eSuper)"
apply (unfold invmode_def)
apply (simp (no_asm))
done

lemma Null_staticD: 
  "a'=Null  (is_static m)  invmode m e = IntVir  a'  Null"
apply (clarsimp simp add: invmode_IntVir_eq)
done

subsubsection "Typing for unary operations"

primrec unop_type :: "unop  prim_ty"
where
  "unop_type UPlus   = Integer"
| "unop_type UMinus  = Integer"
| "unop_type UBitNot = Integer"
| "unop_type UNot    = Boolean"    

primrec wt_unop :: "unop  ty  bool"
where
  "wt_unop UPlus   t = (t = PrimT Integer)"
| "wt_unop UMinus  t = (t = PrimT Integer)"
| "wt_unop UBitNot t = (t = PrimT Integer)"
| "wt_unop UNot    t = (t = PrimT Boolean)"

subsubsection "Typing for binary operations"

primrec binop_type :: "binop  prim_ty"
where
  "binop_type Mul      = Integer"     
| "binop_type Div      = Integer"
| "binop_type Mod      = Integer"
| "binop_type Plus     = Integer"
| "binop_type Minus    = Integer"
| "binop_type LShift   = Integer"
| "binop_type RShift   = Integer"
| "binop_type RShiftU  = Integer"
| "binop_type Less     = Boolean"
| "binop_type Le       = Boolean"
| "binop_type Greater  = Boolean"
| "binop_type Ge       = Boolean"
| "binop_type Eq       = Boolean"
| "binop_type Neq      = Boolean"
| "binop_type BitAnd   = Integer"
| "binop_type And      = Boolean"
| "binop_type BitXor   = Integer"
| "binop_type Xor      = Boolean"
| "binop_type BitOr    = Integer"
| "binop_type Or       = Boolean"
| "binop_type CondAnd  = Boolean"
| "binop_type CondOr   = Boolean"

primrec wt_binop :: "prog  binop  ty  ty  bool"
where
  "wt_binop G Mul     t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G Div     t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G Mod     t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G Plus    t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G Minus   t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G LShift  t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G RShift  t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G RShiftU t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G Less    t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G Le      t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G Greater t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G Ge      t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G Eq      t1 t2 = (Gt1t2  Gt2t1)" 
| "wt_binop G Neq     t1 t2 = (Gt1t2  Gt2t1)"
| "wt_binop G BitAnd  t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G And     t1 t2 = ((t1 = PrimT Boolean)  (t2 = PrimT Boolean))"
| "wt_binop G BitXor  t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G Xor     t1 t2 = ((t1 = PrimT Boolean)  (t2 = PrimT Boolean))"
| "wt_binop G BitOr   t1 t2 = ((t1 = PrimT Integer)  (t2 = PrimT Integer))"
| "wt_binop G Or      t1 t2 = ((t1 = PrimT Boolean)  (t2 = PrimT Boolean))"
| "wt_binop G CondAnd t1 t2 = ((t1 = PrimT Boolean)  (t2 = PrimT Boolean))"
| "wt_binop G CondOr  t1 t2 = ((t1 = PrimT Boolean)  (t2 = PrimT Boolean))"

subsubsection "Typing for terms"

type_synonym tys  = "ty + ty list"
translations
  (type) "tys" <= (type) "ty + ty list"


inductive wt :: "env  dyn_ty  [term,tys]  bool" ("_,___"  [51,51,51,51] 50)
  and wt_stmt :: "env  dyn_ty   stmt        bool" ("_,__∷√"  [51,51,51] 50)
  and ty_expr :: "env  dyn_ty  [expr ,ty ]  bool" ("_,__∷-_" [51,51,51,51] 50)
  and ty_var :: "env  dyn_ty  [var  ,ty ]  bool" ("_,__∷=_" [51,51,51,51] 50)
  and ty_exprs :: "env  dyn_ty  [expr list, ty   list]  bool"
    ("_,__∷≐_" [51,51,51,51] 50)
where

  "E,dts∷√  E,dtIn1r sInl (PrimT Void)"
| "E,dte∷-T  E,dtIn1l eInl T"
| "E,dte∷=T  E,dtIn2  eInl T"
| "E,dte∷≐T  E,dtIn3  eInr T"

― ‹well-typed statements›

| Skip:                                 "E,dtSkip∷√"

| Expr: "E,dte∷-T 
                                         E,dtExpr e∷√"
  ― ‹cf. 14.6›
| Lab:  "E,dtc∷√                    
                                         E,dtl c∷√" 

| Comp: "E,dtc1∷√; 
          E,dtc2∷√ 
                                         E,dtc1;; c2∷√"

  ― ‹cf. 14.8›
| If:   "E,dte∷-PrimT Boolean;
          E,dtc1∷√;
          E,dtc2∷√ 
                                         E,dtIf(e) c1 Else c2∷√"

  ― ‹cf. 14.10›
| Loop: "E,dte∷-PrimT Boolean;
          E,dtc∷√ 
                                         E,dtl While(e) c∷√"
  ― ‹cf. 14.13, 14.15, 14.16›
| Jmp:                                   "E,dtJmp jump∷√"

  ― ‹cf. 14.16›
| Throw: "E,dte∷-Class tn;
          prg EtnC SXcpt Throwable 
                                         E,dtThrow e∷√"
  ― ‹cf. 14.18›
| Try:  "E,dtc1∷√; prg EtnC SXcpt Throwable;
          lcl E (VName vn)=None; E lcl := (lcl E)(VName vnClass tn),dtc2∷√
          
                                         E,dtTry c1 Catch(tn vn) c2∷√"

  ― ‹cf. 14.18›
| Fin:  "E,dtc1∷√; E,dtc2∷√ 
                                         E,dtc1 Finally c2∷√"

| Init: "is_class (prg E) C 
                                         E,dtInit C∷√"
  ― ‹termInit is created on the fly during evaluation (see Eval.thy). 
     The class isn't necessarily accessible from the points termInit 
     is called. Therefor we only demand termis_class and not 
     termis_acc_class here.›

― ‹well-typed expressions›

  ― ‹cf. 15.8›
| NewC: "is_acc_class (prg E) (pkg E) C 
                                         E,dtNewC C∷-Class C"
  ― ‹cf. 15.9›
| NewA: "is_acc_type (prg E) (pkg E) T;
          E,dti∷-PrimT Integer 
                                         E,dtNew T[i]∷-T.[]"

  ― ‹cf. 15.15›
| Cast: "E,dte∷-T; is_acc_type (prg E) (pkg E) T';
          prg ET≼? T' 
                                         E,dtCast T' e∷-T'"

  ― ‹cf. 15.19.2›
| Inst: "E,dte∷-RefT T; is_acc_type (prg E) (pkg E) (RefT T');
          prg ERefT T≼? RefT T' 
                                         E,dte InstOf T'∷-PrimT Boolean"

  ― ‹cf. 15.7.1›
| Lit:  "typeof dt x = Some T 
                                         E,dtLit x∷-T"

| UnOp: "E,dte∷-Te; wt_unop unop Te; T=PrimT (unop_type unop) 
          
          E,dtUnOp unop e∷-T"
  
| BinOp: "E,dte1∷-T1; E,dte2∷-T2; wt_binop (prg E) binop T1 T2; 
           T=PrimT (binop_type binop) 
           
           E,dtBinOp binop e1 e2∷-T"
  
  ― ‹cf. 15.10.2, 15.11.1›
| Super: "lcl E This = Some (Class C); C  Object;
          class (prg E) C = Some c 
                                         E,dtSuper∷-Class (super c)"

  ― ‹cf. 15.13.1, 15.10.1, 15.12›
| Acc:  "E,dtva∷=T 
                                         E,dtAcc va∷-T"

  ― ‹cf. 15.25, 15.25.1›
| Ass:  "E,dtva∷=T; va  LVar This;
          E,dtv ∷-T';
          prg ET'T 
                                         E,dtva:=v∷-T'"

  ― ‹cf. 15.24›
| Cond: "E,dte0∷-PrimT Boolean;
          E,dte1∷-T1; E,dte2∷-T2;
          prg ET1T2  T = T2    prg ET2T1  T = T1 
                                         E,dte0 ? e1 : e2∷-T"

  ― ‹cf. 15.11.1, 15.11.2, 15.11.3›
| Call: "E,dte∷-RefT statT;
          E,dtps∷≐pTs;
          max_spec (prg E) (cls E) statT name=mn,parTs=pTs 
            = {((statDeclT,m),pTs')}
          
                   E,dt{cls E,statT,invmode m e}emn({pTs'}ps)∷-(resTy m)"

| Methd: "is_class (prg E) C;
          methd (prg E) C sig = Some m;
          E,dtBody (declclass m) (stmt (mbody (mthd m)))∷-T 
                                         E,dtMethd C sig∷-T"
 ― ‹The class termC is the dynamic class of the method call 
    (cf. Eval.thy). 
    It hasn't got to be directly accessible from the current package 
    term(pkg E). 
    Only the static class must be accessible (enshured indirectly by 
    termCall). 
    Note that l is just a dummy value. It is only used in the smallstep 
    semantics. To proof typesafety directly for the smallstep semantics 
    we would have to assume conformance of l here!›

| Body: "is_class (prg E) D;
          E,dtblk∷√;
          (lcl E) Result = Some T;
          is_type (prg E) T 
                                         E,dtBody D blk∷-T"
― ‹The class termD implementing the method must not directly be 
     accessible  from the current package term(pkg E), but can also 
     be indirectly accessible due to inheritance (enshured in termCall)
    The result type hasn't got to be accessible in Java! (If it is not 
    accessible you can only assign it to Object).
    For dummy value l see rule termMethd.›

― ‹well-typed variables›

  ― ‹cf. 15.13.1›
| LVar: "lcl E vn = Some T; is_acc_type (prg E) (pkg E) T 
                                         E,dtLVar vn∷=T"
  ― ‹cf. 15.10.1›
| FVar: "E,dte∷-Class C; 
          accfield (prg E) (cls E) C fn = Some (statDeclC,f) 
                         E,dt{cls E,statDeclC,is_static f}e..fn∷=(type f)"
  ― ‹cf. 15.12›
| AVar: "E,dte∷-T.[]; 
          E,dti∷-PrimT Integer 
                                         E,dte.[i]∷=T"


― ‹well-typed expression lists›

  ― ‹cf. 15.11.???›
| Nil:                                  "E,dt[]∷≐[]"

  ― ‹cf. 15.11.???›
| Cons: "E,dte ∷-T;
          E,dtes∷≐Ts 
                                         E,dte#es∷≐T#Ts"


(* for purely static typing *)
abbreviation
  wt_syntax :: "env  [term,tys]  bool" ("___"  [51,51,51] 50)
  where "EtT == E,empty_dtt T"

abbreviation
  wt_stmt_syntax :: "env  stmt  bool" ("__∷√"  [51,51   ] 50)
  where "Es∷√ == EIn1r s  Inl (PrimT Void)"

abbreviation
  ty_expr_syntax :: "env  [expr, ty]  bool" ("__∷-_" [51,51,51] 50) 
  where "Ee∷-T == EIn1l e  Inl T"

abbreviation
  ty_var_syntax :: "env  [var, ty]  bool" ("__∷=_" [51,51,51] 50)
  where "Ee∷=T == EIn2 e  Inl T"

abbreviation
  ty_exprs_syntax :: "env  [expr list, ty list]  bool" ("__∷≐_" [51,51,51] 50)
  where "Ee∷≐T == EIn3 e  Inr T"

notation (ASCII)
  wt_syntax  ("_|-_::_" [51,51,51] 50) and
  wt_stmt_syntax  ("_|-_:<>" [51,51   ] 50) and
  ty_expr_syntax  ("_|-_:-_" [51,51,51] 50) and
  ty_var_syntax  ("_|-_:=_" [51,51,51] 50) and
  ty_exprs_syntax  ("_|-_:#_" [51,51,51] 50)

declare not_None_eq [simp del] 
declare if_split [split del] if_split_asm [split del]
declare split_paired_All [simp del] split_paired_Ex [simp del]
setup map_theory_simpset (fn ctxt => ctxt delloop "split_all_tac")

inductive_cases wt_elim_cases [cases set]:
        "E,dtIn2  (LVar vn)               T"
        "E,dtIn2  ({accC,statDeclC,s}e..fn)T"
        "E,dtIn2  (e.[i])                 T"
        "E,dtIn1l (NewC C)                T"
        "E,dtIn1l (New T'[i])             T"
        "E,dtIn1l (Cast T' e)             T"
        "E,dtIn1l (e InstOf T')           T"
        "E,dtIn1l (Lit x)                 T"
        "E,dtIn1l (UnOp unop e)           T"
        "E,dtIn1l (BinOp binop e1 e2)     T"
        "E,dtIn1l (Super)                 T"
        "E,dtIn1l (Acc va)                T"
        "E,dtIn1l (Ass va v)              T"
        "E,dtIn1l (e0 ? e1 : e2)          T"
        "E,dtIn1l ({accC,statT,mode}emn({pT'}p))T"
        "E,dtIn1l (Methd C sig)           T"
        "E,dtIn1l (Body D blk)            T"
        "E,dtIn3  ([])                    Ts"
        "E,dtIn3  (e#es)                  Ts"
        "E,dtIn1r  Skip                   x"
        "E,dtIn1r (Expr e)                x"
        "E,dtIn1r (c1;; c2)               x"
        "E,dtIn1r (l c)                  x" 
        "E,dtIn1r (If(e) c1 Else c2)      x"
        "E,dtIn1r (l While(e) c)         x"
        "E,dtIn1r (Jmp jump)              x"
        "E,dtIn1r (Throw e)               x"
        "E,dtIn1r (Try c1 Catch(tn vn) c2)x"
        "E,dtIn1r (c1 Finally c2)         x"
        "E,dtIn1r (Init C)                x"
declare not_None_eq [simp] 
declare if_split [split] if_split_asm [split]
declare split_paired_All [simp] split_paired_Ex [simp]
setup map_theory_simpset (fn ctxt => ctxt addloop ("split_all_tac", split_all_tac))

lemma is_acc_class_is_accessible: 
  "is_acc_class G P C  G(Class C) accessible_in P"
by (auto simp add: is_acc_class_def)

lemma is_acc_iface_is_iface: "is_acc_iface G P I  is_iface G I"
by (auto simp add: is_acc_iface_def)

lemma is_acc_iface_Iface_is_accessible: 
  "is_acc_iface G P I  G(Iface I) accessible_in P"
by (auto simp add: is_acc_iface_def)

lemma is_acc_type_is_type: "is_acc_type G P T  is_type G T"
by (auto simp add: is_acc_type_def)

lemma is_acc_iface_is_accessible:
  "is_acc_type G P T  GT accessible_in P"
by (auto simp add: is_acc_type_def)

lemma wt_Methd_is_methd: 
  "EIn1l (Methd C sig)T  is_methd (prg E) C sig"
apply (erule_tac wt_elim_cases)
apply clarsimp
apply (erule is_methdI, assumption)
done


text ‹Special versions of some typing rules, better suited to pattern 
        match the conclusion (no selectors in the conclusion)
›

lemma wt_Call: 
"E,dte∷-RefT statT; E,dtps∷≐pTs;  
  max_spec (prg E) (cls E) statT name=mn,parTs=pTs 
    = {((statDeclC,m),pTs')};rT=(resTy m);accC=cls E;
 mode = invmode m e  E,dt{accC,statT,mode}emn({pTs'}ps)∷-rT"
by (auto elim: wt.Call)


lemma invocationTypeExpr_noClassD: 
" Ee∷-RefT statT
  ( statC. statT  ClassT statC)  invmode m e  SuperM"
proof -
  assume wt: "Ee∷-RefT statT"
  show ?thesis
  proof (cases "e=Super")
    case True
    with wt obtain "C" where "statT = ClassT C" by (blast elim: wt_elim_cases)
    then show ?thesis by blast
  next 
    case False then show ?thesis 
      by (auto simp add: invmode_def)
  qed
qed

lemma wt_Super: 
"lcl E This = Some (Class C); C  Object; class (prg E) C = Some c; D=super c 
 E,dtSuper∷-Class D"
by (auto elim: wt.Super)

lemma wt_FVar:  
"E,dte∷-Class C; accfield (prg E) (cls E) C fn = Some (statDeclC,f);
  sf=is_static f; fT=(type f); accC=cls E 
 E,dt{accC,statDeclC,sf}e..fn∷=fT"
by (auto dest: wt.FVar)


lemma wt_init [iff]: "E,dtInit C∷√ = is_class (prg E) C"
by (auto elim: wt_elim_cases intro: "wt.Init")

declare wt.Skip [iff]

lemma wt_StatRef: 
  "is_acc_type (prg E) (pkg E) (RefT rt)  EStatRef rt∷-RefT rt"
apply (rule wt.Cast)
apply  (rule wt.Lit)
apply   (simp (no_asm))
apply  (simp (no_asm_simp))
apply (rule cast.widen)
apply (simp (no_asm))
done

lemma wt_Inj_elim: 
  "E. E,dttU  case t of 
                       In1 ec  (case ec of 
                                    Inl e  T. U=Inl T  
                                  | Inr s  U=Inl (PrimT Void))  
                     | In2 e  (T. U=Inl T) 
                     | In3 e  (T. U=Inr T)"
apply (erule wt.induct)
apply auto
done

― ‹In the special syntax to distinguish the typing judgements for expressions, 
     statements, variables and expression lists the kind of term corresponds
     to the kind of type in the end e.g. An statement (injection termIn3 
    into terms, always has type void (injection termInl into the generalised
    types. The following simplification procedures establish these kinds of
    correlation.›

lemma wt_expr_eq: "E,dtIn1l tU = (T. U=Inl T  E,dtt∷-T)"
  by (auto, frule wt_Inj_elim, auto)

lemma wt_var_eq: "E,dtIn2 tU = (T. U=Inl T  E,dtt∷=T)"
  by (auto, frule wt_Inj_elim, auto)

lemma wt_exprs_eq: "E,dtIn3 tU = (Ts. U=Inr Ts  E,dtt∷≐Ts)"
  by (auto, frule wt_Inj_elim, auto)

lemma wt_stmt_eq: "E,dtIn1r tU = (U=Inl(PrimT Void)E,dtt∷√)"
  by (auto, frule wt_Inj_elim, auto, frule wt_Inj_elim, auto)

simproc_setup wt_expr ("E,dtIn1l tU") = K (K (fn ct =>
    (case Thm.term_of ct of
      (_ $ _ $ _ $ _ $ (Const _ $ _)) => NONE
    | _ => SOME (mk_meta_eq @{thm wt_expr_eq}))))

simproc_setup wt_var ("E,dtIn2 tU") = K (K (fn ct =>
    (case Thm.term_of ct of
      (_ $ _ $ _ $ _ $ (Const _ $ _)) => NONE
    | _ => SOME (mk_meta_eq @{thm wt_var_eq}))))

simproc_setup wt_exprs ("E,dtIn3 tU") = K (K (fn ct =>
    (case Thm.term_of ct of
      (_ $ _ $ _ $ _ $ (Const _ $ _)) => NONE
    | _ => SOME (mk_meta_eq @{thm wt_exprs_eq}))))

simproc_setup wt_stmt ("E,dtIn1r tU") = K (K (fn ct =>
    (case Thm.term_of ct of
      (_ $ _ $ _ $ _ $ (Const _ $ _)) => NONE
    | _ => SOME (mk_meta_eq @{thm wt_stmt_eq}))))

lemma wt_elim_BinOp:
  "E,dtIn1l (BinOp binop e1 e2)T;
    T1 T2 T3.
       E,dte1∷-T1; E,dte2∷-T2; wt_binop (prg E) binop T1 T2;
          E,dt(if b then In1l e2 else In1r Skip)T3;
          T = Inl (PrimT (binop_type binop))
        P
 P"
apply (erule wt_elim_cases)
apply (cases b)
apply auto
done

lemma Inj_eq_lemma [simp]: 
  "(T. (T'. T = Inj T'  P T')  Q T) = (T'. P T'  Q (Inj T'))"
by auto

(* unused *)
lemma single_valued_tys_lemma [rule_format (no_asm)]: 
  "S T. GST  GTS  S = T  E,dttT   
     G = prg E  (T'. E,dttT'  T  = T')"
apply (cases "E", erule wt.induct)
apply (safe del: disjE)
apply (simp_all (no_asm_use) split del: if_split_asm)
apply (safe del: disjE)
(* 17 subgoals *)
apply (tactic ALLGOALS (fn i =>
  if i = 11 then EVERY'
   [Rule_Insts.thin_tac context "E,dt⊨e0∷-PrimT Boolean" [(bindingE, NONE, NoSyn)],
    Rule_Insts.thin_tac context "E,dt⊨e1∷-T1" [(bindingE, NONE, NoSyn), (bindingT1, NONE, NoSyn)],
    Rule_Insts.thin_tac context "E,dt⊨e2∷-T2" [(bindingE, NONE, NoSyn), (bindingT2, NONE, NoSyn)]] i
  else Rule_Insts.thin_tac context "All P" [(bindingP, NONE, NoSyn)] i))
(*apply (safe del: disjE elim!: wt_elim_cases)*)
apply (tactic ALLGOALS (eresolve_tac context @{thms wt_elim_cases}))
apply (simp_all (no_asm_use) split del: if_split_asm)
apply (erule_tac [12] V = "All P" for P in thin_rl) (* Call *)
apply (blast del: equalityCE dest: sym [THEN trans])+
done

(* unused *)
lemma single_valued_tys: 
"ws_prog (prg E)  single_valued {(t,T). E,dttT}"
apply (unfold single_valued_def)
apply clarsimp
apply (rule single_valued_tys_lemma)
apply (auto intro!: widen_antisym)
done

lemma typeof_empty_is_type: "typeof (λa. None) v = Some T  is_type G T"
  by (induct v) auto

(* unused *)
lemma typeof_is_type: "(a. v  Addr a)  T. typeof dt v = Some T  is_type G T"
  by (induct v) auto

end