Session WebAssembly

Theory Wasm_Ast

section ‹WebAssembly Core AST›

theory Wasm_Ast
  imports
    Main
    "Native_Word.Uint8"
    "Word_Lib.Reversed_Bit_Lists"
begin

type_synonym ― ‹immediate›
  i = nat
type_synonym ― ‹static offset›
  off = nat
type_synonym ― ‹alignment exponent›
  a = nat

― ‹primitive types›
typedecl i32
typedecl i64
typedecl f32
typedecl f64

― ‹memory›
type_synonym byte = uint8

typedef bytes = "UNIV :: (byte list) set" ..
setup_lifting type_definition_bytes
declare Quotient_bytes[transfer_rule]

lift_definition bytes_takefill :: "byte  nat  bytes  bytes" is "(λa n as. takefill (Abs_uint8 a) n as)" .
lift_definition bytes_replicate :: "nat  byte  bytes" is "(λn b. replicate n (Abs_uint8 b))" .
definition msbyte :: "bytes  byte" where
  "msbyte bs = last (Rep_bytes bs)"

typedef mem = "UNIV :: (byte list) set" ..
setup_lifting type_definition_mem
declare Quotient_mem[transfer_rule]

lift_definition read_bytes :: "mem  nat  nat  bytes" is "(λm n l. take l (drop n m))" .
lift_definition write_bytes :: "mem  nat  bytes  mem" is "(λm n bs. (take n m) @ bs @ (drop (n + length bs) m))" .
lift_definition mem_append :: "mem  bytes  mem" is append .

― ‹host›
typedecl host
typedecl host_state

datatype ― ‹value types›
  t = T_i32 | T_i64 | T_f32 | T_f64

datatype ― ‹packed types›
  tp = Tp_i8 | Tp_i16 | Tp_i32

datatype ― ‹mutability›
  mut = T_immut | T_mut

record tg = ― ‹global types›
  tg_mut :: mut
  tg_t :: t

datatype ― ‹function types›
  tf = Tf "t list" "t list" ("_ '_> _" 60)

(* TYPING *)
record t_context =
  types_t :: "tf list"
  func_t :: "tf list"
  global :: "tg list"
  table :: "nat option"
  memory :: "nat option"
  local :: "t list"
  label :: "(t list) list"
  return :: "(t list) option"

record s_context =
  s_inst :: "t_context list"
  s_funcs :: "tf list"
  s_tab  :: "nat list"
  s_mem  :: "nat list"
  s_globs :: "tg list"

datatype
  sx = S | U

datatype
  unop_i = Clz | Ctz | Popcnt

datatype
  unop_f = Neg | Abs | Ceil | Floor | Trunc | Nearest | Sqrt

datatype
  binop_i = Add | Sub | Mul | Div sx | Rem sx | And | Or | Xor | Shl | Shr sx | Rotl | Rotr

datatype
  binop_f = Addf | Subf | Mulf | Divf | Min | Max | Copysign
  
datatype
  testop = Eqz
  
datatype
  relop_i = Eq | Ne | Lt sx | Gt sx | Le sx | Ge sx
  
datatype
  relop_f = Eqf | Nef | Ltf | Gtf | Lef | Gef
  
datatype
  cvtop = Convert | Reinterpret

datatype ― ‹values›
  v =
    ConstInt32 i32
    | ConstInt64 i64
    | ConstFloat32 f32
    | ConstFloat64 f64

datatype ― ‹basic instructions›
  b_e =
    Unreachable
    | Nop
    | Drop
    | Select
    | Block tf "b_e list"
    | Loop tf "b_e list"
    | If tf "b_e list" "b_e list"
    | Br i
    | Br_if i
    | Br_table "i list" i
    | Return
    | Call i
    | Call_indirect i
    | Get_local i
    | Set_local i
    | Tee_local i
    | Get_global i
    | Set_global i
    | Load t "(tp × sx) option" a off
    | Store t "tp option" a off
    | Current_memory
    | Grow_memory
    | EConst v ("C _" 60)
    | Unop_i t unop_i
    | Unop_f t unop_f
    | Binop_i t binop_i
    | Binop_f t binop_f
    | Testop t testop
    | Relop_i t relop_i
    | Relop_f t relop_f
    | Cvtop t cvtop t "sx option"

datatype cl = ― ‹function closures›
  Func_native i tf "t list" "b_e list"
| Func_host tf host

record inst = ― ‹instances›
  types :: "tf list"
  funcs :: "i list"
  tab :: "i option"
  mem :: "i option"
  globs :: "i list"

type_synonym tabinst = "(cl option) list"

record global =
  g_mut :: mut
  g_val :: v

record s = ― ‹store›
  inst :: "inst list"
  funcs :: "cl list"
  tab :: "tabinst list"
  mem :: "mem list"
  globs :: "global list"

datatype e = ― ‹administrative instruction›
  Basic b_e ("$_" 60)
  | Trap
  | Callcl cl
  | Label nat "e list" "e list"
  | Local nat i "v list" "e list"

datatype Lholed =
    ― ‹L0 = v* [<hole>] e*›
    LBase "e list" "e list"
    ― ‹L(i+1) = v* (label n {e* } Li) e*›
  | LRec "e list" nat "e list" Lholed "e list"
end

Theory Wasm_Type_Abs

section ‹Syntactic Typeclasses›

theory Wasm_Type_Abs imports Main begin

class wasm_base = zero

class wasm_int = wasm_base +
  (* unops*)
  fixes int_clz :: "'a  'a"
  fixes int_ctz :: "'a  'a"
  fixes int_popcnt :: "'a  'a"
  (* binops *)
  fixes int_add :: "'a  'a  'a"
  fixes int_sub :: "'a  'a  'a"
  fixes int_mul :: "'a  'a  'a"
  fixes int_div_u :: "'a  'a  'a option"
  fixes int_div_s :: "'a  'a  'a option"
  fixes int_rem_u :: "'a  'a  'a option"
  fixes int_rem_s :: "'a  'a  'a option"
  fixes int_and :: "'a  'a  'a"
  fixes int_or :: "'a  'a  'a"
  fixes int_xor :: "'a  'a  'a"
  fixes int_shl :: "'a  'a  'a"
  fixes int_shr_u :: "'a  'a  'a"
  fixes int_shr_s :: "'a  'a  'a"
  fixes int_rotl :: "'a  'a  'a"
  fixes int_rotr :: "'a  'a  'a"
  (* testops *)
  fixes int_eqz :: "'a  bool"
  (* relops *)
  fixes int_eq :: "'a  'a  bool"
  fixes int_lt_u :: "'a  'a  bool"
  fixes int_lt_s :: "'a  'a  bool"
  fixes int_gt_u :: "'a  'a  bool"
  fixes int_gt_s :: "'a  'a  bool"
  fixes int_le_u :: "'a  'a  bool"
  fixes int_le_s :: "'a  'a  bool"
  fixes int_ge_u :: "'a  'a  bool"
  fixes int_ge_s :: "'a  'a  bool"
  (* value conversions *)
  fixes int_of_nat :: "nat  'a"
  fixes nat_of_int :: "'a  nat"
begin
  abbreviation (input)
  int_ne where
    "int_ne x y  ¬ (int_eq x y)"
end

class wasm_float = wasm_base +
  (* unops *)
  fixes float_neg     :: "'a  'a"
  fixes float_abs     :: "'a  'a"
  fixes float_ceil    :: "'a  'a"
  fixes float_floor   :: "'a  'a"
  fixes float_trunc   :: "'a  'a"
  fixes float_nearest :: "'a  'a"
  fixes float_sqrt    :: "'a  'a"
  (* binops *)
  fixes float_add :: "'a  'a  'a"
  fixes float_sub :: "'a  'a  'a"
  fixes float_mul :: "'a  'a  'a"
  fixes float_div :: "'a  'a  'a"
  fixes float_min :: "'a  'a  'a"
  fixes float_max :: "'a  'a  'a"
  fixes float_copysign :: "'a  'a  'a"
  (* relops *)
  fixes float_eq :: "'a  'a  bool"
  fixes float_lt :: "'a  'a  bool"
  fixes float_gt :: "'a  'a  bool"
  fixes float_le :: "'a  'a  bool"
  fixes float_ge :: "'a  'a  bool"
begin
  abbreviation (input)
  float_ne where
    "float_ne x y  ¬ (float_eq x y)"
end
end

Theory Wasm_Base_Defs

section ‹WebAssembly Base Definitions›

theory Wasm_Base_Defs imports Wasm_Ast Wasm_Type_Abs begin

instantiation i32 :: wasm_int begin instance .. end
instantiation i64 :: wasm_int begin instance .. end
instantiation f32 :: wasm_float begin instance .. end
instantiation f64 :: wasm_float begin instance .. end

consts
  (* inter-type conversions *)
  (* float to i32 *)
  ui32_trunc_f32 :: "f32  i32 option"
  si32_trunc_f32 :: "f32  i32 option"
  ui32_trunc_f64 :: "f64  i32 option"
  si32_trunc_f64 :: "f64  i32 option"
  (* float to i64 *)
  ui64_trunc_f32 :: "f32  i64 option"
  si64_trunc_f32 :: "f32  i64 option"
  ui64_trunc_f64 :: "f64  i64 option"
  si64_trunc_f64 :: "f64  i64 option"
  (* int to f32 *)
  f32_convert_ui32 :: "i32  f32"
  f32_convert_si32 :: "i32  f32"
  f32_convert_ui64 :: "i64  f32"
  f32_convert_si64 :: "i64  f32"
  (* int to f64 *)
  f64_convert_ui32 :: "i32  f64"
  f64_convert_si32 :: "i32  f64"
  f64_convert_ui64 :: "i64  f64"
  f64_convert_si64 :: "i64  f64"
  (* intra-{int/float} conversions *)
  wasm_wrap :: "i64  i32"
  wasm_extend_u :: "i32  i64"
  wasm_extend_s :: "i32  i64"
  wasm_demote :: "f64  f32"
  wasm_promote :: "f32  f64"
  (* boolean encoding *)
  serialise_i32 :: "i32  bytes"
  serialise_i64 :: "i64  bytes"
  serialise_f32 :: "f32  bytes"
  serialise_f64 :: "f64  bytes"
  wasm_bool :: "bool  i32"
  int32_minus_one :: i32

  (* memory *)
definition mem_size :: "mem  nat" where
  "mem_size m = length (Rep_mem m)"

definition mem_grow :: "mem  nat  mem" where
  "mem_grow m n = mem_append m (bytes_replicate (n * 64000) 0)"

definition load :: "mem  nat  off  nat  bytes option" where
  "load m n off l = (if (mem_size m  (n+off+l))
                       then Some (read_bytes m (n+off) l)
                       else None)"

definition sign_extend :: "sx  nat  bytes  bytes" where
  "sign_extend sx l bytes = (let msb = msb (msbyte bytes) in
                          let byte = (case sx of U  0 | S  if msb then -1 else 0) in
                          bytes_takefill byte l bytes)"

definition load_packed :: "sx  mem  nat  off  nat  nat  bytes option" where
  "load_packed sx m n off lp l = map_option (sign_extend sx l) (load m n off lp)"

definition store :: "mem  nat  off  bytes  nat  mem option" where
  "store m n off bs l = (if (mem_size m  (n+off+l))
                          then Some (write_bytes m (n+off) (bytes_takefill 0 l bs))
                          else None)"

definition store_packed :: "mem  nat  off  bytes  nat  mem option" where
  "store_packed = store"

consts
  wasm_deserialise :: "bytes  t  v"
  (* host *)
  host_apply :: "s  tf  host  v list  host_state  (s × v list) option"

definition typeof :: " v  t" where
  "typeof v = (case v of
                 ConstInt32 _  T_i32
               | ConstInt64 _  T_i64
               | ConstFloat32 _  T_f32
               | ConstFloat64 _  T_f64)"

definition option_projl :: "('a × 'b) option  'a option" where
  "option_projl x = map_option fst x"

definition option_projr :: "('a × 'b) option  'b option" where
  "option_projr x = map_option snd x"

definition t_length :: "t  nat" where
 "t_length t = (case t of
                  T_i32  4
                | T_i64  8
                | T_f32  4
                | T_f64  8)"

definition tp_length :: "tp  nat" where
 "tp_length tp = (case tp of
                 Tp_i8  1
               | Tp_i16  2
               | Tp_i32  4)"

definition is_int_t :: "t  bool" where
 "is_int_t t = (case t of
                  T_i32  True
                | T_i64  True
                | T_f32  False
                | T_f64  False)"

definition is_float_t :: "t  bool" where
 "is_float_t t = (case t of
                    T_i32  False
                  | T_i64  False
                  | T_f32  True
                  | T_f64  True)"

definition is_mut :: "tg  bool" where
  "is_mut tg = (tg_mut tg = T_mut)"

definition app_unop_i :: "unop_i  'i::wasm_int  'i::wasm_int" where
  "app_unop_i iop c =
     (case iop of
     Ctz  int_ctz c
   | Clz  int_clz c
   | Popcnt  int_popcnt c)"

definition app_unop_f :: "unop_f  'f::wasm_float  'f::wasm_float" where
  "app_unop_f fop c =
                 (case fop of
                    Neg  float_neg c
                  | Abs  float_abs c
                  | Ceil  float_ceil c
                  | Floor  float_floor c
                  | Trunc  float_trunc c
                  | Nearest  float_nearest c
                  | Sqrt  float_sqrt c)"

definition app_binop_i :: "binop_i  'i::wasm_int  'i::wasm_int  ('i::wasm_int) option" where
  "app_binop_i iop c1 c2 = (case iop of
                              Add  Some (int_add c1 c2)
                            | Sub  Some (int_sub c1 c2)
                            | Mul  Some (int_mul c1 c2)
                            | Div U  int_div_u c1 c2
                            | Div S  int_div_s c1 c2
                            | Rem U  int_rem_u c1 c2
                            | Rem S  int_rem_s c1 c2
                            | And  Some (int_and c1 c2)
                            | Or  Some (int_or c1 c2)
                            | Xor  Some (int_xor c1 c2)
                            | Shl  Some (int_shl c1 c2)
                            | Shr U  Some (int_shr_u c1 c2)
                            | Shr S  Some (int_shr_s c1 c2)
                            | Rotl  Some (int_rotl c1 c2)
                            | Rotr  Some (int_rotr c1 c2))"

definition app_binop_f :: "binop_f  'f::wasm_float  'f::wasm_float  ('f::wasm_float) option" where
  "app_binop_f fop c1 c2 = (case fop of
                              Addf  Some (float_add c1 c2)
                            | Subf  Some (float_sub c1 c2)
                            | Mulf  Some (float_mul c1 c2)
                            | Divf  Some (float_div c1 c2)
                            | Min  Some (float_min c1 c2)
                            | Max  Some (float_max c1 c2)
                            | Copysign  Some (float_copysign c1 c2))"

definition app_testop_i :: "testop  'i::wasm_int  bool" where
  "app_testop_i testop c = (case testop of Eqz  int_eqz c)"

definition app_relop_i :: "relop_i  'i::wasm_int  'i::wasm_int  bool" where
  "app_relop_i rop c1 c2 = (case rop of
                              Eq  int_eq c1 c2
                            | Ne  int_ne c1 c2
                            | Lt U  int_lt_u c1 c2
                            | Lt S  int_lt_s c1 c2
                            | Gt U  int_gt_u c1 c2
                            | Gt S  int_gt_s c1 c2
                            | Le U  int_le_u c1 c2
                            | Le S  int_le_s c1 c2
                            | Ge U  int_ge_u c1 c2
                            | Ge S  int_ge_s c1 c2)"

definition app_relop_f :: "relop_f  'f::wasm_float  'f::wasm_float  bool" where
  "app_relop_f rop c1 c2 = (case rop of
                              Eqf  float_eq c1 c2
                            | Nef  float_ne c1 c2
                            | Ltf  float_lt c1 c2
                            | Gtf  float_gt c1 c2
                            | Lef  float_le c1 c2
                            | Gef  float_ge c1 c2)" 

definition types_agree :: "t  v  bool" where
  "types_agree t v = (typeof v = t)"

definition cl_type :: "cl  tf" where
  "cl_type cl = (case cl of Func_native _ tf _ _  tf | Func_host tf _  tf)"

definition rglob_is_mut :: "global  bool" where
  "rglob_is_mut g = (g_mut g = T_mut)"

definition stypes :: "s  nat  nat  tf" where
  "stypes s i j = ((types ((inst s)!i))!j)"
  
definition sfunc_ind :: "s  nat  nat  nat" where
  "sfunc_ind s i j = ((inst.funcs ((inst s)!i))!j)"

definition sfunc :: "s  nat  nat  cl" where
  "sfunc s i j = (funcs s)!(sfunc_ind s i j)"

definition sglob_ind :: "s  nat  nat  nat" where
  "sglob_ind s i j = ((inst.globs ((inst s)!i))!j)"
  
definition sglob :: "s  nat  nat  global" where
  "sglob s i j = (globs s)!(sglob_ind s i j)"

definition sglob_val :: "s  nat  nat  v" where
  "sglob_val s i j = g_val (sglob s i j)"

definition smem_ind :: "s  nat  nat option" where
  "smem_ind s i = (inst.mem ((inst s)!i))"

definition stab_s :: "s  nat  nat  cl option" where
  "stab_s s i j = (let stabinst = ((tab s)!i) in  (if (length (stabinst) > j) then (stabinst!j) else None))"

definition stab :: "s  nat  nat  cl option" where
  "stab s i j = (case (inst.tab ((inst s)!i)) of Some k => stab_s s k j | None => None)"

definition supdate_glob_s :: "s  nat  v  s" where
  "supdate_glob_s s k v = sglobs := (globs s)[k:=((globs s)!k)g_val := v]"

definition supdate_glob :: "s  nat  nat  v  s" where
  "supdate_glob s i j v = (let k = sglob_ind s i j in supdate_glob_s s k v)"

definition is_const :: "e  bool" where
  "is_const e = (case e of Basic (C _)  True | _  False)"
    
definition const_list :: "e list  bool" where
  "const_list xs = list_all is_const xs"

inductive store_extension :: "s  s  bool" where
"insts = insts'; fs = fs'; tclss = tclss'; list_all2 (λbs bs'. mem_size bs  mem_size bs') bss bss'; gs = gs' 
  store_extension s.inst = insts, s.funcs = fs, s.tab = tclss, s.mem = bss, s.globs = gs
                    s.inst = insts', s.funcs = fs', s.tab = tclss', s.mem = bss', s.globs = gs'"

abbreviation to_e_list :: "b_e list  e list" ("$* _" 60) where
  "to_e_list b_es  map Basic b_es"

abbreviation v_to_e_list :: "v list  e list" ("$$* _" 60) where
  "v_to_e_list ves  map (λv. $C v) ves"

  (* Lfilled depth thing-to-fill fill-with result *)
inductive Lfilled :: "nat  Lholed  e list  e list  bool" where
  (* "Lfill (LBase vs es') es = vs @ es @ es'" *)
  L0:"const_list vs; lholed = (LBase vs es')  Lfilled 0 lholed es (vs @ es @ es')"
  (* "Lfill (LRec vs ts es' l es'') es = vs @ [Label ts es' (Lfill l es)] @ es''" *)
| LN:"const_list vs; lholed = (LRec vs n es' l es''); Lfilled k l es lfilledk  Lfilled (k+1) lholed es (vs @ [Label n es' lfilledk] @ es'')"

  (* Lfilled depth thing-to-fill fill-with result *)
inductive Lfilled_exact :: "nat  Lholed  e list  e list  bool" where
  (* "Lfill (LBase vs es') es = vs @ es @ es'" *)
  L0:"lholed = (LBase [] [])  Lfilled_exact 0 lholed es es"
  (* "Lfill (LRec vs ts es' l es'') es = vs @ [Label ts es' (Lfill l es)] @ es''" *)
| LN:"const_list vs; lholed = (LRec vs n es' l es''); Lfilled_exact k l es lfilledk  Lfilled_exact (k+1) lholed es (vs @ [Label n es' lfilledk] @ es'')"

definition load_store_t_bounds :: "a  tp option  t  bool" where
  "load_store_t_bounds a tp t = (case tp of
                                   None  2^a  t_length t
                                 | Some tp  2^a  tp_length tp  tp_length tp < t_length t   is_int_t t)"

definition cvt_i32 :: "sx option  v  i32 option" where
  "cvt_i32 sx v = (case v of
                   ConstInt32 c  None
                 | ConstInt64 c  Some (wasm_wrap c)
                 | ConstFloat32 c  (case sx of
                                        Some U  ui32_trunc_f32 c
                                      | Some S  si32_trunc_f32 c
                                      | None  None)
                 | ConstFloat64 c  (case sx of
                                        Some U  ui32_trunc_f64 c
                                      | Some S  si32_trunc_f64 c
                                      | None  None))"

definition cvt_i64 :: "sx option  v  i64 option" where
  "cvt_i64 sx v = (case v of
                   ConstInt32 c  (case sx of
                                        Some U  Some (wasm_extend_u c)
                                      | Some S  Some (wasm_extend_s c)
                                      | None  None)
                 | ConstInt64 c  None
                 | ConstFloat32 c  (case sx of
                                        Some U  ui64_trunc_f32 c
                                      | Some S  si64_trunc_f32 c
                                      | None  None)
                 | ConstFloat64 c  (case sx of
                                        Some U  ui64_trunc_f64 c
                                      | Some S  si64_trunc_f64 c
                                      | None  None))"

definition cvt_f32 :: "sx option  v  f32 option" where
  "cvt_f32 sx v = (case v of
                   ConstInt32 c  (case sx of
                                      Some U  Some (f32_convert_ui32 c)
                                    | Some S  Some (f32_convert_si32 c)
                                    | _  None)
                 | ConstInt64 c  (case sx of
                                      Some U  Some (f32_convert_ui64 c)
                                    | Some S  Some (f32_convert_si64 c)
                                    | _  None)
                 | ConstFloat32 c  None
                 | ConstFloat64 c  Some (wasm_demote c))"

definition cvt_f64 :: "sx option  v  f64 option" where
  "cvt_f64 sx v = (case v of
                   ConstInt32 c  (case sx of
                                      Some U  Some (f64_convert_ui32 c)
                                    | Some S  Some (f64_convert_si32 c)
                                    | _  None)
                 | ConstInt64 c  (case sx of
                                      Some U  Some (f64_convert_ui64 c)
                                    | Some S  Some (f64_convert_si64 c)
                                    | _  None)
                 | ConstFloat32 c  Some (wasm_promote c)
                 | ConstFloat64 c  None)"

definition cvt :: "t  sx option  v  v option" where
  "cvt t sx v = (case t of
                 T_i32  (case (cvt_i32 sx v) of Some c  Some (ConstInt32 c) | None  None)
               | T_i64  (case (cvt_i64 sx v) of Some c  Some (ConstInt64 c) | None  None) 
               | T_f32  (case (cvt_f32 sx v) of Some c  Some (ConstFloat32 c) | None  None)
               | T_f64  (case (cvt_f64 sx v) of Some c  Some (ConstFloat64 c) | None  None))"

definition bits :: "v  bytes" where
  "bits v = (case v of
               ConstInt32 c  (serialise_i32 c)
             | ConstInt64 c  (serialise_i64 c)
             | ConstFloat32 c  (serialise_f32 c)
             | ConstFloat64 c  (serialise_f64 c))"

definition bitzero :: "t  v" where
  "bitzero t = (case t of
                T_i32  ConstInt32 0
              | T_i64  ConstInt64 0
              | T_f32  ConstFloat32 0
              | T_f64  ConstFloat64 0)"

definition n_zeros :: "t list  v list" where
  "n_zeros ts = (map (λt. bitzero t) ts)"

lemma is_int_t_exists:
  assumes "is_int_t t"
  shows "t = T_i32  t = T_i64"
  using assms
  by (cases t) (auto simp add: is_int_t_def)

lemma is_float_t_exists:
  assumes "is_float_t t"
  shows "t = T_f32  t = T_f64"
  using assms
  by (cases t) (auto simp add: is_float_t_def)


lemma int_float_disjoint: "is_int_t t = -(is_float_t t)"
  by simp (metis is_float_t_def is_int_t_def t.exhaust t.simps(13-16))

lemma stab_unfold:
  assumes "stab s i j = Some cl"
  shows "k. inst.tab ((inst s)!i) = Some k  length ((tab s)!k) > j ((tab s)!k)!j = Some cl"
proof -
  obtain k where have_k:"(inst.tab ((inst s)!i)) = Some k"
    using assms
    unfolding stab_def
    by fastforce
  hence s_o:"stab s i j = stab_s s k j"
    using assms
    unfolding stab_def
    by simp
  then obtain stabinst where stabinst_def:"stabinst = ((tab s)!k)"
    by blast
  hence "stab_s s k j = (stabinst!j)  (length stabinst > j)"
    using assms s_o
    unfolding stab_s_def
    by (cases "(length stabinst > j)", auto)
  thus ?thesis
    using have_k stabinst_def assms s_o
    by auto
qed

lemma inj_basic: "inj Basic"
  by (meson e.inject(1) injI)

lemma inj_basic_econst: "inj (λv. $C v)"
  by (meson b_e.inject(16) e.inject(1) injI)

lemma to_e_list_1:"[$ a] = $* [a]"
  by simp

lemma to_e_list_2:"[$ a, $ b] = $* [a, b]"
  by simp

lemma to_e_list_3:"[$ a, $ b, $ c] = $* [a, b, c]"
  by simp

lemma v_exists_b_e:"ves. ($$*vs) = ($*ves)"
proof (induction vs)
  case (Cons a vs)
  thus ?case
  by (metis list.simps(9))
qed auto

lemma Lfilled_exact_imp_Lfilled:
  assumes "Lfilled_exact n lholed es LI"
  shows "Lfilled n lholed es LI"
  using assms
proof (induction rule: Lfilled_exact.induct)
  case (L0 lholed es)
  thus ?case
    using const_list_def Lfilled.intros(1)
    by fastforce
next
  case (LN vs lholed n es' l es'' k es lfilledk)
  thus ?case
    using Lfilled.intros(2)
    by fastforce
qed

lemma Lfilled_exact_app_imp_exists_Lfilled:
  assumes "const_list ves"
          "Lfilled_exact n lholed (ves@es) LI"
  shows "lholed'. Lfilled n lholed' es LI"
  using assms(2,1)
proof (induction "(ves@es)" LI rule: Lfilled_exact.induct)
  case (L0 lholed)
  show ?case
    using Lfilled.intros(1)[OF L0(2), of _ "[]"]
    by fastforce
next
  case (LN vs lholed n es' l es'' k lfilledk)
  thus ?case
    using Lfilled.intros(2)
    by fastforce
qed

lemma Lfilled_imp_exists_Lfilled_exact:
  assumes "Lfilled n lholed es LI"
  shows "lholed' ves es_c. const_list ves  Lfilled_exact n lholed' (ves@es@es_c) LI"
  using assms Lfilled_exact.intros
  by (induction rule: Lfilled.induct) fastforce+

lemma n_zeros_typeof:
  "n_zeros ts = vs  (ts = map typeof vs)"
proof (induction ts arbitrary: vs)
  case Nil
  thus ?case
    unfolding n_zeros_def
    by simp
next
  case (Cons t ts)
  obtain vs' where "n_zeros ts = vs'"
    using n_zeros_def
    by blast
  moreover
  have "typeof (bitzero t) = t"
    unfolding typeof_def bitzero_def
    by (cases t, simp_all)
  ultimately
  show ?case
    using Cons
    unfolding n_zeros_def
    by auto
qed

end

Theory Wasm

theory Wasm imports Wasm_Base_Defs begin

(* TYPING RELATION *)
inductive b_e_typing :: "[t_context, b_e list, tf]  bool" ("_  _ : _" 60) where
  ― ‹num ops›
  const:"𝒞  [C v]         : ([]    _> [(typeof v)])"
| unop_i:"is_int_t t    𝒞  [Unop_i t _]  : ([t]   _> [t])"
| unop_f:"is_float_t t  𝒞  [Unop_f t _]  : ([t]   _> [t])"
| binop_i:"is_int_t t    𝒞  [Binop_i t iop] : ([t,t] _> [t])"
| binop_f:"is_float_t t  𝒞  [Binop_f t _] : ([t,t] _> [t])"
| testop:"is_int_t t    𝒞  [Testop t _]  : ([t]   _> [T_i32])"
| relop_i:"is_int_t t    𝒞  [Relop_i t _] : ([t,t] _> [T_i32])"
| relop_f:"is_float_t t  𝒞  [Relop_f t _] : ([t,t] _> [T_i32])"
  ― ‹convert›
| convert:"(t1  t2); (sx = None) = ((is_float_t t1  is_float_t t2)  (is_int_t t1  is_int_t t2  (t_length t1 < t_length t2)))  𝒞  [Cvtop t1 Convert t2 sx] : ([t2] _> [t1])"
  ― ‹reinterpret›
| reinterpret:"(t1  t2); t_length t1 = t_length t2  𝒞  [Cvtop t1 Reinterpret t2 None] : ([t2] _> [t1])"
  ― ‹unreachable, nop, drop, select›
| unreachable:"𝒞  [Unreachable] : (ts _> ts')"
| nop:"𝒞  [Nop] : ([] _> [])"
| drop:"𝒞  [Drop] : ([t] _> [])"
| select:"𝒞  [Select] : ([t,t,T_i32] _> [t])"
  ― ‹block›
| block:"tf = (tn _> tm); 𝒞label := ([tm] @ (label 𝒞))  es : (tn _> tm)  𝒞  [Block tf es] : (tn _> tm)"
  ― ‹loop›
| loop:"tf = (tn _> tm); 𝒞label := ([tn] @ (label 𝒞))  es : (tn _> tm)  𝒞  [Loop tf es] : (tn _> tm)"
  ― ‹if then else›
| if_wasm:"tf = (tn _> tm); 𝒞label := ([tm] @ (label 𝒞))  es1 : (tn _> tm); 𝒞label := ([tm] @ (label 𝒞))  es2 : (tn _> tm)  𝒞  [If tf es1 es2] : (tn @ [T_i32] _> tm)"
  ― ‹br›
| br:"i < length(label 𝒞); (label 𝒞)!i = ts  𝒞  [Br i] : (t1s @ ts _> t2s)"
  ― ‹br_if›
| br_if:"i < length(label 𝒞); (label 𝒞)!i = ts  𝒞  [Br_if i] : (ts @ [T_i32] _> ts)"
  ― ‹br_table›
| br_table:"list_all (λi. i < length(label 𝒞)  (label 𝒞)!i = ts) (is@[i])  𝒞  [Br_table is i] : (t1s @ ts @ [T_i32] _> t2s)"
  ― ‹return›
| return:"(return 𝒞) = Some ts  𝒞  [Return] : (t1s @ ts _> t2s)"
  ― ‹call›
| call:"i < length(func_t 𝒞); (func_t 𝒞)!i = tf  𝒞  [Call i] : tf"
  ― ‹call_indirect›
| call_indirect:"i < length(types_t 𝒞); (types_t 𝒞)!i = (t1s _> t2s); (table 𝒞)  None  𝒞  [Call_indirect i] : (t1s @ [T_i32] _> t2s)"
  ― ‹get_local›
| get_local:"i < length(local 𝒞); (local 𝒞)!i = t  𝒞  [Get_local i] : ([] _> [t])"
  ― ‹set_local›
| set_local:"i < length(local 𝒞); (local 𝒞)!i = t  𝒞  [Set_local i] : ([t] _> [])"
  ― ‹tee_local›
| tee_local:"i < length(local 𝒞); (local 𝒞)!i = t  𝒞  [Tee_local i] : ([t] _> [t])"
  ― ‹get_global›
| get_global:"i < length(global 𝒞); tg_t ((global 𝒞)!i) = t  𝒞  [Get_global i] : ([] _> [t])"
  ― ‹set_global›
| set_global:"i < length(global 𝒞); tg_t ((global 𝒞)!i) = t; is_mut ((global 𝒞)!i)  𝒞  [Set_global i] : ([t] _> [])"
  ― ‹load›
| load:"(memory 𝒞) = Some n; load_store_t_bounds a (option_projl tp_sx) t  𝒞  [Load t tp_sx a off] : ([T_i32] _> [t])"
  ― ‹store›
| store:"(memory 𝒞) = Some n; load_store_t_bounds a tp t  𝒞  [Store t tp a off] : ([T_i32,t] _> [])"
  ― ‹current_memory›
| current_memory:"(memory 𝒞) = Some n  𝒞  [Current_memory] : ([] _> [T_i32])"
  ― ‹Grow_memory›
| grow_memory:"(memory 𝒞) = Some n  𝒞  [Grow_memory] : ([T_i32] _> [T_i32])"
  ― ‹empty program›
| empty:"𝒞  [] : ([] _> [])"
  ― ‹composition›
| composition:"𝒞  es : (t1s _> t2s); 𝒞  [e] : (t2s _> t3s)  𝒞  es @ [e] : (t1s _> t3s)"
  ― ‹weakening›
| weakening:"𝒞  es : (t1s _> t2s)  𝒞  es : (ts @ t1s _> ts @ t2s)"

inductive cl_typing :: "[s_context, cl, tf]  bool" where
   "i < length (s_inst 𝒮); ((s_inst 𝒮)!i) = 𝒞; tf = (t1s _> t2s); 𝒞local := (local 𝒞) @ t1s @ ts, label := ([t2s] @ (label 𝒞)), return := Some t2s  es : ([] _> t2s)  cl_typing 𝒮 (Func_native i tf ts es) (t1s _> t2s)"
|  "cl_typing 𝒮 (Func_host tf h) tf"

(* lifting the b_e_typing relation to the administrative operators *)
inductive e_typing :: "[s_context, t_context, e list, tf]  bool" ("__  _ : _" 60)
and       s_typing :: "[s_context, (t list) option, nat, v list, e list, t list]  bool" ("__ ⊩'_ _ _;_ : _" 60) where
(* section: e_typing *)
  (* lifting *)
  "𝒞  b_es : tf  𝒮𝒞  $*b_es : tf"
  (* composition *)
| "𝒮𝒞  es : (t1s _> t2s); 𝒮𝒞  [e] : (t2s _> t3s)  𝒮𝒞  es @ [e] : (t1s _> t3s)"
  (* weakening *)
| "𝒮𝒞  es : (t1s _> t2s) 𝒮𝒞  es : (ts @ t1s _> ts @ t2s)"
  (* trap *)
| "𝒮𝒞  [Trap] : tf"
  (* local *)
| "𝒮Some ts ⊩_i vs;es : ts; length ts = n  𝒮𝒞  [Local n i vs es] : ([] _> ts)"
  (* callcl *)
| "cl_typing 𝒮 cl tf  𝒮𝒞   [Callcl cl] : tf"
  (* label *)
| "𝒮𝒞  e0s : (ts _> t2s); 𝒮𝒞label := ([ts] @ (label 𝒞))  es : ([] _> t2s); length ts = n  𝒮𝒞  [Label n e0s es] : ([] _> t2s)"
(* section: s_typing *)
| "i < (length (s_inst 𝒮)); tvs = map typeof vs; 𝒞 =((s_inst 𝒮)!i)local := (local ((s_inst 𝒮)!i) @ tvs), return := rs; 𝒮𝒞  es : ([] _> ts); (rs = Some ts)  rs = None  𝒮rs ⊩_i vs;es : ts"

definition "globi_agree gs n g = (n < length gs  gs!n = g)"

definition "memi_agree sm j m = ((j' m'. j = Some j'  j' < length sm   m = Some m'  sm!j' = m')  j = None  m = None)"

definition "funci_agree fs n f = (n < length fs  fs!n = f)"

inductive inst_typing :: "[s_context, inst, t_context]  bool" where
  "list_all2 (funci_agree (s_funcs 𝒮)) fs tfs; list_all2 (globi_agree (s_globs 𝒮)) gs tgs; (i = Some i'  i' < length (s_tab 𝒮)  (s_tab 𝒮)!i' = (the n))  (i = None  n = None); memi_agree (s_mem 𝒮) j m  inst_typing 𝒮 types = ts, funcs = fs, tab = i, mem = j, globs = gs types_t = ts, func_t = tfs, global = tgs, table = n, memory = m, local = [], label = [], return = None"

definition "glob_agree g tg = (tg_mut tg = g_mut g  tg_t tg = typeof (g_val g))"

definition "tab_agree 𝒮 tcl = (case tcl of None  True | Some cl  tf. cl_typing 𝒮 cl tf)"

definition "mem_agree bs m = (λ bs m. m  mem_size bs) bs m"

inductive store_typing :: "[s, s_context]  bool" where
  "𝒮 = s_inst = 𝒞s, s_funcs = tfs, s_tab = ns, s_mem = ms, s_globs = tgs; list_all2 (inst_typing 𝒮) insts 𝒞s; list_all2 (cl_typing 𝒮) fs tfs; list_all (tab_agree 𝒮) (concat tclss); list_all2 (λ tcls n. n  length tcls) tclss ns; list_all2 mem_agree bss ms; list_all2 glob_agree gs tgs  store_typing s.inst = insts, s.funcs = fs, s.tab = tclss, s.mem = bss, s.globs = gs 𝒮"

inductive config_typing :: "[nat, s, v list, e list, t list]  bool" ("⊢'_ _ _;_;_ : _" 60) where
  "store_typing s 𝒮; 𝒮None ⊩_i vs;es : ts  ⊢_i s;vs;es : ts"

(* REDUCTION RELATION *)

inductive reduce_simple :: "[e list, e list]  bool" ("_  _" 60) where
  ― ‹integer unary ops›
  unop_i32:"[$C (ConstInt32 c), $(Unop_i T_i32 iop)]  [$C (ConstInt32 (app_unop_i iop c))]"
| unop_i64:"[$C (ConstInt64 c), $(Unop_i T_i64 iop)]  [$C (ConstInt64 (app_unop_i iop c))]"
  ― ‹float unary ops›
| unop_f32:"[$C (ConstFloat32 c), $(Unop_f T_f32 fop)]  [$C (ConstFloat32 (app_unop_f fop c))]"
| unop_f64:"[$C (ConstFloat64 c), $(Unop_f T_f64 fop)]  [$C (ConstFloat64 (app_unop_f fop c))]"
  ― ‹int32 binary ops›
| binop_i32_Some:"app_binop_i iop c1 c2 = (Some c)  [$C (ConstInt32 c1), $C (ConstInt32 c2), $(Binop_i T_i32 iop)]  [$C (ConstInt32 c)]"
| binop_i32_None:"app_binop_i iop c1 c2 = None  [$C (ConstInt32 c1), $C (ConstInt32 c2), $(Binop_i T_i32 iop)]  [Trap]"
  ― ‹int64 binary ops›
| binop_i64_Some:"app_binop_i iop c1 c2 = (Some c)  [$C (ConstInt64 c1), $C (ConstInt64 c2), $(Binop_i T_i64 iop)]  [$C (ConstInt64 c)]"
| binop_i64_None:"app_binop_i iop c1 c2 = None  [$C (ConstInt64 c1), $C (ConstInt64 c2), $(Binop_i T_i64 iop)]  [Trap]"
  ― ‹float32 binary ops›
| binop_f32_Some:"app_binop_f fop c1 c2 = (Some c)  [$C (ConstFloat32 c1), $C (ConstFloat32 c2), $(Binop_f T_f32 fop)]  [$C (ConstFloat32 c)]"
| binop_f32_None:"app_binop_f fop c1 c2 = None  [$C (ConstFloat32 c1), $C (ConstFloat32 c2), $(Binop_f T_f32 fop)]  [Trap]"
  ― ‹float64 binary ops›
| binop_f64_Some:"app_binop_f fop c1 c2 = (Some c)  [$C (ConstFloat64 c1), $C (ConstFloat64 c2), $(Binop_f T_f64 fop)]  [$C (ConstFloat64 c)]"
| binop_f64_None:"app_binop_f fop c1 c2 = None  [$C (ConstFloat64 c1), $C (ConstFloat64 c2), $(Binop_f T_f64 fop)]  [Trap]"
  ― ‹testops›
| testop_i32:"[$C (ConstInt32 c), $(Testop T_i32 testop)]  [$C ConstInt32 (wasm_bool (app_testop_i testop c))]"
| testop_i64:"[$C (ConstInt64 c), $(Testop T_i64 testop)]  [$C ConstInt32 (wasm_bool (app_testop_i testop c))]"
  ― ‹int relops›
| relop_i32:"[$C (ConstInt32 c1), $C (ConstInt32 c2), $(Relop_i T_i32 iop)]  [$C (ConstInt32 (wasm_bool (app_relop_i iop c1 c2)))]"
| relop_i64:"[$C (ConstInt64 c1), $C (ConstInt64 c2), $(Relop_i T_i64 iop)]  [$C (ConstInt32 (wasm_bool (app_relop_i iop c1 c2)))]"
  ― ‹float relops›
| relop_f32:"[$C (ConstFloat32 c1), $C (ConstFloat32 c2), $(Relop_f T_f32 fop)]  [$C (ConstInt32 (wasm_bool (app_relop_f fop c1 c2)))]"
| relop_f64:"[$C (ConstFloat64 c1), $C (ConstFloat64 c2), $(Relop_f T_f64 fop)]  [$C (ConstInt32 (wasm_bool (app_relop_f fop c1 c2)))]"
  ― ‹convert›
| convert_Some:"types_agree t1 v; cvt t2 sx v = (Some v')  [$(C v), $(Cvtop t2 Convert t1 sx)]  [$(C v')]"
| convert_None:"types_agree t1 v; cvt t2 sx v = None  [$(C v), $(Cvtop t2 Convert t1 sx)]  [Trap]"
  ― ‹reinterpret›
| reinterpret:"types_agree t1 v  [$(C v), $(Cvtop t2 Reinterpret t1 None)]  [$(C (wasm_deserialise (bits v) t2))]"
  ― ‹unreachable›
| unreachable:"[$ Unreachable]  [Trap]"
  ― ‹nop›
| nop:"[$ Nop]  []"
  ― ‹drop›
| drop:"[$(C v), ($ Drop)]  []"
  ― ‹select›
| select_false:"int_eq n 0  [$(C v1), $(C v2), $C (ConstInt32 n), ($ Select)]  [$(C v2)]"
| select_true:"int_ne n 0  [$(C v1), $(C v2), $C (ConstInt32 n), ($ Select)]  [$(C v1)]"
  ― ‹block›
| block:"const_list vs; length vs = n; length t1s = n; length t2s = m  vs @ [$(Block (t1s _> t2s) es)]  [Label m [] (vs @ ($* es))]"
  ― ‹loop›
| loop:"const_list vs; length vs = n; length t1s = n; length t2s = m  vs @ [$(Loop (t1s _> t2s) es)]  [Label n [$(Loop (t1s _> t2s) es)] (vs @ ($* es))]"
  ― ‹if›
| if_false:"int_eq n 0  [$C (ConstInt32 n), $(If tf e1s e2s)]  [$(Block tf e2s)]"
| if_true:"int_ne n 0  [$C (ConstInt32 n), $(If tf e1s e2s)]  [$(Block tf e1s)]"
  ― ‹label›
| label_const:"const_list vs  [Label n es vs]  vs"
| label_trap:"[Label n es [Trap]]  [Trap]"
  ― ‹br›
| br:"const_list vs; length vs = n; Lfilled i lholed (vs @ [$(Br i)]) LI  [Label n es LI]  vs @ es"
  ― ‹br_if›
| br_if_false:"int_eq n 0  [$C (ConstInt32 n), $(Br_if i)]  []"
| br_if_true:"int_ne n 0  [$C (ConstInt32 n), $(Br_if i)]  [$(Br i)]"
  ― ‹br_table›
| br_table:"length is > (nat_of_int c)  [$C (ConstInt32 c), $(Br_table is i)]  [$(Br (is!(nat_of_int c)))]"
| br_table_length:"length is  (nat_of_int c)  [$C (ConstInt32 c), $(Br_table is i)]  [$(Br i)]"
  ― ‹local›
| local_const:"const_list es; length es = n  [Local n i vs es]  es"
| local_trap:"[Local n i vs [Trap]]  [Trap]"
  ― ‹return›
| return:"const_list vs; length vs = n; Lfilled j lholed (vs @ [$Return]) es   [Local n i vls es]  vs"
  ― ‹tee_local›
| tee_local:"is_const v  [v, $(Tee_local i)]  [v, v, $(Set_local i)]"
| trap:"es  [Trap]; Lfilled 0 lholed [Trap] es  es  [Trap]"

(* full reduction rule *)
inductive reduce :: "[s, v list, e list, nat, s, v list, e list]  bool" ("_;_;_ ↝'_ _ _;_;_" 60) where
  ― ‹lifting basic reduction›
  basic:"e  e'  s;vs;e ↝_i s;vs;e'"
  ― ‹call›
| call:"s;vs;[$(Call j)] ↝_i s;vs;[Callcl (sfunc s i j)]"
  ― ‹call_indirect›
| call_indirect_Some:"stab s i (nat_of_int c) = Some cl; stypes s i j = tf; cl_type cl = tf  s;vs;[$C (ConstInt32 c), $(Call_indirect j)] ↝_i s;vs;[Callcl cl]"
| call_indirect_None:"(stab s i (nat_of_int c) = Some cl  stypes s i j  cl_type cl)  stab s i (nat_of_int c) = None  s;vs;[$C (ConstInt32 c), $(Call_indirect j)] ↝_i s;vs;[Trap]"
  ― ‹call›
| callcl_native:"cl = Func_native j (t1s _> t2s) ts es; ves = ($$* vcs); length vcs = n; length ts = k; length t1s = n; length t2s = m; (n_zeros ts = zs)   s;vs;ves @ [Callcl cl] ↝_i s;vs;[Local m j (vcs@zs) [$(Block ([] _> t2s) es)]]"
| callcl_host_Some:"cl = Func_host (t1s _> t2s) f; ves = ($$* vcs); length vcs = n; length t1s = n; length t2s = m; host_apply s (t1s _> t2s) f vcs hs = Some (s', vcs')  s;vs;ves @ [Callcl cl] ↝_i s';vs;($$* vcs')"
| callcl_host_None:"cl = Func_host (t1s _> t2s) f; ves = ($$* vcs); length vcs = n; length t1s = n; length t2s = m  s;vs;ves @ [Callcl cl] ↝_i s;vs;[Trap]"
  ― ‹get_local›
| get_local:"length vi = j  s;(vi @ [v] @ vs);[$(Get_local j)] ↝_i s;(vi @ [v] @ vs);[$(C v)]"
  ― ‹set_local›
| set_local:"length vi = j  s;(vi @ [v] @ vs);[$(C v'), $(Set_local j)] ↝_i s;(vi @ [v'] @ vs);[]"
  ― ‹get_global›
| get_global:"s;vs;[$(Get_global j)] ↝_i s;vs;[$ C(sglob_val s i j)]"
  ― ‹set_global›
| set_global:"supdate_glob s i j v = s'  s;vs;[$(C v), $(Set_global j)] ↝_i s';vs;[]"
  ― ‹load›
| load_Some:"smem_ind s i = Some j; ((mem s)!j) = m; load m (nat_of_int k) off (t_length t) = Some bs  s;vs;[$C (ConstInt32 k), $(Load t None a off)] ↝_i s;vs;[$C (wasm_deserialise bs t)]"
| load_None:"smem_ind s i = Some j; ((mem s)!j) = m; load m (nat_of_int k) off (t_length t) = None  s;vs;[$C (ConstInt32 k), $(Load t None a off)] ↝_i s;vs;[Trap]"
  ― ‹load packed›
| load_packed_Some:"smem_ind s i = Some j; ((mem s)!j) = m; load_packed sx m (nat_of_int k) off (tp_length tp) (t_length t) = Some bs  s;vs;[$C (ConstInt32 k), $(Load t (Some (tp, sx)) a off)] ↝_i s;vs;[$C (wasm_deserialise bs t)]"
| load_packed_None:"smem_ind s i = Some j; ((mem s)!j) = m; load_packed sx m (nat_of_int k) off (tp_length tp) (t_length t) = None  s;vs;[$C (ConstInt32 k), $(Load t (Some (tp, sx)) a off)] ↝_i s;vs;[Trap]"
  ― ‹store›
| store_Some:"types_agree t v; smem_ind s i = Some j; ((mem s)!j) = m; store m (nat_of_int k) off (bits v) (t_length t) = Some mem'  s;vs;[$C (ConstInt32 k), $C v, $(Store t None a off)] ↝_i smem:= ((mem s)[j := mem']);vs;[]"
| store_None:"types_agree t v; smem_ind s i = Some j; ((mem s)!j) = m; store m (nat_of_int k) off (bits v) (t_length t) = None  s;vs;[$C (ConstInt32 k), $C v, $(Store t None a off)] ↝_i s;vs;[Trap]"
  ― ‹store packed› (* take only (tp_length tp) lower order bytes *)
| store_packed_Some:"types_agree t v; smem_ind s i = Some j; ((mem s)!j) = m; store_packed m (nat_of_int k) off (bits v) (tp_length tp) = Some mem'  s;vs;[$C (ConstInt32 k), $C v, $(Store t (Some tp) a off)] ↝_i smem:= ((mem s)[j := mem']);vs;[]"
| store_packed_None:"types_agree t v; smem_ind s i = Some j; ((mem s)!j) = m; store_packed m (nat_of_int k) off (bits v) (tp_length tp) = None  s;vs;[$C (ConstInt32 k), $C v, $(Store t (Some tp) a off)] ↝_i s;vs;[Trap]"
  ― ‹current_memory›
| current_memory:"smem_ind s i = Some j; ((mem s)!j) = m; mem_size m = n  s;vs;[ $(Current_memory)] ↝_i s;vs;[$C (ConstInt32 (int_of_nat n))]"
  ― ‹grow_memory›
| grow_memory:"smem_ind s i = Some j; ((mem s)!j) = m; mem_size m = n; mem_grow m (nat_of_int c) = mem'  s;vs;[$C (ConstInt32 c), $(Grow_memory)] ↝_i smem:= ((mem s)[j := mem']);vs;[$C (ConstInt32 (int_of_nat n))]"
  ― ‹grow_memory fail›
| grow_memory_fail:"smem_ind s i = Some j; ((mem s)!j) = m; mem_size m = n  s;vs;[$C (ConstInt32 c),$(Grow_memory)] ↝_i s;vs;[$C (ConstInt32 int32_minus_one)]"
  (* The bad ones. *)
  ― ‹inductive label reduction›
| label:"s;vs;es ↝_i s';vs';es'; Lfilled k lholed es les; Lfilled k lholed es' les'  s;vs;les ↝_i s';vs';les'"
  ― ‹inductive local reduction›
| local:"s;vs;es ↝_i s';vs';es'  s;v0s;[Local n i vs es] ↝_j s';v0s;[Local n i vs' es']"

end

Theory Wasm_Axioms

section ‹Host Properties›

theory Wasm_Axioms imports Wasm begin

(* these were originally axioms, but memory now has a concrete representation in the model *)
lemma mem_grow_size:
  assumes "mem_grow m n = m'"
  shows "(mem_size m + (64000 * n)) = mem_size m'"
  using assms Abs_mem_inverse Abs_bytes_inverse
  unfolding mem_grow_def mem_size_def mem_append_def bytes_replicate_def
  by auto

lemma load_size:
  "(load m n off l = None) = (mem_size m < (off + n + l))"
  unfolding load_def
  by (cases "n + off + l  mem_size m") auto

lemma load_packed_size:
  "(load_packed sx m n off lp l = None) = (mem_size m < (off + n + lp))"
  using load_size
  unfolding load_packed_def
  by (cases "n + off + l  mem_size m") auto  

lemma store_size1:
  "(store m n off v l = None) = (mem_size m < (off + n + l))"
  unfolding store_def
  by (cases "n + off + l  mem_size m") auto

lemma store_size:
  assumes "(store m n off v l = Some m')"
  shows "mem_size m = mem_size m'"
  using assms Abs_mem_inverse Abs_bytes_inverse
  unfolding store_def write_bytes_def bytes_takefill_def
  by (cases "n + off + l  mem_size m") (auto simp add: mem_size_def)

lemma store_packed_size1:
  "(store_packed m n off v l = None) = (mem_size m < (off + n + l))"
  using store_size1
  unfolding store_packed_def
  by simp

lemma store_packed_size:
  assumes "(store_packed m n off v l = Some m')"
  shows "mem_size m = mem_size m'"
  using assms store_size
  unfolding store_packed_def
  by simp

axiomatization where
  wasm_deserialise_type:"typeof (wasm_deserialise bs t) = t"

axiomatization where
    host_apply_preserve_store:" list_all2 types_agree t1s vs  host_apply s (t1s _> t2s) f vs hs = Some (s', vs')  store_extension s s'"
and host_apply_respect_type:"list_all2 types_agree t1s vs  host_apply s (t1s _> t2s) f vs hs = Some (s', vs')  list_all2 types_agree t2s vs'"
end

Theory Wasm_Properties_Aux

section ‹Auxiliary Type System Properties›

theory Wasm_Properties_Aux imports Wasm_Axioms begin

lemma typeof_i32:
  assumes "typeof v = T_i32"
  shows "c. v = ConstInt32 c"
  using assms
  unfolding typeof_def
  by (cases v) auto

lemma typeof_i64:
  assumes "typeof v = T_i64"
  shows "c. v = ConstInt64 c"
  using assms
  unfolding typeof_def
  by (cases v) auto

lemma typeof_f32:
  assumes "typeof v = T_f32"
  shows "c. v = ConstFloat32 c"
  using assms
  unfolding typeof_def
  by (cases v) auto

lemma typeof_f64:
  assumes "typeof v = T_f64"
  shows "c. v = ConstFloat64 c"
  using assms
  unfolding typeof_def
  by (cases v) auto

lemma exists_v_typeof: "v v. typeof v = t"
proof (cases t)
  case T_i32
  fix v
  have "typeof (ConstInt32 v) = t"
    using T_i32
    unfolding typeof_def
    by simp
  thus ?thesis
    using T_i32
    by fastforce
next
  case T_i64
  fix v
  have "typeof (ConstInt64 v) = t"
    using T_i64
    unfolding typeof_def
    by simp
  thus ?thesis
    using T_i64
    by fastforce
next
  case T_f32
  fix v
  have "typeof (ConstFloat32 v) = t"
    using T_f32
    unfolding typeof_def
    by simp
  thus ?thesis
    using T_f32
    by fastforce
next
  case T_f64
  fix v
  have "typeof (ConstFloat64 v) = t"
    using T_f64
    unfolding typeof_def
    by simp
  thus ?thesis
    using T_f64
    by fastforce
qed

lemma lfilled_collapse1:
  assumes "Lfilled n lholed (vs@es) LI"
          "const_list vs"
          "length vs  l"
  shows "lholed'. Lfilled n lholed' ((drop (length vs - l) vs)@es) LI"
  using assms(1)
proof (induction "vs@es" LI rule: Lfilled.induct)
  case (L0 vs' lholed es')
  obtain vs1 vs2 where "vs = vs1@vs2" "length vs2 = l"
    using assms(3)
    by (metis append_take_drop_id diff_diff_cancel length_drop)
  moreover
  hence "const_list (vs'@vs1)"
    using L0(1) assms(2)
    unfolding const_list_def
    by simp
  ultimately
  show ?case
    using Lfilled.intros(1)[of "vs'@vs1" _ es' "vs2@es"]
      by fastforce
next
  case (LN vs lholed n es' l es'' k lfilledk)
  thus ?case
    using Lfilled.intros(2)
    by fastforce
qed

lemma lfilled_collapse2:
  assumes "Lfilled n lholed (es@es') LI"
  shows "lholed' vs'. Lfilled n lholed' es LI"
  using assms
proof (induction "es@es'" LI rule: Lfilled.induct)
  case (L0 vs lholed es')
  thus ?case
    using Lfilled.intros(1)
    by fastforce
next
  case (LN vs lholed n es' l es'' k lfilledk)
  thus ?case
    using Lfilled.intros(2)
    by fastforce
qed

lemma lfilled_collapse3:
  assumes "Lfilled k lholed [Label n les es] LI"
  shows "lholed'. Lfilled (Suc k) lholed' es LI"
  using assms
proof (induction "[Label n les es]" LI rule: Lfilled.induct)
  case (L0 vs lholed es')
  have "Lfilled 0 (LBase [] []) es es"
    using Lfilled.intros(1)
    unfolding const_list_def
    by (metis append.left_neutral append_Nil2 list_all_simps(2))
  thus ?case
    using Lfilled.intros(2) L0
    by fastforce
next
  case (LN vs lholed n es' l es'' k lfilledk)
  thus ?case
    using Lfilled.intros(2)
    by fastforce
qed


lemma unlift_b_e: assumes "𝒮𝒞  $*b_es : tf" shows "𝒞  b_es : tf"
using assms proof (induction "𝒮" "𝒞" "($*b_es)" "tf" arbitrary: b_es)
  case (1 𝒞 b_es tf 𝒮)
  then show ?case
    using inj_basic map_injective
    by auto
next
  case (2 𝒮 𝒞 es t1s t2s e t3s)
  obtain es' e' where "es' @ [e'] = b_es"
    using 2(5)
    by (simp add: snoc_eq_iff_butlast)
  then show ?case using 2
    using b_e_typing.composition
    by fastforce
next                            
  case (3 𝒮 𝒞 t1s t2s ts)
  then show ?case
    using b_e_typing.weakening
    by blast
qed auto

lemma store_typing_imp_inst_length_eq:
  assumes "store_typing s 𝒮"
  shows "length (inst s) = length (s_inst 𝒮)"
  using assms list_all2_lengthD
  unfolding store_typing.simps
  by fastforce

lemma store_typing_imp_func_length_eq:
  assumes "store_typing s 𝒮"
  shows "length (funcs s) = length (s_funcs 𝒮)"
  using assms list_all2_lengthD
  unfolding store_typing.simps
  by fastforce

lemma store_typing_imp_mem_length_eq:
  assumes "store_typing s 𝒮"
  shows "length (s.mem s) = length (s_mem 𝒮)"
  using assms list_all2_lengthD
  unfolding store_typing.simps
  by fastforce

lemma store_typing_imp_glob_length_eq:
  assumes "store_typing s 𝒮"
  shows "length (globs s) = length (s_globs 𝒮)"
  using assms list_all2_lengthD
  unfolding store_typing.simps
  by fastforce

lemma store_typing_imp_inst_typing:
  assumes "store_typing s 𝒮"
          "i < length (inst s)"
  shows "inst_typing 𝒮 ((inst s)!i) ((s_inst 𝒮)!i)"
  using assms
  unfolding list_all2_conv_all_nth store_typing.simps
  by fastforce

lemma stab_typed_some_imp_member:
  assumes "stab s i c = Some cl"
          "store_typing s 𝒮"
          "i < length (inst s)"
  shows "Some cl  set (concat (s.tab s))"
proof -
  obtain k' where k_def:"inst.tab ((inst s)!i) = Some k'"
                       "length ((s.tab s)!k') > c"
                       "((s.tab s)!k')!c = Some cl"
    using stab_unfold assms(1,3)
    by fastforce
  hence "Some cl  set ((s.tab s)!k')"
    using nth_mem
    by fastforce
  moreover
  have "inst_typing 𝒮 ((inst s)!i) ((s_inst 𝒮)!i)"
    using assms(2,3) store_typing_imp_inst_typing
    by blast
  hence "k' < length (s_tab 𝒮)"
    using k_def(1)
    unfolding inst_typing.simps stypes_def
    by auto
  hence "k' < length (s.tab s)"
    using assms(2) list_all2_lengthD
    unfolding store_typing.simps
    by fastforce
  ultimately
  show ?thesis
    using k_def
    by auto
qed

lemma stab_typed_some_imp_cl_typed:
  assumes "stab s i c = Some cl"
          "store_typing s 𝒮"
          "i < length (inst s)"
  shows "tf. cl_typing 𝒮 cl tf"
proof -
  have "Some cl  set (concat (s.tab s))"
    using assms stab_typed_some_imp_member
    by auto
  moreover
  have "list_all (tab_agree 𝒮) (concat (s.tab s))"
    using assms(2)
    unfolding store_typing.simps
    by auto
  ultimately
  show ?thesis
    unfolding in_set_conv_nth list_all_length tab_agree_def
    by fastforce
qed

lemma b_e_type_empty1[dest]: assumes "𝒞  [] : (ts _> ts')" shows "ts = ts'"
  using assms
  by (induction "[]::(b_e list)" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, simp_all)

lemma b_e_type_empty: "(𝒞  [] : (ts _> ts')) = (ts = ts')"
proof (safe)
  assume "𝒞  [] : (ts _> ts')"
  thus "ts = ts'"
    by blast
next
  assume "ts = ts'"
  thus "𝒞  [] : (ts' _> ts')"
    using b_e_typing.empty b_e_typing.weakening
    by fastforce
qed

lemma b_e_type_value:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = C v"
  shows "ts' = ts @ [typeof v]"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_load:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Load t tp_sx a off"
  shows "ts'' sec n. ts = ts''@[T_i32]  ts' = ts''@[t]  (memory 𝒞) = Some n"
        "load_store_t_bounds a (option_projl tp_sx) t"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_store:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Store t tp a off"
    shows "ts = ts'@[T_i32, t]"
          "sec n. (memory 𝒞) = Some n"
          "load_store_t_bounds a tp t"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_current_memory:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Current_memory"
  shows "sec n. ts' = ts @ [T_i32]  (memory 𝒞) = Some n"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_grow_memory:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Grow_memory"
  shows "ts''. ts = ts''@[T_i32]  ts = ts'  (n. (memory 𝒞) = Some n)"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct) auto

lemma b_e_type_nop:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Nop"
  shows "ts = ts'"
  using assms
  by (induction "[e]"  "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

definition arity_2_result :: "b_e  t" where
  "arity_2_result op2 = (case op2 of
                           Binop_i t _  t
                         | Binop_f t _  t
                         | Relop_i t _  T_i32
                         | Relop_f t _  T_i32)"

lemma b_e_type_binop_relop:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Binop_i t iop  e = Binop_f t fop  e = Relop_i t irop  e = Relop_f t frop"
  shows "ts''. ts = ts''@[t,t]  ts' = ts''@[arity_2_result(e)]"
        "e = Binop_f t fop  is_float_t t"
        "e = Relop_f t frop  is_float_t t"
  using assms
  unfolding arity_2_result_def
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_testop_drop_cvt0:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Testop t testop  e = Drop  e = Cvtop t1 cvtop t2 sx"
  shows "ts  []"
  using assms
  by (induction "[e]" "ts _> ts'" arbitrary: ts' rule: b_e_typing.induct, auto)

definition arity_1_result :: "b_e  t" where
  "arity_1_result op1 = (case op1 of
                           Unop_i t _  t
                         | Unop_f t _  t
                         | Testop t _  T_i32
                         | Cvtop t1 Convert _ _  t1
                         | Cvtop t1 Reinterpret _ _  t1)"

lemma b_e_type_unop_testop:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Unop_i t iop  e = Unop_f t fop  e = Testop t testop"
  shows "ts''. ts = ts''@[t]  ts' = ts''@[arity_1_result e]"
        "e = Unop_f t fop  is_float_t t"
  using assms int_float_disjoint
  unfolding arity_1_result_def
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct) fastforce+

lemma b_e_type_cvtop:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Cvtop t1 cvtop t sx"
  shows "ts''. ts = ts''@[t]  ts' = ts''@[arity_1_result e]"
        "cvtop = Convert  (t1  t)  (sx = None) = ((is_float_t t1  is_float_t t)  (is_int_t t1  is_int_t t  (t_length t1 < t_length t)))"
        "cvtop = Reinterpret  (t1  t)  t_length t1 = t_length t"
  using assms
  unfolding arity_1_result_def
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_drop:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Drop"
  shows "t. ts = ts'@[t]"
  using assms b_e_type_testop_drop_cvt0
by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_select:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Select"
  shows "ts'' t. ts = ts''@[t,t,T_i32]  ts' = ts''@[t]"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_call:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Call i"
  shows  "i < length (func_t 𝒞)"
         "ts'' tf1 tf2. ts = ts''@tf1  ts' = ts''@tf2  (func_t 𝒞)!i = (tf1 _> tf2)"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_call_indirect:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Call_indirect i"
  shows "i < length (types_t 𝒞)"
        "ts'' tf1 tf2. ts = ts''@tf1@[T_i32]  ts' = ts''@tf2  (types_t 𝒞)!i = (tf1 _> tf2)"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_get_local:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Get_local i"
  shows "t. ts' = ts@[t]  (local 𝒞)!i = t" "i < length(local 𝒞)"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_set_local:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Set_local i"
  shows "t. ts = ts'@[t]  (local 𝒞)!i = t" "i < length(local 𝒞)"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_tee_local:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Tee_local i"
  shows "ts'' t. ts = ts''@[t]  ts' = ts''@[t]  (local 𝒞)!i = t" "i < length(local 𝒞)"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_get_global:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Get_global i"
  shows "t. ts' = ts@[t]  tg_t((global 𝒞)!i) = t" "i < length(global 𝒞)"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_set_global:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Set_global i"
  shows "t. ts = ts'@[t]  (global 𝒞)!i = tg_mut = T_mut, tg_t = t  i < length(global 𝒞)"
  using assms is_mut_def
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct) auto

lemma b_e_type_block:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Block tf es"
  shows "ts'' tfn tfm. tf = (tfn _> tfm)  (ts = ts''@tfn)  (ts' = ts''@tfm) 
                        (𝒞label :=  [tfm] @ label 𝒞  es : tf)"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_loop:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Loop tf es"
  shows "ts'' tfn tfm. tf = (tfn _> tfm)  (ts = ts''@tfn)  (ts' = ts''@tfm) 
                        (𝒞label :=  [tfn] @ label 𝒞  es : tf)"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_if:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = If tf es1 es2"
  shows "ts'' tfn tfm. tf = (tfn _> tfm)  (ts = ts''@tfn @ [T_i32])  (ts' = ts''@tfm) 
                        (𝒞label := [tfm] @ label 𝒞  es1 : tf) 
                        (𝒞label := [tfm] @ label 𝒞  es2 : tf)"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_br:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Br i"
        shows "i < length(label 𝒞)"
              "ts_c ts''. ts = ts_c @ ts''  (label 𝒞)!i = ts''"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_br_if:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Br_if i"
        shows "i < length(label 𝒞)"
              "ts_c ts''. ts = ts_c @ ts'' @ [T_i32]  ts' = ts_c @ ts''  (label 𝒞)!i = ts''"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_br_table:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Br_table is i"
  shows "ts_c ts''. list_all (λi. i < length(label 𝒞)  (label 𝒞)!i = ts'') (is@[i])  ts = ts_c @ ts''@[T_i32]"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, fastforce+)

lemma b_e_type_return:
  assumes "𝒞  [e] : (ts _> ts')"
          "e = Return"
        shows "ts_c ts''. ts = ts_c @ ts''  (return 𝒞) = Some ts''"
  using assms
  by (induction "[e]" "(ts _> ts')" arbitrary: ts ts' rule: b_e_typing.induct, auto)

lemma b_e_type_comp:
  assumes "𝒞  es@[e] : (t1s _> t4s)"
  shows "ts'. (𝒞  es : (t1s _> ts'))  (𝒞  [e] : (ts' _> t4s))"
proof (cases es rule: List.rev_cases)
  case Nil
  then show ?thesis
    using assms b_e_typing.empty b_e_typing.weakening
    by fastforce
next
  case (snoc es' e')
  show ?thesis using assms snoc b_e_typing.weakening
    by (induction "es@[e]" "(t1s _> t4s)" arbitrary: t1s t4s, fastforce+)
qed

(* Two special cases - useful for inductions over reduce. *)
lemma b_e_type_comp2_unlift:
  assumes "𝒮𝒞  [$e1, $e2] : (t1s _> t2s)"
  shows "ts'. (𝒞  [e1] : (t1s _> ts'))  (𝒞  [e2] : (ts' _> t2s))"
  using assms
        unlift_b_e[of 𝒮 𝒞 "([e1, e2])" "(t1s _> t2s)"]
        b_e_type_comp[of 𝒞 "[e1]" e2 t1s t2s]
  by simp

lemma b_e_type_comp2_relift:
  assumes "𝒞  [e1] : (t1s _> ts')" "𝒞  [e2] : (ts' _> t2s)"
  shows "𝒮𝒞  [$e1, $e2] : (ts@t1s _> ts@t2s)"
  using assms
        b_e_typing.composition[OF assms]
        e_typing_s_typing.intros(1)[of 𝒞 "[e1, e2]" "(t1s _> t2s)"]
        e_typing_s_typing.intros(3)[of 𝒮 𝒞 "([$e1,$e2])" t1s t2s ts]
  by simp

lemma b_e_type_value2:
  assumes "𝒞  [C v1, C v2] : (t1s _> t2s)"
  shows "t2s = t1s @ [typeof v1, typeof v2]"
proof -
  obtain ts' where ts'_def:"𝒞  [C v1] : (t1s _> ts')"
                           "𝒞  [C v2] : (ts' _> t2s)"
    using b_e_type_comp assms
    by (metis append_butlast_last_id butlast.simps(2) last_ConsL last_ConsR list.distinct(1))
  have "ts' = t1s @ [typeof v1]"
    using b_e_type_value ts'_def(1)
    by fastforce
  thus ?thesis
    using b_e_type_value ts'_def(2)
    by fastforce
qed

(* Lifting the previous results to all expressions. *)
lemma e_type_comp:
  assumes "𝒮𝒞  es@[e] : (t1s _> t3s)"
  shows "ts'. (𝒮𝒞  es : (t1s _> ts'))  (𝒮𝒞  [e] : (ts' _> t3s))"
proof (cases es rule: List.rev_cases)
  case Nil
  thus ?thesis
    using assms e_typing_s_typing.intros(1)
    by (metis append_Nil b_e_type_empty list.simps(8))
next
  case (snoc es' e')
  show ?thesis using assms snoc
  proof (induction "es@[e]" "(t1s _> t3s)" arbitrary: t1s t3s)
    case (1 𝒞 b_es 𝒮)
    obtain es'' e'' where b_e_defs:"($* (es'' @ [e''])) = ($* b_es)"
      using 1(1,2)
      by (metis Nil_is_map_conv append_is_Nil_conv not_Cons_self2 rev_exhaust)
    hence "($*es'') = es" "($e'') = e"
      using 1(2) inj_basic map_injective
      by auto
    moreover
    have "𝒞  (es'' @ [e'']) : (t1s _> t3s)" using 1(1)
      using inj_basic map_injective b_e_defs
      by blast
    then obtain t2s where "𝒞  es'' : (t1s _> t2s)" "𝒞  [e''] : (t2s _> t3s)"
      using b_e_type_comp
      by blast
    ultimately
    show ?case
      using e_typing_s_typing.intros(1)
      by fastforce
  next
    case (3 𝒮 𝒞 t1s t2s ts)
    thus ?case
      using e_typing_s_typing.intros(3)
      by fastforce
  qed auto
qed

lemma e_type_comp_conc:
  assumes "𝒮𝒞  es : (t1s _> t2s)"
          "𝒮𝒞  es' : (t2s _> t3s)"
  shows "𝒮𝒞  es@es' : (t1s _> t3s)"
  using assms(2)
proof (induction es' arbitrary: t3s rule: List.rev_induct)
  case Nil
  hence "t2s = t3s"
    using unlift_b_e[of _ _ "[]"] b_e_type_empty[of _ t2s t3s]
    by fastforce
  then show ?case
    using Nil assms(1) e_typing_s_typing.intros(2)
    by fastforce
next
  case (snoc x xs)
  then obtain ts' where "𝒮𝒞  xs : (t2s _> ts')" "𝒮𝒞  [x] : (ts' _> t3s)"
    using e_type_comp[of _ _ xs x]
    by fastforce
  then show ?case
    using snoc(1)[of ts'] e_typing_s_typing.intros(2)[of _ _ "es @ xs" t1s ts' x t3s]
    by simp
qed

(* This isn't needed here, but we unlift for convenience. *)
lemma b_e_type_comp_conc:
  assumes "𝒞  es : (t1s _> t2s)"
          "𝒞  es' : (t2s _> t3s)"
  shows "𝒞  es@es' : (t1s _> t3s)"
proof -
  fix 𝒮
  have 1:"𝒮𝒞  $*es : (t1s _> t2s)"
    using e_typing_s_typing.intros(1)[OF assms(1)]
    by fastforce
  have 2:"𝒮𝒞  $*es' : (t2s _> t3s)"
    using e_typing_s_typing.intros(1)[OF assms(2)]
    by fastforce
  show ?thesis
    using e_type_comp_conc[OF 1 2]
    by (simp add:  unlift_b_e)
qed

lemma e_type_comp_conc1:
  assumes "𝒮𝒞  es@es' : (ts _> ts')"
  shows "ts''. (𝒮𝒞  es : (ts _> ts''))  (𝒮𝒞  es' : (ts'' _> ts'))"
  using assms
proof (induction es' arbitrary: ts ts' rule: List.rev_induct)
  case Nil
  thus ?case
    using b_e_type_empty[of _ ts' ts'] e_typing_s_typing.intros(1)
    by fastforce
next
  case (snoc x xs)
  then show ?case
    using e_type_comp[of 𝒮 𝒞 "es @ xs" x ts ts'] e_typing_s_typing.intros(2)[of 𝒮 𝒞 xs _ _ x ts']
    by fastforce
qed

lemma e_type_comp_conc2:
  assumes "𝒮𝒞  es@es'@es'' : (t1s _> t2s)"
  shows "ts' ts''. (𝒮𝒞  es : (t1s _> ts'))
                      (𝒮𝒞  es' : (ts' _> ts''))
                      (𝒮𝒞  es'' : (ts'' _> t2s))"
proof -
  obtain ts' where "𝒮𝒞  es : (t1s _> ts')" "𝒮𝒞  es'@es'' : (ts' _> t2s)"
    using assms(1) e_type_comp_conc1
    by fastforce
  moreover
  then obtain ts'' where "𝒮𝒞  es' : (ts' _> ts'')" "𝒮𝒞  es'' : (ts'' _> t2s)"
    using e_type_comp_conc1
    by fastforce
  ultimately
  show ?thesis
    by fastforce
qed

lemma b_e_type_value_list:
  assumes "(𝒞  es@[C v] : (ts _> ts'@[t]))"
  shows "(𝒞  es : (ts _> ts'))"
        "(typeof v = t)"
proof -
  obtain ts'' where "(𝒞  es : (ts _> ts''))" "(𝒞  [C v] : (ts'' _> ts' @ [t]))"
    using b_e_type_comp assms
    by blast
  thus "(𝒞  es : (ts _> ts'))" "(typeof v = t)"
    using b_e_type_value[of 𝒞 "C v" "ts''" "ts' @ [t]"]
    by auto
qed

lemma e_type_label:
  assumes "𝒮𝒞  [Label n es0 es] : (ts _> ts')"
  shows "tls t2s. (ts' = (ts@t2s))
                 length tls = n
                 (𝒮𝒞  es0 : (tls _> t2s))
                 (𝒮𝒞label := [tls] @ (label 𝒞)  es : ([] _> t2s))"
  using assms
proof (induction "𝒮" "𝒞" "[Label n es0 es]" "(ts _> ts')" arbitrary: ts ts')
  case (1 𝒞 b_es 𝒮)
  then show ?case
    by (simp add: map_eq_Cons_conv)
next
  case (2 𝒮 𝒞 es t1s t2s e t3s)
  then show ?case
    by (metis append_self_conv2 b_e_type_empty last_snoc list.simps(8) unlift_b_e)
next
  case (3 𝒮 𝒞 t1s t2s ts)
  then show ?case
    by simp
next
  case (7 𝒮 𝒞 t2s)
  then show ?case
    by fastforce
qed

lemma e_type_callcl_native:
  assumes "𝒮𝒞  [Callcl cl] : (t1s' _> t2s')"
          "cl = Func_native i tf ts es"
  shows "t1s t2s ts_c. (t1s' = ts_c @ t1s)
                          (t2s' = ts_c @ t2s)
                          tf = (t1s _> t2s)
                          i < length (s_inst 𝒮)
                          (((s_inst 𝒮)!i)local := (local ((s_inst 𝒮)!i)) @ t1s @ ts, label := ([t2s] @ (label ((s_inst 𝒮)!i))), return := Some t2s   es : ([] _> t2s))"
  using assms
proof (induction "𝒮" "𝒞" "[Callcl cl]" "(t1s' _> t2s')" arbitrary: t1s' t2s')
  case (1 𝒞 b_es 𝒮)
  thus ?case
    by auto
next
  case (2 𝒮 𝒞 es t1s t2s e t3s)
  have "𝒞  [] : (t1s _> t2s)"
    using 2(1,5) unlift_b_e
    by (metis Nil_is_map_conv append_Nil butlast_snoc)
  thus ?case
    using 2(4,5,6)
    by fastforce
next
  case (3 𝒮 𝒞 t1s t2s ts)
    thus ?case
    by fastforce
next
  case (6 𝒮 𝒞)
  thus ?case
    unfolding cl_typing.simps
    by fastforce
qed

lemma e_type_callcl_host:
  assumes "𝒮𝒞  [Callcl cl] : (t1s' _> t2s')"
          "cl = Func_host tf f"
  shows "t1s t2s ts_c. (t1s' = ts_c @ t1s)
                         (t2s' = ts_c @ t2s)
                         tf = (t1s _> t2s)"
  using assms
proof (induction "𝒮" "𝒞" "[Callcl cl]" "(t1s' _> t2s')" arbitrary: t1s' t2s')
  case (1 𝒞 b_es 𝒮)
  thus ?case
    by auto
next
  case (2 𝒮 𝒞 es t1s t2s e t3s)
  have "𝒞  [] : (t1s _> t2s)"
    using 2(1,5) unlift_b_e
    by (metis Nil_is_map_conv append_Nil butlast_snoc)
  thus ?case
    using 2(4,5,6)
    by fastforce
next
  case (3 𝒮 𝒞 t1s t2s ts)
    thus ?case
    by fastforce
next
  case (6 𝒮 𝒞)
  thus ?case
    unfolding cl_typing.simps
    by fastforce
qed

lemma e_type_callcl:
  assumes "𝒮𝒞  [Callcl cl] : (t1s' _> t2s')"
  shows "t1s t2s ts_c. (t1s' = ts_c @ t1s)
                         (t2s' = ts_c @ t2s)
                         cl_type cl = (t1s _> t2s)"
proof (cases cl)
  case (Func_native x11 x12 x13 x14)
  thus ?thesis
    using e_type_callcl_native[OF assms]
    unfolding cl_type_def
    by (cases x12) fastforce
next
  case (Func_host x21 x22)
  thus ?thesis
    using e_type_callcl_host[OF assms]
    unfolding cl_type_def
    by fastforce
qed

lemma s_type_unfold:
  assumes "𝒮rs ⊩_i vs;es : ts"
  shows "i < length (s_inst 𝒮)"
        "(rs = Some ts)  rs = None"
        "(𝒮((s_inst 𝒮)!i)local := (local ((s_inst 𝒮)!i)) @ (map typeof vs), return := rs  es : ([] _> ts))"
  using assms
  by (induction vs es ts, auto)

lemma e_type_local:
  assumes "𝒮𝒞  [Local n i vs es] : (ts _> ts')"
  shows "tls. i < length (s_inst 𝒮)
                length tls = n
                (𝒮((s_inst 𝒮)!i)local := (local ((s_inst 𝒮)!i)) @ (map typeof vs), return := Some tls  es : ([] _> tls))
                ts' = ts @ tls"
  using assms
proof (induction "𝒮" "𝒞" "[Local n i vs es]" "(ts _> ts')" arbitrary: ts ts')
  case (2 𝒮 𝒞 es' t1s t2s e t3s)
  have "t1s = t2s"
    using 2 unlift_b_e
    by force
  thus ?case
    using 2
    by simp
qed (auto simp add: unlift_b_e s_typing.simps)

lemma e_type_local_shallow:
  assumes "𝒮𝒞  [Local n i vs es] : (ts _> ts')"
  shows "tls. length tls = n  ts' = ts@tls  (𝒮(Some tls) ⊩_i vs;es : tls)"
  using assms
proof (induction "𝒮" "𝒞" "[Local n i vs es]" "(ts _> ts')" arbitrary: ts ts')
  case (1 𝒞 b_es 𝒮)
  thus ?case
  by (metis e.distinct(7) map_eq_Cons_D)
next
  case (2 𝒮 𝒞 es t1s t2s e t3s)
  thus ?case
  by simp (metis append_Nil append_eq_append_conv e_type_comp_conc e_type_local)
qed simp_all

(* Some proofs treat (lists of) consts as an opaque (typed) arrangement. *)
lemma e_type_const_unwrap:
  assumes "is_const e"
  shows "v. e = $C v"
  using assms
proof (cases e)
  case (Basic x1)
  then show ?thesis
    using assms
  proof (cases x1)
    case (EConst x23)
      thus ?thesis
        using Basic e_typing_s_typing.intros(1,3)
        by fastforce
  qed  (simp_all add: is_const_def)
qed (simp_all add: is_const_def)

lemma is_const_list1:
  assumes "ves = map (Basic  EConst) vs"
  shows "const_list ves"
  using assms
proof (induction vs arbitrary: ves)
  case Nil
  then show ?case
    unfolding const_list_def
    by simp
next
  case (Cons a vs)
  then obtain ves' where "ves' = map (Basic  EConst) vs"
    by blast
  moreover
  have "is_const ((Basic  EConst) a)"
    unfolding is_const_def
    by simp
  ultimately
  show ?case
    using Cons
    unfolding const_list_def
      (* WHYYYYYY *)
    by auto
qed

lemma is_const_list:
  assumes "ves = $$* vs"
  shows "const_list ves"
  using assms is_const_list1
  unfolding comp_def
  by auto

lemma const_list_cons_last:
  assumes "const_list (es@[e])"
  shows "const_list es"
        "is_const e"
  using assms list_all_append[of is_const es "[e]"]
  unfolding const_list_def
  by auto

lemma e_type_const1:
  assumes "is_const e"
  shows "t. (𝒮𝒞  [e] : (ts _> ts@[t]))"
  using assms
proof (cases e)
  case (Basic x1)
  then show ?thesis
    using assms
  proof (cases x1)
    case (EConst x23)
      hence "𝒞  [x1] : ([] _> [typeof x23])"
        by (simp add: b_e_typing.intros(1))
      thus ?thesis
        using Basic e_typing_s_typing.intros(1,3)
        by (metis append_Nil2 to_e_list_1)
  qed  (simp_all add: is_const_def)
qed (simp_all add: is_const_def)

lemma e_type_const:
  assumes "is_const e"
          "𝒮𝒞  [e] : (ts _> ts')"
  shows  "t. (ts' = ts@[t])  (𝒮𝒞'  [e] : ([] _> [t]))"
  using assms
proof (cases e)
  case (Basic x1)
  then show ?thesis
    using assms
  proof (cases x1)
    case (EConst x23)
      then have "ts' = ts @ [typeof x23]"
        by (metis (no_types) Basic assms(2) b_e_type_value list.simps(8,9) unlift_b_e)
      moreover
      have "𝒮𝒞'  [e] : ([] _> [typeof x23])"
        using Basic EConst b_e_typing.intros(1) e_typing_s_typing.intros(1)
        by fastforce
      ultimately
      show ?thesis
        by simp
  qed  (simp_all add: is_const_def)
qed (simp_all add: is_const_def)

lemma const_typeof:
  assumes "𝒮𝒞  [$C v] : ([] _> [t])"
  shows "typeof v = t"
  using assms
proof -
  have "𝒞  [C v] : ([] _> [t])"
    using unlift_b_e assms
    by fastforce
  thus ?thesis
    by (induction "[C v]" "([] _> [t])" rule: b_e_typing.induct, auto)
qed

lemma e_type_const_list:
  assumes "const_list vs"
          "𝒮𝒞  vs : (ts _> ts')"
  shows   "tvs. ts' = ts @ tvs  length vs = length tvs  (𝒮𝒞'  vs : ([] _> tvs))"
  using assms
proof (induction vs arbitrary: ts ts' rule: List.rev_induct)
  case Nil
  have "𝒮𝒞'  [] : ([] _> [])"
    using b_e_type_empty[of 𝒞' "[]" "[]"] e_typing_s_typing.intros(1)
    by fastforce
  thus ?case
    using Nil
    by (metis append_Nil2 b_e_type_empty list.map(1) list.size(3) unlift_b_e)
next
  case (snoc x xs)
  hence v_lists:"list_all is_const xs" "is_const x"
  unfolding const_list_def
  by simp_all
  obtain ts'' where ts''_def:"𝒮𝒞  xs : (ts _> ts'')" "𝒮𝒞  [x] : (ts'' _> ts')"
    using snoc(3) e_type_comp
    by fastforce
  then obtain ts_b where ts_b_def:"ts'' = ts @ ts_b" "length xs = length ts_b" "𝒮𝒞'  xs : ([] _> ts_b)"
    using snoc(1) v_lists(1)
    unfolding const_list_def
    by fastforce
  then obtain t where t_def:"ts' = ts @ ts_b @ [t]" "𝒮𝒞'  [x] : ([] _> [t])"
    using e_type_const v_lists(2) ts''_def
    by fastforce
  moreover
  then have "length (ts_b@[t]) = length (xs@[x])"
    using ts_b_def(2)
    by simp
  moreover
  have "𝒮𝒞'  (xs@[x]) : ([] _> ts_b@[t])"
    using ts_b_def(3) t_def e_typing_s_typing.intros(2,3)
    by fastforce
  ultimately
  show ?case
    by simp
qed

lemma e_type_const_list_snoc:
  assumes "const_list vs"
          "𝒮𝒞  vs : ([] _> ts@[t])"
  shows "vs1 v2. (𝒮𝒞  vs1 : ([] _> ts))
                    (𝒮𝒞  [v2] : (ts _> ts@[t]))
                    (vs = vs1@[v2])
                    const_list vs1
                    is_const v2"
  using assms
proof -
  obtain vs' v where vs_def:"vs = vs'@[v]"
    using e_type_const_list[OF assms(1,2)]
    by (metis append_Nil append_eq_append_conv list.size(3) snoc_eq_iff_butlast)
  hence consts_def:"const_list vs'" "is_const v"
    using assms(1)
    unfolding const_list_def
    by auto
  obtain ts' where ts'_def:"𝒮𝒞  vs' : ([] _> ts')" "𝒮𝒞  [v] : (ts' _> ts@[t])"
    using vs_def assms(2) e_type_comp[of 𝒮 𝒞 vs' v "[]" "ts@[t]"]
    by fastforce
  obtain c where "v = $C c"
    using e_type_const_unwrap consts_def(2)
    by fastforce
  hence "ts' = ts"
    using ts'_def(2) unlift_b_e[of 𝒮 𝒞 "[C c]"] b_e_type_value
    by fastforce
  thus ?thesis using ts'_def vs_def consts_def
    by simp
qed
    
lemma e_type_const_list_cons:
  assumes "const_list vs"
          "𝒮𝒞  vs : ([] _> (ts1@ts2))"
  shows "vs1 vs2. (𝒮𝒞  vs1 : ([] _> ts1))
                    (𝒮𝒞  vs2 : (ts1 _> (ts1@ts2)))
                    vs = vs1@vs2
                    const_list vs1
                    const_list vs2"
  using assms
proof (induction "ts1@ts2" arbitrary: vs ts1 ts2 rule: List.rev_induct)
  case Nil
  thus ?case
    using e_type_const_list
    by fastforce
next
  case (snoc t ts)
  note snoc_outer = snoc
  show ?case
  proof (cases ts2 rule: List.rev_cases)
    case Nil
    have "𝒮𝒞  [] : (ts1 _> ts1 @ [])"
      using b_e_typing.empty b_e_typing.weakening e_typing_s_typing.intros(1)
      by fastforce
    then show ?thesis
      using snoc(3,4) Nil
      unfolding const_list_def
      by auto
  next
    case (snoc ts2' a)
    obtain vs1 v2 where vs1_def:"(𝒮𝒞  vs1 : ([] _> ts1 @ ts2'))"
                                "(𝒮𝒞  [v2] : (ts1 @ ts2' _> ts1 @ ts2' @[t]))"
                                "(vs = vs1@[v2])"
                                "const_list vs1"
                                "is_const v2"
                                "ts = ts1 @ ts2'"
      using e_type_const_list_snoc[OF snoc_outer(3), of 𝒮 𝒞 "ts1@ts2'" t]
            snoc_outer(2,4) snoc
      by fastforce
    show ?thesis
      using snoc_outer(1)[OF vs1_def(6,4,1)] snoc_outer(2) vs1_def(3,5)
            e_typing_s_typing.intros(2)[OF _ vs1_def(2), of _ ts1]
            snoc
      unfolding const_list_def
      by fastforce
  qed
qed

lemma e_type_const_conv_vs:
  assumes "const_list ves"
  shows "vs. ves = $$* vs"
  using assms
proof (induction ves)
  case Nil
  thus ?case
    by simp
next
  case (Cons a ves)
  thus ?case
  using e_type_const_unwrap
  unfolding const_list_def
  by (metis (no_types, lifting) list.pred_inject(2) list.simps(9)) 
qed

lemma types_exist_lfilled:
  assumes "Lfilled k lholed es lfilled"
          "𝒮𝒞  lfilled : (ts _> ts')"
  shows "t1s t2s 𝒞' arb_label. (𝒮𝒞label := arb_label@(label 𝒞)  es : (t1s _> t2s))"
  using assms
proof (induction arbitrary: 𝒞 ts ts' rule: Lfilled.induct)
  case (L0 vs lholed es' es)
  hence "𝒮(𝒞label := label 𝒞)  vs @ es @ es' : (ts _> ts')"
    by simp
  thus ?case
    using e_type_comp_conc2
    by (metis append_Nil)
next
  case (LN vs lholed n es' l es'' k es lfilledk)
  obtain ts'' ts''' where "𝒮𝒞  [Label n es' lfilledk]  : (ts'' _> ts''')"
    using e_type_comp_conc2[OF LN(5)]
    by fastforce
  then obtain t1s t2s ts where test:"𝒮𝒞label := [ts] @ (label 𝒞)  lfilledk  : (t1s _> t2s)"
    using e_type_label
    by metis
  show ?case
    using LN(4)[OF test(1)]
    by simp (metis append.assoc append_Cons append_Nil)
qed

lemma types_exist_lfilled_weak:
  assumes "Lfilled k lholed es lfilled"
          "𝒮𝒞  lfilled : (ts _> ts')"
  shows "t1s t2s 𝒞' arb_label arb_return. (𝒮𝒞label := arb_label, return := arb_return  es : (t1s _> t2s))"
proof -
  have "t1s t2s 𝒞' arb_label. (𝒮𝒞label := arb_label, return := (return 𝒞)  es : (t1s _> t2s))"
    using types_exist_lfilled[OF assms]
    by fastforce
  thus ?thesis
    by fastforce
qed

lemma store_typing_imp_func_agree:
  assumes "store_typing s 𝒮"
          "i < length (s_inst 𝒮)"
          "j < length (func_t ((s_inst 𝒮)!i))"
  shows "(sfunc_ind s i j) < length (s_funcs 𝒮)"
        "cl_typing 𝒮 (sfunc s i j) ((s_funcs 𝒮)!(sfunc_ind s i j))"
        "((s_funcs 𝒮)!(sfunc_ind s i j)) = (func_t ((s_inst 𝒮)!i))!j"
proof -
  have funcs_agree:"list_all2 (cl_typing 𝒮) (funcs s) (s_funcs 𝒮)"
    using assms(1)
    unfolding store_typing.simps
    by auto
  have "list_all2 (funci_agree (s_funcs 𝒮)) (inst.funcs ((inst s)!i)) (func_t ((s_inst 𝒮)!i))"
    using assms(1,2) store_typing_imp_inst_length_eq store_typing_imp_inst_typing
    by (fastforce simp add: inst_typing.simps)
  hence "funci_agree (s_funcs 𝒮) ((inst.funcs ((inst s)!i))!j) ((func_t ((s_inst 𝒮)!i))!j)"
    using assms(3) list_all2_nthD2
    by blast
  thus "(sfunc_ind s i j) < length (s_funcs 𝒮)"
       "((s_funcs 𝒮)!(sfunc_ind s i j)) = (func_t ((s_inst 𝒮)!i))!j"
    unfolding funci_agree_def sfunc_ind_def
    by auto
  thus "cl_typing 𝒮 (sfunc s i j) ((s_funcs 𝒮)!(sfunc_ind s i j))"
    using funcs_agree list_all2_nthD2
    unfolding sfunc_def
    by fastforce
qed

lemma store_typing_imp_glob_agree:
  assumes "store_typing s 𝒮"
          "i < length (s_inst 𝒮)"
          "j < length (global ((s_inst 𝒮)!i))"
  shows "(sglob_ind s i j) < length (s_globs 𝒮)"
        "glob_agree (sglob s i j) ((s_globs 𝒮)!(sglob_ind s i j))"
        "((s_globs 𝒮)!(sglob_ind s i j)) = (global ((s_inst 𝒮)!i))!j"
proof -
  have globs_agree:"list_all2 glob_agree (globs s) (s_globs 𝒮)"
    using assms(1)
    unfolding store_typing.simps
    by auto
  have "list_all2 (globi_agree (s_globs 𝒮)) (inst.globs ((inst s)!i)) (global ((s_inst 𝒮)!i))"
    using assms(1,2) store_typing_imp_inst_length_eq store_typing_imp_inst_typing
    by (fastforce simp add: inst_typing.simps)
  hence "globi_agree (s_globs 𝒮) ((inst.globs ((inst s)!i))!j) ((global ((s_inst 𝒮)!i))!j)"
    using assms(3) list_all2_nthD2
    by blast
  thus "(sglob_ind s i j) < length (s_globs 𝒮)"
       "((s_globs 𝒮)!(sglob_ind s i j)) = (global ((s_inst 𝒮)!i))!j"
    unfolding globi_agree_def sglob_ind_def
    by auto
  thus "glob_agree (sglob s i j) ((s_globs 𝒮)!(sglob_ind s i j))"
    using globs_agree list_all2_nthD2
    unfolding sglob_def
    by fastforce
qed

lemma store_typing_imp_mem_agree_Some:
  assumes "store_typing s 𝒮"
          "i < length (s_inst 𝒮)"
          "smem_ind s i = Some j"
  shows "j < length (s_mem 𝒮)"
        "mem_agree ((mem s)!j) ((s_mem 𝒮)!j)"
        "x. ((s_mem 𝒮)!j) = x  (memory ((s_inst 𝒮)!i)) = Some x"
proof -
  have mems_agree:"list_all2 mem_agree (mem s) (s_mem 𝒮)"
  using assms(1)
  unfolding store_typing.simps
  by auto
  hence "memi_agree (s_mem 𝒮) ((inst.mem ((inst s)!i))) ((memory ((s_inst 𝒮)!i)))"
    using assms(1,2) store_typing_imp_inst_length_eq store_typing_imp_inst_typing
    by (fastforce simp add: inst_typing.simps)
  thus "j < length (s_mem 𝒮)"
       "x. ((s_mem 𝒮)!j) = x  (memory ((s_inst 𝒮)!i)) = Some x"
    using assms(3)
    unfolding memi_agree_def smem_ind_def
    by auto
  thus "mem_agree ((mem s)!j) ((s_mem 𝒮)!j)"
    using mems_agree list_all2_nthD2
    unfolding sglob_def
    by fastforce
qed

lemma store_typing_imp_mem_agree_None:
  assumes "store_typing s 𝒮"
          "i < length (s_inst 𝒮)"
          "smem_ind s i = None"
  shows "(memory ((s_inst 𝒮)!i)) = None"
proof -
  have mems_agree:"list_all2 mem_agree (mem s) (s_mem 𝒮)"
  using assms(1)
  unfolding store_typing.simps
  by auto
  hence "memi_agree (s_mem 𝒮) ((inst.mem ((inst s)!i))) ((memory ((s_inst 𝒮)!i)))"
    using assms(1,2) store_typing_imp_inst_length_eq store_typing_imp_inst_typing
    by (fastforce simp add: inst_typing.simps)
  thus ?thesis
    using assms(3)
    unfolding memi_agree_def smem_ind_def
    by auto
qed

lemma store_mem_exists:
  assumes "i < length (s_inst 𝒮)"
          "store_typing s 𝒮"
  shows "Option.is_none (memory ((s_inst 𝒮)!i)) = Option.is_none (inst.mem ((inst s)!i))"
proof -
  obtain j where j_def:"j = (inst.mem ((inst s)!i))"
    by blast
  obtain m where m_def:"m = (memory ((s_inst 𝒮)!i))"
    by blast
  have inst_typ:"inst_typing 𝒮 ((inst s)!i) ((s_inst 𝒮)!i)"
    using assms
    unfolding store_typing.simps list_all2_conv_all_nth
    by auto
  thus ?thesis
    unfolding inst_typing.simps memi_agree_def
    by auto
qed

lemma store_preserved_mem:
  assumes "store_typing s 𝒮"
          "s' = ss.mem := (s.mem s)[i := mem']"
          "mem_size mem'  mem_size orig_mem"
          "((s.mem s)!i) = orig_mem"
  shows "store_typing s' 𝒮"
proof -
  obtain insts fs clss bss gs where "s = inst = insts, funcs = fs, tab = clss, mem = bss, globs = gs"
    using s.cases
    by blast
  moreover
  obtain insts' fs' clss' bss' gs' where "s' = inst = insts', funcs = fs', tab = clss', mem = bss', globs = gs'"
    using s.cases
    by blast
  moreover
  obtain 𝒞s tfs ns ms tgs where "𝒮 = s_inst = 𝒞s, s_funcs = tfs, s_tab = ns, s_mem = ms, s_globs = tgs"
    using s_context.cases
    by blast
  moreover
  note s_S_defs = calculation
  hence
  "insts = insts'"
  "fs = fs'"
  "clss = clss'"
  "gs = gs'"
    using assms(2)
    by simp_all
  hence
  "list_all2 (inst_typing 𝒮) insts' 𝒞s"
  "list_all2 (cl_typing 𝒮) fs' tfs"
  "list_all (tab_agree 𝒮) (concat clss')"
  "list_all2 (λcls n. n  length cls) clss' ns"
  "list_all2 glob_agree gs' tgs"
    using s_S_defs assms(1)
    unfolding store_typing.simps
    by auto
  moreover
  have "list_all2 (λ bs m. m  mem_size bs) bss' ms"
  proof -
    have "length bss = length bss'"
      using assms(2)  s_S_defs
      by (simp)
    moreover
    (* Memory correct before execution. *)
    have initial_mem:"list_all2 (λ bs m. m  mem_size bs) bss ms"
      using assms(1) s_S_defs
      unfolding store_typing.simps mem_agree_def
      by blast
    have "n. n < length bss  (λ bs m. m  mem_size bs) (bss'!n) (ms!n)"
    proof -
      fix n
      assume local_assms:"n < length bss"
      obtain 𝒞_m where cmdef:"𝒞_m = 𝒞s ! n"
        by blast
      hence "(λ bs m. m  mem_size bs) (bss!n) (ms!n)"
        using initial_mem local_assms
        unfolding list_all2_conv_all_nth
        by simp
      thus "(λ bs m. m  mem_size bs) (bss'!n) (ms!n)"
        using assms(2,3,4) s_S_defs local_assms
        by (cases "n=i", auto)
    qed
    ultimately
    show ?thesis
      by (metis initial_mem list_all2_all_nthI list_all2_lengthD)
  qed
  ultimately
  show ?thesis
    unfolding store_typing.simps mem_agree_def
    by simp
qed

lemma types_agree_imp_e_typing:
  assumes "types_agree t v"
  shows "𝒮𝒞  [$C v] : ([] _> [t])"
  using assms e_typing_s_typing.intros(1)[OF b_e_typing.intros(1)]
  unfolding types_agree_def
  by fastforce

lemma list_types_agree_imp_e_typing:
  assumes "list_all2 types_agree ts vs"
  shows "𝒮𝒞  $$* vs : ([] _> ts)"
  using assms
proof (induction rule: list_all2_induct)
  case Nil
  thus ?case
    using b_e_typing.empty e_typing_s_typing.intros(1)
    by fastforce
next
  case (Cons t ts v vs)
  hence "𝒮𝒞  [$C v] : ([] _> [t])"
    using types_agree_imp_e_typing
    by fastforce
  thus ?case
    using e_typing_s_typing.intros(3)[OF Cons(3), of "[t]"] e_type_comp_conc
    by fastforce
qed

lemma b_e_typing_imp_list_types_agree:
  assumes "𝒞  (map (λv. C v) vs) : (ts' _> ts'@ts)"
  shows "list_all2 types_agree ts vs"
  using assms
proof (induction "(map (λv. C v) vs)" "(ts' _> ts'@ts)" arbitrary: ts ts' vs rule: b_e_typing.induct)
  case (composition 𝒞 es t1s t2s e)
  obtain vs1 vs2 where es_e_def:"es = map EConst vs1" "[e] = map EConst vs2" "vs1@vs2=vs"  
    using composition(5)
    by (metis (no_types) last_map list.simps(8,9) map_butlast snoc_eq_iff_butlast)
  have "const_list ($*es)"
    using es_e_def(1) is_const_list1
    by auto
  then obtain tvs1 where "t2s = t1s@tvs1"
    using e_type_const_list e_typing_s_typing.intros(1)[OF composition(1)]
    by fastforce
  moreover
  have "const_list ($*[e])"
    using es_e_def(2) is_const_list1
    by auto
  then obtain tvs2 where "t1s @ ts = t2s @ tvs2"
    using e_type_const_list e_typing_s_typing.intros(1)[OF composition(3)]
    by fastforce
  ultimately
  show ?case
    using composition(2,4,5) es_e_def
    by (auto simp add: list_all2_appendI)
qed (auto simp add: types_agree_def)

lemma e_typing_imp_list_types_agree:
  assumes "𝒮𝒞  ($$* vs) : (ts' _> ts'@ts)"
  shows "list_all2 types_agree ts vs"
proof -
  have "($$* vs) = $* (map (λv. C v) vs)"
    by simp
  thus ?thesis
    using assms unlift_b_e b_e_typing_imp_list_types_agree
    by (fastforce simp del: map_map)
qed

lemma store_extension_imp_store_typing:
  assumes "store_extension s s'"
          "store_typing s 𝒮"
  shows "store_typing s' 𝒮"
proof -
  obtain insts fs clss bss gs where "s = inst = insts, funcs = fs, tab = clss, mem = bss, globs = gs"
    using s.cases
    by blast
  moreover
  obtain insts' fs' clss' bss' gs' where "s' = inst = insts', funcs = fs', tab = clss', mem = bss', globs = gs'"
    using s.cases
    by blast
  moreover
  obtain 𝒞s tfs ns ms tgs where "𝒮 = s_inst = 𝒞s, s_funcs = tfs, s_tab = ns, s_mem = ms, s_globs = tgs"
    using s_context.cases
    by blast
  moreover
  note s_S_defs = calculation
  hence
  "insts = insts'"
  "fs = fs'"
  "clss = clss'"
  "gs = gs'"
    using assms(1)
    unfolding store_extension.simps
    by simp_all
  hence
  "list_all2 (inst_typing 𝒮) insts' 𝒞s"
  "list_all2 (cl_typing 𝒮) fs' tfs"
  "list_all (tab_agree 𝒮) (concat clss')"
  "list_all2 (λcls n. n  length cls) clss' ns"
  "list_all2 glob_agree gs' tgs"
    using s_S_defs assms(2)
    unfolding store_typing.simps
    by auto
  moreover
  have "list_all2 (λ bs m. m  mem_size bs) bss ms"
    using s_S_defs(1,3) assms(2)
    unfolding store_typing.simps mem_agree_def
    by simp
  hence "list_all2 mem_agree bss' ms"
    using assms(1) s_S_defs(1,2)
    unfolding store_extension.simps list_all2_conv_all_nth mem_agree_def
    by fastforce
  ultimately
  show ?thesis
    using store_typing.intros
    by fastforce
qed

lemma lfilled_deterministic:
  assumes "Lfilled k lfilled es les"
          "Lfilled k lfilled es les'"
  shows "les = les'"
  using assms
proof (induction arbitrary: les' rule: Lfilled.induct)
  case (L0 vs lholed es' es)
  thus ?case
    by (fastforce simp add: Lfilled.simps[of 0])
next
  case (LN vs lholed n es' l es'' k es lfilledk)
  thus ?case
    unfolding Lfilled.simps[of "(k + 1)"]
    by fastforce
qed
end

Theory Wasm_Properties

section ‹Lemmas for Soundness Proof›

theory Wasm_Properties imports Wasm_Properties_Aux begin

subsection ‹Preservation›

lemma t_cvt: assumes "cvt t sx v = Some v'" shows "t = typeof v'"
  using assms
  unfolding cvt_def typeof_def
  apply (cases t)
     apply (simp add: option.case_eq_if, metis option.discI option.inject v.simps(17))
    apply (simp add: option.case_eq_if, metis option.discI option.inject v.simps(18))
   apply (simp add: option.case_eq_if, metis option.discI option.inject v.simps(19))
  apply (simp add: option.case_eq_if, metis option.discI option.inject v.simps(20))
  done

lemma store_preserved1:
  assumes "s;vs;es ↝_i s';vs';es'"
          "store_typing s 𝒮"
          "𝒮𝒞  es : (ts _> ts')"
          "𝒞 = ((s_inst 𝒮)!i)local := local ((s_inst 𝒮)!i) @ (map typeof vs), label := arb_label, return := arb_return"
          "i < length (s_inst 𝒮)"
  shows "store_typing s' 𝒮"
  using assms
proof (induction arbitrary: 𝒞 arb_label arb_return ts ts' rule: reduce.induct)
  case (callcl_host_Some cl t1s t2s f ves vcs n m s hs s' vcs' vs i)
  obtain ts'' where ts''_def:"𝒮𝒞  ves : (ts _> ts'')" "𝒮𝒞  [Callcl cl] : (ts'' _> ts')"
  using callcl_host_Some(8) e_type_comp
  by fastforce
  have ves_c:"const_list ves"
    using is_const_list[OF callcl_host_Some(2)]
    by simp
  then obtain tvs where tvs_def:"ts'' = ts @ tvs"
                                "length t1s = length tvs"
                                "𝒮𝒞  ves : ([] _> tvs)"
    using ts''_def(1) e_type_const_list[of ves 𝒮 𝒞 ts ts''] callcl_host_Some
    by fastforce
  hence "ts'' = ts @ t1s"
        "ts' = ts @ t2s"
    using e_type_callcl_host[OF ts''_def(2) callcl_host_Some(1)]
    by auto
  moreover
  hence "list_all2 types_agree t1s vcs"
    using e_typing_imp_list_types_agree[where ?ts' = "[]"] callcl_host_Some(2) tvs_def(1,3)
    by fastforce
  thus ?case
    using store_extension_imp_store_typing
          host_apply_preserve_store[OF _ callcl_host_Some(6)] callcl_host_Some(7)
    by fastforce
next
  case (set_global s i j v s' vs)
  obtain insts fs clss bss gs where "s = inst = insts, funcs = fs, tab = clss, mem = bss, globs = gs"
    using s.cases
    by blast
  moreover
  obtain insts' fs' clss' bss' gs' where "s' = inst = insts', funcs = fs', tab = clss', mem = bss', globs = gs'"
    using s.cases
    by blast
  moreover
  obtain 𝒞s tfs ns ms tgs where "𝒮 = s_inst = 𝒞s, s_funcs = tfs, s_tab = ns, s_mem = ms, s_globs = tgs"
    using s_context.cases
    by blast
  moreover
  
  note s_S_defs = calculation

  (* Prove that inst, tab and mem are not altered. *)
  have
  "insts = insts'"
  "fs = fs'"
  "clss = clss'"
  "bss = bss'"
    using set_global(1) s_S_defs(1,2)
    unfolding supdate_glob_def supdate_glob_s_def
    by (metis s.ext_inject s.update_convs(5))+
  hence
  "list_all2 (inst_typing 𝒮) insts' 𝒞s"
  "list_all2 (cl_typing 𝒮) fs' tfs"
  "list_all (tab_agree 𝒮) (concat clss')"
  "list_all2 (λcls n. n  length cls) clss' ns"
  "list_all2 mem_agree bss' ms"
    using set_global(2) s_S_defs
    unfolding store_typing.simps
    by auto
  moreover
  have "list_all2 glob_agree gs' tgs"
  proof -
    have gs_agree:"list_all2 glob_agree gs tgs"
      using set_global(2) s_S_defs
      unfolding store_typing.simps
      by auto
    have "length gs = length gs'"
      using s_S_defs(1,2) set_global(1)
      unfolding supdate_glob_def supdate_glob_s_def
      by (metis length_list_update s.select_convs(5) s.update_convs(5))
    moreover
    obtain k where k_def:"(sglob_ind s i j) = k"
      by blast
    hence "j'. j'  k; j' < length gs  gs!j' = gs'!j'"
      using s_S_defs(1,2) set_global(1)
      unfolding supdate_glob_def supdate_glob_s_def
      by auto
    hence "j'. j'  k; j' < length gs  glob_agree (gs'!j') (tgs!j')"
      using gs_agree
      by (metis list_all2_conv_all_nth)
    moreover
    have "glob_agree (gs'!k) (tgs!k)"
    proof -
      obtain ts'' where ts''_def:"𝒞  [C v] : (ts _> ts'')" "𝒞  [Set_global j] : (ts'' _> ts')"
        by (metis b_e_type_comp2_unlift set_global.prems(2))
      have b_es:"ts'' = ts@[typeof v]"
                "ts = ts'"
                "global 𝒞 ! j = tg_mut = T_mut, tg_t = typeof v"
                "j < length (global 𝒞)"
        using b_e_type_value[OF ts''_def(1)] b_e_type_set_global[OF ts''_def(2)]
        by auto
      hence "j < length (global ((s_inst 𝒮)!i))"
        using set_global(4)
        by fastforce
      hence globs_agree:"k < length (s_globs 𝒮)"
                        "glob_agree (gs!k) (tgs!k)"
                        "(tgs!k) = (global 𝒞)!j"
        using store_typing_imp_glob_agree[OF set_global(2,5)] b_es(4) s_S_defs(1,3) k_def set_global(4)
        unfolding sglob_def
        by auto
      hence "g_mut (gs!k) = T_mut"
            "typeof (g_val (gs!k)) = typeof v"
        using b_es(3)
        unfolding glob_agree_def
        by auto
      hence "g_mut (gs'!k) = T_mut"
            "typeof (g_val (gs'!k)) = typeof v"
        using set_global(1) k_def globs_agree(1) store_typing_imp_glob_length_eq[OF set_global(2)] s_S_defs(1,2)
        unfolding supdate_glob_def supdate_glob_s_def
        by auto
      thus ?thesis
        using globs_agree(3) b_es(3)
        unfolding glob_agree_def
        by fastforce 
    qed
    ultimately
    show ?thesis
      using gs_agree
      unfolding list_all2_conv_all_nth
      by fastforce
  qed
  ultimately
  show ?case
    using store_typing.intros
    by simp
next
  (* The following are all special cases of store_preserved_mem. *)
  case (store_Some t v s i j m k off mem' vs a)
  show ?case
    using store_preserved_mem[OF store_Some(5) _ _ store_Some(3)] store_size[OF store_Some(4)]
    by fastforce
next
  case (store_packed_Some t v s i j m k off tp mem' vs a)
  thus ?case
    using store_preserved_mem[OF store_packed_Some(5) _ _ store_packed_Some(3)] store_packed_size[OF store_packed_Some(4)]
    by simp
next
  case (grow_memory s i j n mem c mem' vs)
  show ?case
    using store_preserved_mem[OF grow_memory(5)_ _ grow_memory(2)] mem_grow_size[OF grow_memory(4)]
    by simp
next
  case (label s vs es i s' vs' es' k lholed les les')
  obtain 𝒞' t1s t2s arb_label' arb_return' where es_def:"𝒞' = 𝒞label := arb_label', return := arb_return'" "𝒮𝒞'  es : (t1s _> t2s)"
    using types_exist_lfilled_weak[OF label(2,6)]
    by fastforce
  thus ?case
    using label(4)[OF label(5) es_def(2) _ label(8)] label(7)
    by fastforce
next
  case (local s vs es i s' vs' es' v0s n j)
  obtain tls where t_local:"(𝒮((s_inst 𝒮)!i)local := (local ((s_inst 𝒮)!i)) @ (map typeof vs), return := Some tls  es : ([] _> tls))"
                           "ts' = ts @ tls" "i < length (s_inst 𝒮)"
    using e_type_local[OF local(4)]
    by blast+
  show ?case
    using local(2)[OF local(3) t_local(1) _ t_local(3), of "(Some tls)" "label ((s_inst 𝒮)!i)" ]
    by fastforce
qed (simp_all)

lemma store_preserved:
  assumes "s;vs;es ↝_i s';vs';es'"
          "store_typing s 𝒮"
          "𝒮None ⊩_i vs;es : ts"
  shows "store_typing s' 𝒮"
proof -
  show ?thesis
    using store_preserved1[OF assms(1,2), of _ "[]" "ts" None "label (s_inst 𝒮!i)"]
          s_type_unfold[OF assms(3)]
    by fastforce
qed

lemma typeof_unop_testop:
  assumes "𝒮𝒞  [$C v, $e] : (ts _> ts')"
          "(e = (Unop_i t iop))  (e = (Unop_f t fop))  (e = (Testop t testop))"
  shows "(typeof v) = t"
        "e = (Unop_f t fop)  is_float_t t"
proof -
  have  "𝒞  [C v, e] : (ts _> ts')"
    using unlift_b_e assms(1)
    by simp
  then obtain ts'' where ts''_def:"𝒞  [C v] : (ts _> ts'')" "𝒞  [e] : (ts'' _> ts')"
    using b_e_type_comp[where ?e = e and ?es = "[C v]"]
    by fastforce
  show "(typeof v) = t" "e = (Unop_f t fop)  is_float_t t"
    using b_e_type_value[OF ts''_def(1)] assms(2) b_e_type_unop_testop[OF ts''_def(2)]
    by simp_all
qed

lemma typeof_cvtop:
  assumes "𝒮𝒞  [$C v, $e] : (ts _> ts')"
          "e = Cvtop t1 cvtop t sx"
  shows "(typeof v) = t"
        "cvtop = Convert  (t1  t)  ((sx = None) = ((is_float_t t1  is_float_t t)  (is_int_t t1  is_int_t t  (t_length t1 < t_length t))))"
        "cvtop = Reinterpret  (t1  t)  t_length t1 = t_length t"
proof -
  have  "𝒞  [C v, e] : (ts _> ts')"
    using unlift_b_e assms(1)
    by simp
  then obtain ts'' where ts''_def:"𝒞  [C v] : (ts _> ts'')" "𝒞  [e] : (ts'' _> ts')"
    using b_e_type_comp[where ?e = e and ?es = "[C v]"]
    by fastforce
  show "(typeof v) = t"
       "cvtop = Convert  (t1  t)  (sx = None) = ((is_float_t t1  is_float_t t)  (is_int_t t1  is_int_t t  (t_length t1 < t_length t)))"
       "cvtop = Reinterpret  (t1  t)  t_length t1 = t_length t"
    using b_e_type_value[OF ts''_def(1)] b_e_type_cvtop[OF ts''_def(2) assms(2)]
    by simp_all
qed

lemma types_preserved_unop_testop_cvtop:
  assumes "[$C v, $e]  [$C v']"
          "𝒮𝒞  [$C v, $e] : (ts _> ts')"
          "(e = (Unop_i t iop))  (e = (Unop_f t fop))  (e = (Testop t testop))   (e = (Cvtop t2 cvtop t sx))"
  shows "𝒮𝒞  [$C v'] : (ts _> ts')"
proof -
  have  "𝒞  [C v, e] : (ts _> ts')"
    using unlift_b_e assms(2)
    by simp
  then obtain ts'' where ts''_def:"𝒞  [C v] : (ts _> ts'')" "𝒞  [e] : (ts'' _> ts')"
    using b_e_type_comp[where ?e = e and ?es = "[C v]"]
    by fastforce
  have "ts@[arity_1_result e] = ts'" "(typeof v) = t"
    using b_e_type_value[OF ts''_def(1)] assms(3) b_e_type_unop_testop(1)[OF ts''_def(2)]
          b_e_type_cvtop(1)[OF ts''_def(2)]
    by (metis butlast_snoc, metis last_snoc)
  moreover
  have "arity_1_result e = typeof (v')"
    using assms(1,3)
    apply (cases rule: reduce_simple.cases)
             apply (simp_all add: arity_1_result_def wasm_deserialise_type t_cvt)
           apply (auto simp add: typeof_def)
    done
  hence "𝒞  [C v'] : ([] _> [arity_1_result e])"
    using b_e_typing.const
    by metis
  ultimately
  show "𝒮𝒞  [$C v'] : (ts _> ts')"
    using e_typing_s_typing.intros(1)
          b_e_typing.weakening[of 𝒞 "[C v']" "[]" "[arity_1_result e]" ts]
    by fastforce
qed

lemma typeof_binop_relop:
  assumes "𝒮𝒞  [$C v1, $C v2, $e] : (ts _> ts')"
          "e = Binop_i t iop  e = Binop_f t fop  e = Relop_i t irop  e = Relop_f t frop"
  shows "typeof v1 = t"
        "typeof v2 = t"
        "e = Binop_f t fop  is_float_t t"
        "e = Relop_f t frop  is_float_t t"
proof -
  have "𝒞  [C v1, C v2, e] : (ts _> ts')"
    using unlift_b_e assms(1)
    by simp
  then obtain ts'' where ts''_def:"𝒞  [C v1, C v2] : (ts _> ts'')" "𝒞  [e] : (ts'' _> ts')"
    using b_e_type_comp[where ?e = e and ?es = "[C v1, C v2]"]
    by fastforce
  then obtain ts_id where ts_id_def:"ts_id@[t,t] = ts''" "ts' = ts_id @ [arity_2_result e]"
                                    "e = Binop_f t fop  is_float_t t"
                                    "e = Relop_f t frop  is_float_t t"
    using assms(2) b_e_type_binop_relop[of 𝒞 e ts'' ts' t]
    by blast
  thus "typeof v1 = t"
       "typeof v2 = t"
       "e = Binop_f t fop  is_float_t t"
       "e = Relop_f t frop  is_float_t t"
    using ts''_def b_e_type_comp[of 𝒞 "[C v1]" "C v2" ts ts''] b_e_type_value2
    by fastforce+
qed

lemma types_preserved_binop_relop:
  assumes "[$C v1, $C v2, $e]  [$C v']"
          "𝒮𝒞  [$C v1, $C v2, $e] : (ts _> ts')"
          "e = Binop_i t iop  e = Binop_f t fop  e = Relop_i t irop  e = Relop_f t frop"
  shows "𝒮𝒞  [$C v'] : (ts _> ts')"
proof -
  have "𝒞  [C v1, C v2, e] : (ts _> ts')"
    using unlift_b_e assms(2)
    by simp
  then obtain ts'' where ts''_def:"𝒞  [C v1, C v2] : (ts _> ts'')" "𝒞  [e] : (ts'' _> ts')"
    using b_e_type_comp[where ?e = e and ?es = "[C v1, C v2]"]
    by fastforce
  then obtain ts_id where ts_id_def:"ts_id@[t,t] = ts''" "ts' = ts_id @ [arity_2_result e]"
    using assms(3) b_e_type_binop_relop[of 𝒞 e ts'' ts' t]
    by blast
  hence "𝒞  [C v1] : (ts _> ts_id@[t])"
    using ts''_def b_e_type_comp[of 𝒞 "[C v1]" "C v2" ts ts''] b_e_type_value
      by fastforce
  hence "ts@[arity_2_result e] = ts'"
    using b_e_type_value ts_id_def(2)
    by fastforce
  moreover
  have "arity_2_result e = typeof (v')"
    using assms(1,3)
    by (cases rule: reduce_simple.cases) (auto simp add: arity_2_result_def typeof_def)
  hence "𝒞  [C v'] : ([] _> [arity_2_result e])"
    using b_e_typing.const
    by metis
  ultimately show ?thesis
    using e_typing_s_typing.intros(1)
          b_e_typing.weakening[of 𝒞 "[C v']" "[]" "[arity_2_result e]" ts]
    by fastforce
qed

lemma types_preserved_drop:
  assumes "[$C v, $e]  []"
          "𝒮𝒞  [$C v, $e] : (ts _> ts')"
          "(e = (Drop))"
  shows "𝒮𝒞  [] : (ts _> ts')"
proof -
  have "𝒞  [C v, e] : (ts _> ts')"
    using unlift_b_e assms(2)
    by simp
  then obtain ts'' where ts''_def:"𝒞  [C v] : (ts _> ts'')" "𝒞  [e] : (ts'' _> ts')"
    using b_e_type_comp[where ?e = e and ?es = "[C v]"]
    by fastforce
  hence "ts'' = ts@[typeof v]"
    using b_e_type_value
    by blast
  hence "ts = ts'"
    using ts''_def assms(3) b_e_type_drop
    by blast
  hence "𝒞  [] : (ts _> ts')"
    using b_e_type_empty
    by simp
  thus ?thesis
    using e_typing_s_typing.intros(1)
    by fastforce
qed

lemma types_preserved_select:
  assumes "[$C v1, $C v2, $C vn, $e]  [$C v3]"
          "𝒮𝒞  [$C v1, $C v2, $C vn, $e] : (ts _> ts')"
          "(e = Select)"
  shows "𝒮𝒞  [$C v3] : (ts _> ts')"
proof -
  have "𝒞  [C v1, C v2, C vn, e] : (ts _> ts')"
    using unlift_b_e assms(2)
    by simp
  then obtain t1s where t1s_def:"𝒞  [C v1, C v2, C vn] : (ts _> t1s)" "𝒞  [e] : (t1s _> ts')"
    using b_e_type_comp[where ?e = e and ?es = "[C v1, C v2, C vn]"]
    by fastforce
  then obtain t2s t where t2s_def:"t1s = t2s @ [t, t, (T_i32)]" "ts' = t2s@[t]"
    using b_e_type_select[of 𝒞 e t1s] assms
    by fastforce
  hence "𝒞  [C v1, C v2] : (ts _> t2s@[t,t])"
    using t1s_def t2s_def b_e_type_value_list[of 𝒞 "[C v1, C v2]" "vn" ts "t2s@[t,t]"]
    by fastforce
  hence v2_t_def:"𝒞  [C v1] : (ts _> t2s@[t])" "typeof v2 = t"
    using t1s_def t2s_def b_e_type_value_list[of 𝒞 "[C v1]" "v2" ts "t2s@[t]"]
    by fastforce+
  hence v1_t_def:"ts = t2s" "typeof v1 = t"
    using b_e_type_value
    by fastforce+
  have "typeof v3 = t"
    using assms(1) v2_t_def(2) v1_t_def(2)
    by (cases rule: reduce_simple.cases, simp_all)
  hence "𝒞  [C v3] : (ts _> ts')"
    using b_e_typing.const b_e_typing.weakening t2s_def(2) v1_t_def(1)
    by fastforce
  thus ?thesis
    using e_typing_s_typing.intros(1)
    by fastforce
qed

lemma types_preserved_block:
  assumes "vs @ [$Block (tn _> tm) es]  [Label m [] (vs @ ($* es))]"
          "𝒮𝒞  vs @ [$Block (tn _> tm) es] : (ts _> ts')"
          "const_list vs"
          "length vs = n"
          "length tn = n"
          "length tm = m"
  shows "𝒮𝒞  [Label m [] (vs @ ($* es))] : (ts _> ts')"
proof -
  obtain 𝒞' where c_def:"𝒞' = 𝒞label := [tm] @ label 𝒞" by blast
  obtain ts'' where ts''_def:"𝒮𝒞  vs : (ts _> ts'')" "𝒮𝒞  [$Block (tn _> tm) es] : (ts'' _> ts')"
    using assms(2) e_type_comp[of 𝒮 𝒞 vs "$Block (tn _> tm) es" ts ts']
    by fastforce
  hence "𝒞  [Block (tn _> tm) es] : (ts'' _> ts')"
    using unlift_b_e
    by auto
  then obtain ts_c tfn tfm where ts_c_def:"(tn _> tm) = (tfn _> tfm)" "ts'' = ts_c@tfn" "ts' = ts_c@tfm" " (𝒞label := [tfm] @ label 𝒞  es : (tn _> tm))"
    using b_e_type_block[of 𝒞 "Block (tn _> tm) es" ts'' ts' "(tn _> tm)" es]
    by fastforce
  hence tfn_l:"length tfn = n"
    using assms(5)
    by simp
  obtain tvs' where tvs'_def:"ts'' = ts@tvs'" "length tvs' = n" "𝒮𝒞'  vs : ([] _> tvs')"
    using e_type_const_list assms(3,4) ts''_def(1)
    by fastforce
  hence "𝒮𝒞'  vs : ([] _> tn)" "𝒮𝒞'  $*es : (tn _> tm)"
    using ts_c_def tvs'_def tfn_l ts''_def c_def e_typing_s_typing.intros(1)
    by simp_all
  hence "𝒮𝒞'  (vs @ ($* es)) : ([] _> tm)" using e_type_comp_conc
    by simp
  moreover
  have "𝒮𝒞  [] : (tm _> tm)"
    using b_e_type_empty[of 𝒞 "[]" "[]"]
          e_typing_s_typing.intros(1)[where ?b_es = "[]"]
          e_typing_s_typing.intros(3)[of 𝒮 𝒞 "[]" "[]" "[]" "tm"]
    by fastforce
  ultimately
  show ?thesis
    using e_typing_s_typing.intros(7)[of 𝒮 𝒞 "[]" tm _ "vs @ ($* es)" m]
          ts_c_def tvs'_def assms(5,6) e_typing_s_typing.intros(3) c_def
    by fastforce
qed

lemma types_preserved_if:
  assumes "[$C ConstInt32 n, $If tf e1s e2s]  [$Block tf es']"
          "𝒮𝒞  [$C ConstInt32 n, $If tf e1s e2s] : (ts _> ts')"
  shows   "𝒮𝒞  [$Block tf es'] : (ts _> ts')"
proof -
  have "𝒞  [C ConstInt32 n, If tf e1s e2s] : (ts _> ts')"
    using unlift_b_e assms(2)
    by fastforce
  then obtain ts_i where ts_i_def:"𝒞  [C ConstInt32 n] : (ts _> ts_i)" "𝒞  [If tf e1s e2s] : (ts_i _> ts')"
    using b_e_type_comp
    by (metis append_Cons append_Nil)
  then obtain ts'' tfn tfm where ts_def:"tf = (tfn _> tfm)"
                                        "ts_i = ts''@tfn @ [T_i32]"
                                        "ts' = ts''@tfm"
                                        "(𝒞label := [tfm] @ label 𝒞  e1s : tf)"
                                        "(𝒞label := [tfm] @ label 𝒞  e2s : tf)"
    using b_e_type_if[of 𝒞 "If tf e1s e2s"]
    by fastforce
  have "ts_i = ts @ [(T_i32)]"
    using ts_i_def(1) b_e_type_value
    unfolding typeof_def
    by fastforce
  moreover
  have "(𝒞label := [tfm] @ label 𝒞  es' : (tfn _> tfm))"
    using assms(1) ts_def(4,5) ts_def(1)
    by (cases rule: reduce_simple.cases, simp_all)
  hence "𝒞  [Block tf es'] : (tfn _> tfm)"
    using ts_def(1) b_e_typing.block[of tf tfn tfm 𝒞 es']
    by simp
  ultimately
  show ?thesis
    using ts_def(2,3) e_typing_s_typing.intros(1,3)
    by fastforce
qed

lemma types_preserved_tee_local:
  assumes "[v, $Tee_local i]  [v, v, $Set_local i]"
          "𝒮𝒞  [v, $Tee_local i] : (ts _> ts')"
          "is_const v"
  shows   "𝒮𝒞  [v, v, $Set_local i] : (ts _> ts')"
proof -
  obtain bv where bv_def:"v = $C bv"
    using e_type_const_unwrap assms(3)
    by fastforce
  hence "𝒞  [C bv, Tee_local i] : (ts _> ts')"
    using unlift_b_e assms(2)
    by fastforce
  then obtain ts'' where ts''_def:"𝒞  [C bv] : (ts _> ts'')" "𝒞  [Tee_local i] : (ts'' _> ts')"
    using b_e_type_comp[of _ "[C bv]" "Tee_local i"]
    by fastforce
  then obtain ts_c t where ts_c_def:"ts'' = ts_c@[t]" "ts' = ts_c@[t]" "(local 𝒞)!i = t" "i < length(local 𝒞)"
    using b_e_type_tee_local[of 𝒞 "Tee_local i" ts'' ts' i]
    by fastforce
  hence t_bv:"t = typeof bv" "ts = ts_c"
    using b_e_type_value ts''_def
    by fastforce+
  have "𝒞  [Set_local i] : ([t,t] _> [t])"
    using ts_c_def(3,4) b_e_typing.set_local[of i 𝒞 t]
          b_e_typing.weakening[of 𝒞 "[Set_local i]" "[t]" "[]" "[t]"]
    by fastforce
  moreover
  have "𝒞  [C bv] : ([t] _> [t,t])"
    using t_bv b_e_typing.const[of 𝒞 bv]  b_e_typing.weakening[of 𝒞 "[C bv]" "[]" "[t]" "[t]"]
    by fastforce
  hence "𝒞  [C bv, C bv] : ([] _> [t,t])"
    using t_bv b_e_typing.const[of 𝒞 bv]  b_e_typing.composition[of 𝒞 "[C bv]" "[]" "[t]"]
    by fastforce
  ultimately
  have "𝒞  [C bv, C bv, Set_local i] : (ts _> ts@[t])"
    using b_e_typing.composition b_e_typing.weakening[of 𝒞 "[C bv, C bv, Set_local i]"]
    by fastforce
  thus ?thesis
    using t_bv(2) ts_c_def(2) bv_def e_typing_s_typing.intros(1)
    by fastforce
qed

lemma types_preserved_loop:
  assumes "vs @ [$Loop (t1s _> t2s) es]  [Label n [$Loop (t1s _> t2s) es] (vs @ ($* es))]"
          "𝒮𝒞  vs @ [$Loop (t1s _> t2s) es] : (ts _> ts')"
          "const_list vs"
          "length vs = n"
          "length t1s = n"
          "length t2s = m"
  shows "𝒮𝒞  [Label n [$Loop (t1s _> t2s) es] (vs @ ($* es))] : (ts _> ts')"
proof -
  obtain ts'' where ts''_def:"𝒮𝒞  vs : (ts _> ts'')" "𝒮𝒞  [$Loop (t1s _> t2s) es] : (ts'' _> ts')"
    using assms(2) e_type_comp
    by fastforce
  then have "𝒞  [Loop (t1s _> t2s) es] : (ts'' _> ts')"
    using unlift_b_e assms(2)
    by fastforce
  then obtain ts_c tfn tfm 𝒞' where t_loop:"(t1s _> t2s) = (tfn _> tfm)"
                                           "(ts'' = ts_c@tfn)"
                                           "(ts' = ts_c@tfm)"
                                           "𝒞' = 𝒞label := [t1s] @ label 𝒞"
                                           "(𝒞'  es : (tfn _> tfm))"
    using b_e_type_loop[of 𝒞 "Loop (t1s _> t2s) es" ts'' ts']
    by fastforce
  obtain tvs where tvs_def:"ts'' = ts @ tvs" "length vs = length tvs" "𝒮𝒞'  vs : ([] _> tvs)"
    using e_type_const_list assms(3) ts''_def(1)
    by fastforce
  then have tvs_eq:"tvs = t1s" "tfn = t1s"
    using assms(4,5) t_loop(1,2)
    by simp_all
  have "𝒮𝒞  [$Loop (t1s _> t2s) es] : (t1s _> t2s)"
    using t_loop b_e_typing.loop e_typing_s_typing.intros(1)
    by fastforce
  moreover
  have "𝒮𝒞'  $*es : (t1s _> t2s)"
    using t_loop e_typing_s_typing.intros(1)
    by fastforce
  then have "𝒮𝒞'  vs@($*es) : ([] _> t2s)"
    using tvs_eq tvs_def(3) e_type_comp_conc
    by blast
  ultimately
  have "𝒮𝒞  [Label n [$Loop (t1s _> t2s) es] (vs @ ($* es))] : ([] _> t2s)"
    using e_typing_s_typing.intros(7)[of 𝒮 𝒞 "[$Loop (t1s _> t2s) es]" t1s t2s "vs @ ($* es)"]
          t_loop(4) assms(5)
    by fastforce
  then show ?thesis
    using t_loop e_typing_s_typing.intros(3) tvs_def(1) tvs_eq(1)
    by fastforce
qed

lemma types_preserved_label_value:
  assumes "[Label n es0 vs]  vs"
          "𝒮𝒞  [Label n es0 vs] : (ts _> ts')"
          "const_list vs"
  shows "𝒮𝒞  vs : (ts _> ts')"
proof -
  obtain tls t2s where t2s_def:"(ts' = (ts@t2s))"
                           "(𝒮𝒞  es0 : (tls _> t2s))"
                           "(𝒮𝒞label := [tls] @ (label 𝒞)  vs : ([] _> t2s))"
    using assms e_type_label
    by fastforce
  thus ?thesis
    using e_type_const_list[of vs 𝒮 "𝒞label := [tls] @ (label 𝒞)" "[]" t2s]
          assms(3) e_typing_s_typing.intros(3)
    by fastforce
qed

lemma types_preserved_br_if:
  assumes "[$C ConstInt32 n, $Br_if i]  e"
          "𝒮𝒞  [$C ConstInt32 n, $Br_if i] : (ts _> ts')"
          "e = [$Br i]  e = []"
  shows   "𝒮𝒞  e : (ts _> ts')"
proof -
  have "𝒞  [C ConstInt32 n, Br_if i] : (ts _> ts')"
    using unlift_b_e assms(2)
    by fastforce
  then obtain ts'' where ts''_def:"𝒞  [C ConstInt32 n] : (ts _> ts'')" "𝒞  [Br_if i] : (ts'' _> ts')"
  using b_e_type_comp[of _ "[C ConstInt32 n]" "Br_if i"]
  by fastforce
  then obtain ts_c ts_b where ts_bc_def:"i < length(label 𝒞)"
                                        "ts'' = ts_c @ ts_b @ [T_i32]"
                                        "ts' = ts_c @ ts_b"
                                        "(label 𝒞)!i = ts_b"
    using b_e_type_br_if[of 𝒞 "Br_if i" ts'' ts' i]
    by fastforce
  hence ts_def:"ts = ts_c @ ts_b"
    using ts''_def(1) b_e_type_value
    by fastforce
  show ?thesis
    using assms(3)
  proof (rule disjE)
    assume "e = [$Br i]"
    thus ?thesis
      using ts_def e_typing_s_typing.intros(1) b_e_typing.br ts_bc_def
      by fastforce
  next
    assume "e = []"
    thus ?thesis
      using ts_def b_e_type_empty ts_bc_def(3)
      e_typing_s_typing.intros(1)[of _ "[]" "(ts _> ts')"]
      by fastforce
  qed
qed

lemma types_preserved_br_table:
  assumes "[$C ConstInt32 c, $Br_table is i]  [$Br i']"
          "𝒮𝒞  [$C ConstInt32 c, $Br_table is i] : (ts _> ts')"
          "(i' = (is ! nat_of_int c)  length is > nat_of_int c)  i' = i"
  shows "𝒮𝒞  [$Br i'] : (ts _> ts')"
proof -
  have "𝒞  [C ConstInt32 c, Br_table is i] : (ts _> ts')"
    using unlift_b_e assms(2)
    by fastforce
  then obtain ts'' where ts''_def:"𝒞  [C ConstInt32 c] : (ts _> ts'')" "𝒞  [Br_table is i] : (ts'' _> ts')"
    using b_e_type_comp[of _ "[C ConstInt32 c]" "Br_table is i"]
    by fastforce
  then obtain ts_l ts_c where ts_c_def:"list_all (λi. i < length(label 𝒞)  (label 𝒞)!i = ts_l) (is@[i])"
                                       "ts'' = ts_c @ ts_l@[T_i32]"
    using b_e_type_br_table[of 𝒞 "Br_table is i" ts'' ts']
    by fastforce
  hence ts_def:"ts = ts_c @ ts_l"
    using ts''_def(1) b_e_type_value
    by fastforce
  have "𝒞  [Br i'] : (ts _> ts')"
    using assms(3) ts_c_def(1,2) b_e_typing.br[of i' 𝒞 ts_l ts_c ts'] ts_def
    unfolding list_all_length
    by (fastforce simp add: less_Suc_eq nth_append)
  thus ?thesis
    using e_typing_s_typing.intros(1)
    by fastforce
qed

lemma types_preserved_local_const:
  assumes "[Local n i vs es]  es"
          "𝒮𝒞  [Local n i vs es] : (ts _> ts')"
          "const_list es"
  shows "𝒮𝒞  es: (ts _> ts')"
proof -
  obtain tls where "(𝒮((s_inst 𝒮)!i)local := (local ((s_inst 𝒮)!i)) @ (map typeof vs), return := Some tls  es : ([] _> tls))"
                   "ts' = ts @ tls"
    using e_type_local[OF assms(2)]
    by blast+
  moreover
  then have "𝒮𝒞  es : ([] _> tls)"
    using assms(3) e_type_const_list
    by fastforce
  ultimately
  show ?thesis
    using e_typing_s_typing.intros(3)
    by fastforce
qed

lemma typing_map_typeof:
  assumes "ves = $$* vs"
          "𝒮𝒞  ves : ([] _> tvs)"
  shows "tvs = map typeof vs"
  using assms
proof (induction ves arbitrary: vs tvs rule: List.rev_induct)
  case Nil
  hence "𝒞  [] : ([] _> tvs)"
    using unlift_b_e
    by auto
  thus ?case
    using Nil
    by auto
next
  case (snoc a ves)
  obtain vs' v' where vs'_def:"ves @ [a] = $$* (vs'@[v'])" "vs = vs'@[v']"
    using snoc(2)
    by (metis Nil_is_map_conv append_is_Nil_conv list.distinct(1) rev_exhaust)
  obtain tvs' where tvs'_def:"𝒮𝒞  ves: ([] _> tvs')" "𝒮𝒞  [a] : (tvs' _> tvs)"
    using snoc(3) e_type_comp
    by fastforce
  hence "tvs' = map typeof vs'"
    using snoc(1) vs'_def
    by fastforce
  moreover
  have "is_const a"
    using vs'_def
    unfolding is_const_def
    by auto
  then obtain t where t_def:"tvs = tvs' @ [t]" "𝒮𝒞  [a] : ([] _> [t])"
    using tvs'_def(2)  e_type_const[of a 𝒮 𝒞 tvs' tvs]
    by fastforce
  have "a = $ C v'"
    using vs'_def(1)
    by auto
  hence "t = typeof v'"
    using t_def unlift_b_e[of 𝒮 𝒞 "[C v']" "([] _> [t])"] b_e_type_value[of 𝒞 "C v'" "[]" "[t]" v']
    by fastforce
  ultimately
  show ?case
    using vs'_def t_def
    by simp
qed

lemma types_preserved_call_indirect_Some:
  assumes "𝒮𝒞  [$C ConstInt32 c, $Call_indirect j] : (ts _> ts')"
          "stab s i' (nat_of_int c) = Some cl"
          "stypes s i' j = tf"
          "cl_type cl = tf"
          "store_typing s 𝒮"
          "i' < length (inst s)"
          "𝒞 = (s_inst 𝒮 ! i') local := local (s_inst 𝒮 ! i') @ tvs, label := arb_labs, return := arb_return"
  shows "𝒮𝒞  [Callcl cl] : (ts _> ts')"
proof -
  obtain t1s t2s where tf_def:"tf = (t1s _> t2s)"
    using tf.exhaust by blast
  obtain ts'' where ts''_def:"𝒞  [C ConstInt32 c] : (ts _> ts'')"
                             "𝒞  [Call_indirect j] : (ts'' _> ts')"
    using e_type_comp[of 𝒮 𝒞 "[$C ConstInt32 c]" "$Call_indirect j" ts ts']
          assms(1)
          unlift_b_e[of 𝒮 𝒞 "[C ConstInt32 c]"]
          unlift_b_e[of 𝒮 𝒞 "[Call_indirect j]"]
    by fastforce
  hence "ts'' = ts@[(T_i32)]"
    using b_e_type_value
    unfolding typeof_def
    by fastforce
  moreover
  have "i' < length (s_inst 𝒮)"
    using assms(5,6) store_typing_imp_inst_length_eq
    by fastforce
  hence stypes_eq:"types_t (s_inst 𝒮 ! i') = types (inst s ! i')"
    using store_typing_imp_inst_typing[OF assms(5)] store_typing_imp_inst_length_eq[OF assms(5)]
    unfolding inst_typing.simps
    by fastforce
  obtain ts''a where ts''a_def:"j < length (types_t 𝒞)"
                               "ts'' = ts''a @ t1s @ [T_i32]"
                               "ts' = ts''a @ t2s"
                               "types_t 𝒞 ! j = (t1s _> t2s)"
    using b_e_type_call_indirect[OF ts''_def(2), of j] tf_def assms(3,7) stypes_eq
    unfolding stypes_def
    by fastforce
  moreover
  obtain tf' where tf'_def:"cl_typing 𝒮 cl tf'"
    using assms(2,5,6) stab_typed_some_imp_cl_typed
    by blast
  hence "cl_typing 𝒮 cl tf"
    using assms(4)
    unfolding cl_typing.simps cl_type_def
    by auto
  hence "𝒮𝒞  [Callcl cl] : tf"
    using e_typing_s_typing.intros(6) assms(6,7) ts''a_def(1)
    by fastforce
  ultimately
  show "𝒮𝒞  [Callcl cl] : (ts _> ts')"
    using tf_def e_typing_s_typing.intros(3)
    by auto
qed

lemma types_preserved_call_indirect_None:
  assumes "𝒮𝒞  [$C ConstInt32 c, $Call_indirect j] : (ts _> ts')"
  shows "𝒮𝒞  [Trap] : (ts _> ts')"
  using e_typing_s_typing.intros(4)
  by blast

lemma types_preserved_callcl_native:
  assumes "𝒮𝒞  ves @ [Callcl cl] : (ts _> ts')"
          "cl = Func_native i (t1s _> t2s) tfs es"
          "ves = $$* vs"
          "length vs = n"
          "length tfs = k"
          "length t1s = n"
          "length t2s = m"
          "n_zeros tfs = zs"
          "store_typing s 𝒮"
  shows "𝒮𝒞  [Local m i (vs @ zs) [$Block ([] _> t2s) es]] : (ts _> ts')"
proof -
  obtain ts'' where ts''_def:"𝒮𝒞  ves : (ts _> ts'')" "𝒮𝒞  [Callcl cl] : (ts'' _> ts')"
  using assms(1) e_type_comp
  by fastforce
  have ves_c:"const_list ves"
    using is_const_list[OF assms(3)]
    by simp
  then obtain tvs where tvs_def:"ts'' = ts @ tvs"
                                "length t1s = length tvs"
                                "𝒮𝒞  ves : ([] _> tvs)"
    using ts''_def(1) e_type_const_list[of ves 𝒮 𝒞 ts ts''] assms
    by fastforce    
  obtain ts_c 𝒞' where ts_c_def:"(ts'' = ts_c @ t1s)"
                                "(ts' = ts_c @ t2s)"
                                "i < length (s_inst 𝒮)"
                                "𝒞' = ((s_inst 𝒮)!i)"
                                "(𝒞'local := (local 𝒞') @ t1s @ tfs, label := ([t2s] @ (label 𝒞')), return := Some t2s   es : ([] _> t2s))"
    using e_type_callcl_native[OF ts''_def(2) assms(2)]
    by fastforce
  have "inst_typing 𝒮 (inst s ! i) (s_inst 𝒮 ! i)"
    using store_typing_imp_inst_length_eq[OF assms(9)] store_typing_imp_inst_typing[OF assms(9)]
          ts_c_def(3)
    by simp
  obtain 𝒞'' where c''_def:"𝒞'' = 𝒞'local := (local 𝒞') @ t1s @ tfs, return := Some t2s"
    by blast
  hence "𝒞''label := ([t2s] @ (label 𝒞''))  = 𝒞'local := (local 𝒞') @ t1s @ tfs, label := ([t2s] @ (label 𝒞')), return := Some t2s"
    by fastforce
  hence "𝒮𝒞''  [$Block ([] _> t2s) es] : ([] _> t2s)"
    using ts_c_def b_e_typing.block[of "([] _> t2s)" "[]" "t2s" _ es] e_typing_s_typing.intros(1)[of _ "[Block ([] _> t2s) es]"]
    by fastforce
  moreover
  have t_eqs:"ts = ts_c" "t1s = tvs"
    using tvs_def(1,2) ts_c_def(1)
    by simp_all
  have 1:"tfs = map typeof zs"
    using n_zeros_typeof assms(8)
    by auto
  have "t1s = map typeof vs"
    using typing_map_typeof assms(3) tvs_def t_eqs
    by fastforce
  hence "(t1s @ tfs) = map typeof (vs @ zs)"
    using 1
    by simp
  ultimately
  have "𝒮Some t2s ⊩_i (vs @ zs);([$Block ([] _> t2s) es]) : t2s"
    using e_typing_s_typing.intros(8) ts_c_def c''_def
    by fastforce
  thus ?thesis
    using e_typing_s_typing.intros(3,5) ts_c_def t_eqs(1) assms(2,7)
    by fastforce
qed

lemma types_preserved_callcl_host_some:
  assumes "𝒮𝒞  ves @ [Callcl cl] : (ts _> ts')"
          "cl = Func_host (t1s _> t2s) f"
          "ves = $$* vcs"
          "length vcs = n"
          "length t1s = n"
          "length t2s = m"
          "host_apply s (t1s _> t2s) f vcs hs = Some (s', vcs')"
          "store_typing s 𝒮"
  shows "𝒮𝒞  $$* vcs' : (ts _> ts')"
proof -
  obtain ts'' where ts''_def:"𝒮𝒞  ves : (ts _> ts'')" "𝒮𝒞  [Callcl cl] : (ts'' _> ts')"
  using assms(1) e_type_comp
  by fastforce
  have ves_c:"const_list ves"
    using is_const_list[OF assms(3)]
    by simp
  then obtain tvs where tvs_def:"ts'' = ts @ tvs"
                                "length t1s = length tvs"
                                "𝒮𝒞  ves : ([] _> tvs)"
    using ts''_def(1) e_type_const_list[of ves 𝒮 𝒞 ts ts''] assms
    by fastforce
  hence "ts'' = ts @ t1s"
        "ts' = ts @ t2s"
    using e_type_callcl_host[OF ts''_def(2) assms(2)]
    by auto
  moreover
  hence "list_all2 types_agree t1s vcs"
    using e_typing_imp_list_types_agree[where ?ts' = "[]"] assms(3) tvs_def(1,3)
    by fastforce
  hence "𝒮𝒞  $$* vcs' : ([] _> t2s)"
    using list_types_agree_imp_e_typing host_apply_respect_type[OF _ assms(7)]
    by fastforce
  ultimately
  show ?thesis
    using e_typing_s_typing.intros(3)
    by fastforce
qed

lemma types_imp_concat:
  assumes "𝒮𝒞  es @ [e] @ es' : (ts _> ts')"
          "tes tes'. ((𝒮𝒞  [e] : (tes _> tes'))  (𝒮𝒞  [e'] : (tes _> tes')))"
  shows "𝒮𝒞  es @ [e'] @ es' : (ts _> ts')"
proof -
  obtain ts'' where "𝒮𝒞  es : (ts _> ts'')"
                    "𝒮𝒞  [e] @ es' : (ts'' _> ts')"
    using e_type_comp_conc1[of _ _ es "[e] @ es'"] assms(1)
    by fastforce
  moreover
  then obtain ts''' where "𝒮𝒞  [e] : (ts'' _> ts''')" "𝒮𝒞  es' : (ts''' _> ts')"
    using e_type_comp_conc1[of _ _ "[e]" es' ts'' ts'] assms
    by fastforce
  ultimately
  show ?thesis
    using assms(2) e_type_comp_conc[of _ _ es ts ts'' "[e']" ts''']
                   e_type_comp_conc[of _ _ "es @ [e']" ts ts''']
    by fastforce
qed

lemma type_const_return:
  assumes "Lfilled i lholed (vs @ [$Return]) LI"
          "(return 𝒞) = Some tcs"
          "length tcs = length vs"
          "𝒮𝒞  LI : (ts _> ts')"
          "const_list vs"
  shows "𝒮𝒞'  vs : ([] _> tcs)"
  using assms
proof (induction i arbitrary: ts ts' lholed 𝒞 LI 𝒞')
  case 0
  obtain vs' es' where "LI = (vs' @ (vs @ [$Return]) @ es')"
    using Lfilled.simps[of 0 lholed "(vs @ [$Return])" LI] 0(1)
    by fastforce
  then obtain ts'' ts''' where "𝒮𝒞  vs' : (ts _> ts'')"
                               "𝒮𝒞  (vs @ [$Return]) : (ts'' _> ts''')"
                               "𝒮𝒞  es' : (ts''' _> ts')"
    using e_type_comp_conc2[of 𝒮 𝒞 vs' "(vs @ [$Return])" es'] 0(4)
    by fastforce
  then obtain ts_b where ts_b_def:"𝒮𝒞  vs : (ts'' _> ts_b)" "𝒮𝒞  [$Return] : (ts_b _> ts''')"
    using e_type_comp_conc1
    by fastforce
  then obtain ts_c where ts_c_def:"ts_b = ts_c @ tcs" "(return 𝒞) = Some tcs"
    using 0(2) b_e_type_return[of 𝒞] unlift_b_e[of 𝒮 𝒞 "[Return]" "ts_b _> ts'''"]
    by fastforce
  obtain tcs' where "ts_b = ts'' @ tcs'" "length vs = length tcs'" "𝒮𝒞'  vs : ([] _> tcs')"
    using ts_b_def(1) e_type_const_list 0(5)
    by fastforce
  thus ?case
    using 0(3) ts_c_def
    by simp
next
  case (Suc i)
  obtain vs' n l les les' LK where es_def:"lholed = (LRec vs' n les l les')"
                                           "Lfilled i l (vs @ [$Return]) LK"
                                           "LI = (vs' @ [Label n les LK] @ les')"
    using Lfilled.simps[of "(Suc i)" lholed "(vs @ [$Return])" LI] Suc(2)
    by fastforce
  then obtain ts'' ts''' where "𝒮𝒞  [Label n les LK] : (ts'' _> ts''')"
    using e_type_comp_conc2[of 𝒮 𝒞 vs' "[Label n les LK]" les'] Suc(5)
    by fastforce
  then obtain tls t2s where
       "ts''' = ts'' @ t2s"
       "length tls = n"
       "𝒮𝒞  les : (tls _> t2s)"
       "𝒮𝒞label := [tls] @ label 𝒞  LK : ([] _> t2s)"
       "return (𝒞label := [tls] @ label 𝒞) = Some tcs"
    using e_type_label[of 𝒮 𝒞 n les LK ts'' ts'''] Suc(3)
    by fastforce
  then show ?case
    using Suc(1)[OF es_def(2) _ assms(3) _ assms(5)]
    by fastforce
qed

lemma types_preserved_return:
  assumes "[Local n i vls LI]  ves"
          "𝒮𝒞  [Local n i vls LI] : (ts _> ts')"
          "const_list ves"
          "length ves = n"
          "Lfilled j lholed (ves @ [$Return]) LI"
  shows "𝒮𝒞  ves : (ts _> ts')"
proof -
  obtain tls 𝒞' where l_def:"i < length (s_inst 𝒮)"
                        "𝒞' = ((s_inst 𝒮)!i)local := (local ((s_inst 𝒮)!i)) @ (map typeof vls), return := Some tls"
                        "𝒮𝒞'  LI : ([] _> tls)"
                        "ts' = ts @ tls"
                        "length tls = n"
    using e_type_local[OF assms(2)]
    by blast
  hence "𝒮𝒞  ves : ([] _> tls)"
    using type_const_return[OF assms(5) _ _ l_def(3)] assms(3-5)
    by fastforce
  thus ?thesis
    using e_typing_s_typing.intros(3) l_def(4)
    by fastforce
qed

lemma type_const_br:
  assumes "Lfilled i lholed (vs @ [$Br (i+k)]) LI"
          "length (label 𝒞) > k"
          "(label 𝒞)!k = tcs"
          "length tcs = length vs"
          "𝒮𝒞  LI : (ts _> ts')"
          "const_list vs"
  shows "𝒮𝒞'  vs : ([] _> tcs)"
  using assms
proof (induction i arbitrary: k ts ts' lholed 𝒞 LI 𝒞')
  case 0
  obtain vs' es' where "LI = (vs' @ (vs @ [$Br (0+k)]) @ es')"
    using Lfilled.simps[of 0 lholed "(vs @ [$Br (0 + k)])" LI] 0(1)
    by fastforce
  then obtain ts'' ts''' where "𝒮𝒞  vs' : (ts _> ts'')"
                               "𝒮𝒞  (vs @ [$Br (0+k)]) : (ts'' _> ts''')"
                               "𝒮𝒞  es' : (ts''' _> ts')"
    using e_type_comp_conc2[of 𝒮 𝒞 vs' "(vs @ [$Br (0+k)])" es'] 0(5)
    by fastforce
  then obtain ts_b where ts_b_def:"𝒮𝒞  vs : (ts'' _> ts_b)" "𝒮𝒞  [$Br (0+k)] : (ts_b _> ts''')"
    using e_type_comp_conc1
    by fastforce
  then obtain ts_c where ts_c_def:"ts_b = ts_c @ tcs" "(label 𝒞)!k = tcs"
    using 0(3) b_e_type_br[of 𝒞 "Br (0 + k)"] unlift_b_e[of 𝒮 𝒞 "[Br (0 + k)]" "ts_b _> ts'''"]
    by fastforce
  obtain tcs' where "ts_b = ts'' @ tcs'" "length vs = length tcs'" "𝒮𝒞'  vs : ([] _> tcs')"
    using ts_b_def(1) e_type_const_list 0(6)
    by fastforce
  thus ?case
    using 0(4) ts_c_def
    by simp
next
  case (Suc i k ts ts' lholed 𝒞 LI)
  obtain vs' n l les les' LK where es_def:"lholed = (LRec vs' n les l les')"
                                           "Lfilled i l (vs @ [$Br (i + (Suc k))]) LK"
                                           "LI = (vs' @ [Label n les LK] @ les')"