Theory ContextSubtypingL

(*<*)
theory ContextSubtypingL
  imports TypingL "HOL-Eisbach.Eisbach_Tools" SubstMethods
begin
  (*>*)

declare freshers[simp del]

chapter ‹Context Subtyping  Lemmas›

text ‹Lemmas allowing us to replace the type of a variable in the context with a subtype
and have the judgement remain valid. Also known as narrowing.›

section ‹Replace or exchange type of variable in a context›

text ‹ Because the G-context is extended by the statements like let, we will need a generalised 
substitution lemma for statements. 
For this we setup a function that replaces in G (rig) for a particular x the constraint for it.
We also define a well-formedness relation for RIGs that ensures that each new constraint 
implies the old one›

nominal_function replace_in_g_many :: "Γ  (x*c) list  Γ" where
  "replace_in_g_many G xcs = List.foldr (λ(x,c) G. G[x  c]) xcs G"
  by(auto,simp add: eqvt_def replace_in_g_many_graph_aux_def)
nominal_termination (eqvt)  by lexicographic_order

inductive replace_in_g_subtyped :: "Θ    Γ  (x*c) list  Γ  bool" (" _ ; _   _  _   _" [100,50,50] 50) where
  replace_in_g_subtyped_nilI: "Θ;   G  []   G"
| replace_in_g_subtyped_consI:  " 
       Some (b,c') = lookup G x ; 
        Θ; ; G wf c ;
       Θ; ; G[xc]  c' ; 
       Θ;   G[xc]  xcs   G'; x  fst ` set xcs    
       Θ;   G  (x,c)#xcs   G'" 
equivariance replace_in_g_subtyped
nominal_inductive replace_in_g_subtyped .

inductive_cases replace_in_g_subtyped_elims[elim!]:
  "Θ;   G  []   G'"
  "Θ;   ((x,b,c)#ΓΓ G)  acs   ((x,b,c)#ΓG')"
  "Θ;   G'  (x,c)# acs   G"

lemma rigs_atom_dom_eq:
  assumes "Θ;   G  xcs   G'"
  shows "atom_dom G = atom_dom G'"
  using assms proof(induct rule: replace_in_g_subtyped.induct)
  case (replace_in_g_subtyped_nilI G)
  then show ?case by simp
next
  case (replace_in_g_subtyped_consI b c' G x Θ  c xcs G')
  then show ?case using rig_dom_eq atom_dom.simps dom.simps by simp
qed

lemma replace_in_g_wfG:
  assumes "Θ;   G  xcs   G'" and  "wfG Θ  G "
  shows "wfG Θ  G'"
  using assms proof(induct rule: replace_in_g_subtyped.induct)
  case (replace_in_g_subtyped_nilI Θ G)
  then show ?case by auto
next
  case (replace_in_g_subtyped_consI b c' G x Θ c xcs G')
  then show ?case using valid_g_wf by auto
qed

lemma wfD_rig_single:
  fixes Δ::Δ and x::x and c::c and G::Γ
  assumes "Θ; ; G wf Δ " and  "wfG Θ  (G[xc])"
  shows "Θ; ; G[xc]  wf Δ" 
proof(cases "atom x  atom_dom G")
  case False
  hence "(G[xc]) = G" using assms replace_in_g_forget wfX_wfY by metis
  then show ?thesis using assms by auto
next
  case True
  then obtain G1 G2 b c' where *: "G=G1@(x,b,c')#ΓG2" using split_G by fastforce
  hence **: "(G[xc]) = G1@(x,b,c)#ΓG2" using replace_in_g_inside wfD_wf  assms wfD_wf by metis

  hence "wfG Θ  ((x,b,c)#ΓG2)" using wfG_suffix assms by auto
  hence "Θ; ; (x, b, TRUE) #Γ G2  wf c" using wfG_elim2 by auto

  thus ?thesis using wf_replace_inside1 assms * ** 
    by (simp add: wf_replace_inside2(6))
qed

lemma wfD_rig:
  assumes  "Θ;   G  xcs   G'" and "wfD Θ  G Δ" 
  shows "wfD Θ  G' Δ" 
  using assms proof(induct rule: replace_in_g_subtyped.induct)
  case (replace_in_g_subtyped_nilI Θ G)
  then show ?case by auto
next
  case (replace_in_g_subtyped_consI b c' G x Θ c xcs G')
  then show ?case using wfD_rig_single valid.simps wfC_wf by auto
qed

lemma replace_in_g_fresh:
  fixes x::x
  assumes "Θ;   Γ  xcs   Γ'" and  "wfG Θ  Γ" and "wfG Θ  Γ'" and "atom x  Γ"
  shows "atom x  Γ'"
  using  wfG_dom_supp assms fresh_def rigs_atom_dom_eq by metis

lemma replace_in_g_fresh1:
  fixes x::x
  assumes "Θ;   Γ  xcs   Γ'" and  "wfG Θ  Γ" and "atom x  Γ"
  shows "atom x  Γ'"
proof -
  have  "wfG Θ  Γ'" using  replace_in_g_wfG assms by auto
  thus ?thesis using assms replace_in_g_fresh by metis
qed

text ‹ Wellscoping for an eXchange list›

inductive wsX:: "Γ  (x*c) list  bool" where
  wsX_NilI: "wsX G []"
|  wsX_ConsI: " wsX G xcs ; atom x  atom_dom G ; x  fst ` set xcs   wsX G ((x,c)#xcs)"
equivariance wsX
nominal_inductive wsX .

lemma wsX_if1:
  assumes "wsX G xcs"
  shows "(( atom ` fst ` set xcs)  atom_dom G)  List.distinct (List.map fst xcs)"
  using assms by(induct rule: wsX.induct,force+ )

lemma wsX_if2:
  assumes  "(( atom ` fst ` set xcs)  atom_dom G)  List.distinct (List.map fst xcs)"
  shows  "wsX G xcs"
  using assms proof(induct xcs)
  case Nil
  then show ?case using wsX_NilI by fast
next
  case (Cons a xcs)
  then obtain x and c where xc: "a=(x,c)" by force
  have " wsX G xcs" proof -
    have "distinct (map fst xcs)" using Cons by force
    moreover have " atom ` fst ` set xcs  atom_dom G" using Cons by simp
    ultimately show ?thesis  using Cons by fast
  qed
  moreover have "atom x  atom_dom G" using Cons xc 
    by simp
  moreover have "x  fst ` set xcs" using Cons xc 
    by simp
  ultimately show ?case using wsX_ConsI xc by blast
qed

lemma wsX_iff:
  "wsX G xcs = ((( atom ` fst ` set xcs)  atom_dom G)  List.distinct (List.map fst xcs))"
  using wsX_if1 wsX_if2 by meson

inductive_cases wsX_elims[elim!]:
  "wsX G []"
  "wsX G ((x,c)#xcs)"

lemma wsX_cons:
  assumes  "wsX Γ xcs" and  "x  fst ` set xcs" 
  shows "wsX ((x, b, c1) #Γ Γ) ((x, c2) # xcs)" 
  using assms proof(induct Γ)
  case GNil
  then show ?case using atom_dom.simps wsX_iff by auto
next
  case (GCons xbc Γ)
  obtain x' and b' and c' where xbc: "xbc = (x',b',c')" using prod_cases3 by blast
  then have "atom ` fst ` set xcs  atom_dom (xbc #Γ Γ)  distinct (map fst xcs)"
    using GCons.prems(1) wsX_iff by blast
  then have "wsX ((x, b, c1) #Γ xbc #Γ Γ) xcs"
    by (simp add: Un_commute subset_Un_eq wsX_if2) 
  then show ?case   by (simp add: GCons.prems(2) wsX_ConsI) 
qed

lemma wsX_cons2:
  assumes  "wsX Γ xcs" and  "x  fst ` set xcs" 
  shows "wsX ((x, b, c1) #Γ Γ)  xcs" 
  using assms proof(induct Γ)
  case GNil
  then show ?case using atom_dom.simps wsX_iff by auto
next
  case (GCons xbc Γ)
  obtain x' and b' and c' where xbc: "xbc = (x',b',c')" using prod_cases3 by blast
  then have "atom ` fst ` set xcs  atom_dom (xbc #Γ Γ)  distinct (map fst xcs)"
    using GCons.prems(1) wsX_iff by blast then show ?case by (simp add: Un_commute subset_Un_eq wsX_if2) 
qed

lemma wsX_cons3:
  assumes  "wsX Γ xcs"  
  shows "wsX ((x, b, c1) #Γ Γ)  xcs" 
  using assms proof(induct Γ)
  case GNil
  then show ?case using atom_dom.simps wsX_iff by auto
next
  case (GCons xbc Γ)
  obtain x' and b' and c' where xbc: "xbc = (x',b',c')" using prod_cases3 by blast
  then have "atom ` fst ` set xcs  atom_dom (xbc #Γ Γ)  distinct (map fst xcs)"
    using GCons.prems(1) wsX_iff by blast then show ?case by (simp add: Un_commute subset_Un_eq wsX_if2) 
qed

lemma wsX_fresh:
  assumes "wsX G xcs" and "atom x  G" and "wfG Θ  G "
  shows "x  fst ` set xcs"
proof - 
  have "atom x  atom_dom G" using assms 
    using fresh_def wfG_dom_supp by auto
  thus ?thesis using wsX_iff assms by blast
qed

lemma replace_in_g_dist:
  assumes "x'  x" 
  shows "replace_in_g ((x, b,c) #Γ G) x' c'' = ((x, b,c) #Γ (replace_in_g G x' c''))" using replace_in_g.simps assms by presburger

lemma wfG_replace_inside_rig:
  fixes c''::c
  assumes Θ;  wf G[x'c''] Θ;  wf (x, b, c) #Γ G
  shows "Θ;  wf (x, b, c) #Γ G[x'c'']"
proof(rule wfG_consI)

  have "wfG Θ  G " using wfG_cons assms by auto

  show *:"Θ;  wf G[x'c'']" using assms by auto
  show "atom x  G[x'c'']" using replace_in_g_fresh_single[OF *] assms wfG_elims assms by metis
  show **:"Θ;  wf b " using wfG_elim2 assms by auto
  show "Θ; ; (x, b, TRUE) #Γ G[x'c'']  wf c "
  proof(cases "atom x'  atom_dom G")
    case True
    hence "G = G[x'c'']" using replace_in_g_forget wfG Θ  G  by auto
    thus ?thesis using assms wfG_wfC by auto
  next
    case False
    then obtain G1 G2 b' c' where **:"G=G1@(x',b',c')#ΓG2"
      using split_G by fastforce
    hence ***: "(G[x'c'']) = G1@(x',b',c'')#ΓG2"
      using replace_in_g_inside wfG Θ  G  by metis
    hence "Θ; ; (x, b, TRUE) #Γ G1@(x',b',c')#ΓG2  wf c" using * ** assms wfG_wfC by auto
    hence  "Θ; ; (x, b, TRUE) #Γ G1@(x',b',c'')#ΓG2  wf c" using * *** wf_replace_inside assms
      by (metis "**" append_g.simps(2) wfG_elim2 wfG_suffix)
    thus ?thesis using ** * *** by auto
  qed
qed

lemma replace_in_g_valid_weakening:
  assumes "Θ; ; Γ[x'c'']  c'" and "x'  x" and  "Θ;  wf (x, b, c) #Γ Γ[x'c'']"
  shows "Θ; ; ((x, b,c) #Γ Γ)[x' c'']   c'"
  apply(subst replace_in_g_dist,simp add: assms,rule valid_weakening)
  using assms by auto+

lemma replace_in_g_subtyped_cons:
  assumes "replace_in_g_subtyped Θ  G xcs G'"  and "wfG Θ  ((x,b,c)#ΓG)"
  shows "x  fst ` set xcs  replace_in_g_subtyped Θ  ((x,b,c)#ΓG) xcs ((x,b,c)#ΓG')"
  using assms proof(induct  rule: replace_in_g_subtyped.induct)
  case (replace_in_g_subtyped_nilI G)
  then show ?case 
    by (simp add: replace_in_g_subtyped.replace_in_g_subtyped_nilI)
next
  case (replace_in_g_subtyped_consI b' c' G x' Θ  c'' xcs' G')
  hence "Θ;  wf G[x'c'']" using valid.simps wfC_wf by auto

  show ?case proof(rule replace_in_g_subtyped.replace_in_g_subtyped_consI)
    show  " Some (b', c') = lookup ((x, b,c) #Γ G) x'" using lookup.simps 
        fst_conv image_iff Γ_set_intros surj_pair replace_in_g_subtyped_consI by force
    show wbc: " Θ; ; (x, b, c) #Γ G  wf c'' "  using wf_weakening Θ; ; G wf c'' Θ;   wf (x, b, c) #Γ G by fastforce
    have  "x'  x"  using replace_in_g_subtyped_consI by auto
    have wbc1: "Θ;  wf (x, b, c) #Γ G[x'c'']" proof -
      have "(x, b, c) #Γ G[x'c''] = ((x, b, c) #Γ G)[x'c'']" using x'  x using replace_in_g.simps by auto
      thus  ?thesis using wfG_replace_inside_rig Θ;  wf G[x'c'']  Θ;   wf (x, b, c) #Γ G by fastforce   
    qed
    show  *: "Θ; ; replace_in_g ((x, b,c) #Γ G) x' c''   c'" 
    proof - 
      have "Θ; ; G[x'c'']   c'" using replace_in_g_subtyped_consI by auto
      thus ?thesis using replace_in_g_valid_weakening wbc1 x'x by auto     
    qed

    show  "replace_in_g_subtyped Θ  (replace_in_g ((x, b,c) #Γ G) x' c'') xcs' ((x, b,c) #Γ G')"  
      using replace_in_g_subtyped_consI wbc1 by auto
    show  "x'  fst ` set xcs'" 
      using replace_in_g_subtyped_consI by linarith
  qed
qed

lemma replace_in_g_split:
  fixes G::Γ 
  assumes "Γ = replace_in_g Γ' x c" and "Γ' =  G'@(x,b,c')#ΓG" and "wfG Θ  Γ'"
  shows "Γ =  G'@(x,b,c)#ΓG" 
  using assms proof(induct G' arbitrary: G Γ Γ' rule: Γ_induct)
  case GNil
  then show ?case by simp
next
  case (GCons x1 b1 c1 Γ1)
  hence "x1  x"
    using wfG_cons_fresh2[of Θ  x1 b1 c1 Γ1 x b ] 
    using GCons.prems(2) GCons.prems(3) append_g.simps(2) by auto
  moreover hence *: "Θ;   wf  (Γ1 @ (x, b, c') #Γ G)" using GCons append_g.simps wfG_elims by metis
  moreover hence "replace_in_g (Γ1 @ (x, b, c') #Γ G) x c = Γ1 @ (x, b, c) #Γ G" using GCons replace_in_g_inside[OF *, of c] by auto

  ultimately  show ?case using replace_in_g.simps(2)[of x1 b1 c1 " Γ1 @ (x, b, c') #Γ G" x c] GCons
    by (simp add: GCons.prems(1) GCons.prems(2)) 
qed

lemma replace_in_g_subtyped_split0:
  fixes G::Γ 
  assumes "replace_in_g_subtyped Θ  Γ'[(x,c)] Γ" and "Γ' =  G'@(x,b,c')#ΓG"  and "wfG Θ  Γ'"
  shows "Γ =  G'@(x,b,c)#ΓG" 
proof - 
  have "Γ = replace_in_g Γ' x c" using assms replace_in_g_subtyped.simps
    by (metis Pair_inject list.distinct(1) list.inject)
  thus ?thesis using assms replace_in_g_split by blast
qed

lemma replace_in_g_subtyped_split:
  assumes "Some (b, c') = lookup G x" and "Θ; ; replace_in_g G x c   c'" and "wfG Θ  G "
  shows " Γ Γ'. G = Γ'@(x,b,c')#ΓΓ  Θ; ; Γ'@(x,b,c)#ΓΓ  c'"
proof -
  obtain Γ and Γ' where "G = Γ'@(x,b,c')#ΓΓ" using assms lookup_split by blast
  moreover hence  "replace_in_g G x c =  Γ'@(x,b,c)#ΓΓ" using replace_in_g_split assms by blast
  ultimately show ?thesis by (metis assms(2))
qed

section ‹Validity and Subtyping›

lemma wfC_replace_in_g:
  fixes c::c and c0::c
  assumes "Θ; ; Γ'@(x,b,c0')#ΓΓ wf c" and "Θ; ; (x,b,TRUE)#ΓΓ wf c0"
  shows "Θ; ; Γ' @ (x, b, c0) #Γ Γ wf c"
  using wf_replace_inside1(2) assms by auto 


lemma ctx_subtype_valid:
  assumes "Θ; ; Γ'@(x,b,c0')#ΓΓ  c" and 
    "Θ; ; Γ'@(x,b,c0)#ΓΓ  c0'"
  shows "Θ; ; Γ'@(x,b,c0)#ΓΓ  c"
proof(rule validI)
  show "Θ; ; Γ' @ (x, b, c0) #Γ Γ wf c" proof - 
    have  "Θ; ; Γ'@(x,b,c0')#ΓΓ wf c" using valid.simps assms by auto
    moreover have "Θ; ; (x,b,TRUE)#ΓΓ wf c0" proof -
      have "wfG Θ  (Γ'@(x,b,c0)#ΓΓ)" using assms valid.simps wfC_wf by auto
      hence "wfG Θ  ((x,b,c0)#ΓΓ)" using wfG_suffix by auto
      thus ?thesis using wfG_wfC by auto
    qed
    ultimately show ?thesis using assms wfC_replace_in_g by auto
  qed

  show "i. wfI Θ (Γ' @ (x, b, c0) #Γ Γ) i  is_satis_g i (Γ' @ (x, b, c0) #Γ Γ)  is_satis i c" proof(rule,rule)
    fix i
    assume * : "wfI Θ (Γ' @ (x, b, c0) #Γ Γ) i  is_satis_g i (Γ' @ (x, b, c0) #Γ Γ) "

    hence "is_satis_g i (Γ'@(x, b, c0) #Γ Γ)  wfI Θ (Γ'@(x, b, c0) #Γ Γ) i" using is_satis_g_append wfI_suffix by metis
    moreover hence "is_satis i c0'" using valid.simps assms by presburger

    moreover have "is_satis_g i Γ'"  using is_satis_g_append * by simp
    ultimately have "is_satis_g i (Γ' @ (x, b, c0') #Γ Γ) " using is_satis_g_append by simp
    moreover have "wfI Θ (Γ' @ (x, b, c0') #Γ Γ) i" using wfI_def wfI_suffix * wfI_def wfI_replace_inside by metis
    ultimately show  "is_satis i c" using assms valid.simps by metis
  qed
qed

lemma ctx_subtype_subtype:
  fixes Γ::Γ
  shows "Θ; ; G  t1  t2  G = Γ'@(x,b0,c0')#ΓΓ  Θ; ; Γ'@(x,b0,c0)#ΓΓ  c0'  Θ; ; Γ'@(x,b0,c0)#ΓΓ  t1  t2"
proof(nominal_induct avoiding: c0 rule: subtype.strong_induct)

  case (subtype_baseI x' Θ  Γ'' z c z' c' b)
  let ?Γc0 = "Γ'@(x,b0,c0)#ΓΓ" 
  have wb1:  "wfG Θ  ?Γc0" using valid.simps wfC_wf   subtype_baseI by metis
  show ?case proof
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   wf  z : b  | c  using  wfT_replace_inside2[OF _ wb1] subtype_baseI by metis
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   wf  z' : b  | c'  using  wfT_replace_inside2[OF _ wb1] subtype_baseI by metis
    have "atom x'  Γ' @ (x, b0, c0) #Γ Γ" using fresh_prodN subtype_baseI fresh_replace_inside wb1 subtype_wf wfX_wfY by metis
    thus  atom x'  (Θ, , Γ' @ (x, b0, c0) #Γ Γ,  z,  c , z' , c' )  using subtype_baseI fresh_prodN by metis
    have "Θ; ; ((x', b, c[z::=V_var x']v) #Γ Γ') @ (x, b0, c0) #Γ Γ   c'[z'::=V_var x']v " proof(rule ctx_subtype_valid)
      show 1: Θ; ; ((x', b, c[z::=V_var x']v) #Γ Γ') @ (x, b0, c0') #Γ Γ   c'[z'::=V_var x']v 
        using  subtype_baseI append_g.simps subst_defs by metis
      have *:"Θ;  wf ((x', b, c[z::=V_var x']v) #Γ Γ') @ (x, b0, c0) #Γ Γ " proof(rule wfG_replace_inside2)
        show "Θ;  wf ((x', b, c[z::=V_var x']v) #Γ Γ') @ (x, b0, c0') #Γ Γ" 
          using * valid_wf_all wfC_wf 1 append_g.simps by metis
        show "Θ;  wf (x, b0, c0) #Γ Γ" using wfG_suffix wb1 by auto
      qed
      moreover have "toSet (Γ' @ (x, b0, c0) #Γ Γ)  toSet (((x', b, c[z::=V_var x']v) #Γ Γ') @ (x, b0, c0) #Γ Γ)" using toSet.simps append_g.simps by auto
      ultimately show  Θ; ; ((x', b, c[z::=V_var x']v) #Γ Γ') @ (x, b0, c0) #Γ Γ   c0' using   valid_weakening subtype_baseI * by blast
    qed
    thus  Θ; ;  (x', b, c[z::=V_var x']v) #Γ Γ'  @ (x, b0, c0) #Γ Γ   c'[z'::=V_var x']v using append_g.simps subst_defs by simp     
  qed
qed

lemma ctx_subtype_subtype_rig:
  assumes   "replace_in_g_subtyped Θ   Γ' [(x,c0)] Γ" and  "Θ; ; Γ'  t1  t2"  
  shows "Θ; ; Γ  t1  t2"
proof -
  have wf: "wfG Θ  Γ'" using subtype_g_wf assms by auto
  obtain b and c0' where  "Some (b, c0') = lookup Γ' x  (Θ; ; replace_in_g Γ' x c0   c0')" using 
      replace_in_g_subtyped.simps[of  Θ  Γ' "[(x, c0)]" Γ] assms(1) 

    by (metis fst_conv list.inject list.set_intros(1) list.simps(15) not_Cons_self2 old.prod.exhaust prod.inject set_ConsD surj_pair)
  moreover then obtain G and G' where *: "Γ' = G'@(x,b,c0')#ΓG  Θ; ; G'@(x,b,c0)#ΓG  c0'" 
    using replace_in_g_subtyped_split[of b  c0' Γ' x Θ  c0] wf by metis

  ultimately show ?thesis using ctx_subtype_subtype 
      assms(1) assms(2) replace_in_g_subtyped_split0 subtype_g_wf  
    by (metis (no_types, lifting) local.wf replace_in_g_split)
qed

text ‹ We now prove versions of the @{text "ctx_subtype"} lemmas above using @{text "replace_in_g"}. First we do case where
the replace is just for a single variable (indicated by suffix rig) and then the general case for
multiple replacements (indicated by suffix rigs)›

lemma ctx_subtype_subtype_rigs:
  assumes "replace_in_g_subtyped Θ  Γ' xcs Γ" and  "Θ; ; Γ'  t1  t2"  
  shows "Θ; ; Γ  t1  t2"
  using assms proof(induct xcs arbitrary: Γ Γ'  )
  case Nil  
  moreover have "Γ' = Γ" using replace_in_g_subtyped_nilI 
    using calculation(1) by blast
  ultimately show ?case by auto
next
  case (Cons a xcs)

  then obtain x and c where "a=(x,c)" by fastforce
  then obtain b and c' where bc: "Some (b, c') = lookup Γ' x 
         replace_in_g_subtyped Θ   (replace_in_g Γ' x c) xcs Γ    Θ; ; Γ'  wf c  
         x  fst ` set xcs   Θ; ; (replace_in_g Γ' x c)   c' " using replace_in_g_subtyped_elims(3)[of Θ  Γ' x c xcs Γ] Cons
    by (metis valid.simps)

  hence *: "replace_in_g_subtyped Θ  Γ' [(x,c)] (replace_in_g Γ' x c)" using replace_in_g_subtyped_consI 
    by (meson image_iff list.distinct(1) list.set_cases replace_in_g_subtyped_nilI)

  hence "Θ; ; (replace_in_g Γ' x c)   t1  t2"
    using  ctx_subtype_subtype_rig * assms Cons.prems(2) by auto

  moreover have "replace_in_g_subtyped Θ  (replace_in_g Γ' x c) xcs Γ" using Cons
    using bc by blast

  ultimately show ?case using Cons by blast
qed

lemma replace_in_g_inside_valid:
  assumes "replace_in_g_subtyped Θ  Γ' [(x,c0)] Γ" and "wfG Θ  Γ'"
  shows "b c0' G G'. Γ' = G' @ (x,b,c0')#ΓG   Γ = G' @ (x,b,c0)#ΓG  Θ; ; G'@ (x,b,c0)#ΓG   c0'"
proof - 
  obtain b and c0' where  bc: "Some (b, c0') = lookup Γ' x  Θ; ; replace_in_g Γ' x c0   c0'" using 
      replace_in_g_subtyped.simps[of  Θ  Γ' "[(x, c0)]" Γ] assms(1) 
    by (metis fst_conv list.inject list.set_intros(1) list.simps(15) not_Cons_self2 old.prod.exhaust prod.inject set_ConsD surj_pair)
  then obtain G and G' where *: "Γ' = G'@(x,b,c0')#ΓG  Θ; ; G'@(x,b,c0)#ΓG  c0'" using replace_in_g_subtyped_split[of b c0' Γ' x Θ  c0] assms
    by metis
  thus ?thesis using replace_in_g_inside bc
    using assms(1) assms(2) by blast
qed

lemma replace_in_g_valid:
  assumes "Θ;    G  xcs   G'" and  "Θ; ; G   c "
  shows  Θ; ; G'   c
  using assms proof(induct rule: replace_in_g_subtyped.inducts)
  case (replace_in_g_subtyped_nilI Θ  G)
  then show ?case by auto
next
  case (replace_in_g_subtyped_consI b c1 G x Θ  c2 xcs G')
  hence "Θ; ; G[xc2]   c" 
    by (metis ctx_subtype_valid replace_in_g_split replace_in_g_subtyped_split valid_g_wf)
  then show ?case using replace_in_g_subtyped_consI by auto
qed

section ‹Literals›

section ‹Values›

lemma lookup_inside_unique_b[simp]:
  assumes "Θ ; B wf (Γ'@(x,b0,c0)#ΓΓ)" and "Θ ; B wf (Γ'@(x,b0,c0')#ΓΓ)"
    and  "Some (b, c) = lookup (Γ' @ (x, b0, c0') #Γ Γ) y" and  "Some (b0,c0) = lookup (Γ'@((x,b0,c0))#ΓΓ) x" and "x=y"
  shows "b = b0"
  by (metis assms(2) assms(3) assms(5) lookup_inside_wf old.prod.exhaust option.inject prod.inject)

lemma ctx_subtype_v_aux:
  fixes v::v
  assumes  "Θ; ; Γ'@((x,b0,c0')#ΓΓ)  v  t1" and   "Θ; ; Γ'@(x,b0,c0)#ΓΓ  c0'" 
  shows "Θ; ; Γ'@((x,b0,c0)#ΓΓ)  v  t1"
  using assms proof(nominal_induct "Γ'@((x,b0,c0')#ΓΓ)" v t1 avoiding: c0    rule: infer_v.strong_induct)
  case (infer_v_varI Θ  b c xa z)
  have  wf:Θ;   wf Γ' @ (x, b0, c0) #Γ Γ using wfG_inside_valid2 infer_v_varI by metis
  have  xf1:atom z  xa using  infer_v_varI by metis
  have  xf2: atom z  (Θ, , Γ' @ (x, b0, c0) #Γ Γ) apply( fresh_mth add:  infer_v_varI )
    using fresh_def infer_v_varI wfG_supp fresh_append_g fresh_GCons fresh_prodN by metis+
  show ?case proof (cases "x=xa")
    case True
    moreover have "b = b0" using infer_v_varI True by simp
    moreover hence  Some (b, c0) = lookup (Γ' @ (x, b0, c0) #Γ Γ) xa using   lookup_inside_wf[OF wf] infer_v_varI True by auto
    ultimately show ?thesis using  wf xf1 xf2 Typing.infer_v_varI by metis
  next
    case False
    moreover hence  Some (b, c) = lookup (Γ' @ (x, b0, c0) #Γ Γ) xa using   lookup_inside2 infer_v_varI by metis
    ultimately show ?thesis using wf xf1 xf2 Typing.infer_v_varI by simp
  qed   
next
  case (infer_v_litI Θ  l τ)
  thus ?case using Typing.infer_v_litI wfG_inside_valid2 by simp
next
  case (infer_v_pairI z v1 v2 Θ  t1' t2' c0)
  show  ?case proof
    show "atom z  (v1, v2)" using infer_v_pairI fresh_Pair by simp
    show "atom z  (Θ, , Γ' @ (x, b0, c0) #Γ Γ)"  apply( fresh_mth add:  infer_v_pairI )
      using fresh_def infer_v_pairI wfG_supp fresh_append_g fresh_GCons fresh_prodN by metis+
    show "Θ; ; Γ' @ (x, b0, c0) #Γ Γ  v1  t1'" using infer_v_pairI  by simp
    show "Θ; ; Γ' @ (x, b0, c0) #Γ Γ  v2  t2'" using infer_v_pairI  by simp
  qed   
next
  case (infer_v_consI s dclist Θ dc tc  v tv z)
  show ?case proof
    show AF_typedef s dclist  set Θ using infer_v_consI by auto
    show (dc, tc)  set dclist using infer_v_consI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  v  tv using infer_v_consI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   tv  tc using infer_v_consI ctx_subtype_subtype by auto
    show atom z  v using infer_v_consI by auto
    show atom z  (Θ, , Γ' @ (x, b0, c0) #Γ Γ) apply( fresh_mth add:  infer_v_consI )
      using fresh_def infer_v_consI wfG_supp fresh_append_g fresh_GCons fresh_prodN by metis+
  qed
next
  case (infer_v_conspI s bv dclist Θ dc tc  v tv b z)
  show ?case proof
    show AF_typedef_poly s bv dclist  set Θ using infer_v_conspI by auto
    show (dc, tc)  set dclist  using infer_v_conspI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  v  tv  using infer_v_conspI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   tv  tc[bv::=b]τb  using infer_v_conspI ctx_subtype_subtype by auto
    show atom z  (Θ, , Γ' @ (x, b0, c0) #Γ Γ, v, b)  apply( fresh_mth add:  infer_v_conspI )
      using fresh_def infer_v_conspI wfG_supp fresh_append_g fresh_GCons fresh_prodN by metis+
    show atom bv  (Θ, , Γ' @ (x, b0, c0) #Γ Γ, v, b) apply( fresh_mth add:  infer_v_conspI )
      using fresh_def infer_v_conspI wfG_supp fresh_append_g fresh_GCons fresh_prodN by metis+
    show Θ;   wf b  using infer_v_conspI by auto
  qed
qed

lemma ctx_subtype_v:
  fixes v::v
  assumes  "Θ; ; Γ'@((x,b0,c0')#ΓΓ)  v  t1" and   "Θ; ; Γ'@(x,b0,c0)#ΓΓ  c0'" 
  shows "t2.  Θ; ; Γ'@((x,b0,c0)#ΓΓ)  v  t2   Θ; ; Γ'@((x,b0,c0)#ΓΓ)  t2  t1"
proof -

  have "Θ; ; Γ'@((x,b0,c0)#ΓΓ)  v  t1 " using ctx_subtype_v_aux assms by auto
  moreover hence "Θ; ; Γ'@((x,b0,c0)#ΓΓ)  t1  t1" using subtype_reflI2 infer_v_wf by simp
  ultimately show ?thesis by auto
qed

lemma ctx_subtype_v_eq:
  fixes v::v
  assumes
    "Θ; ; Γ'@((x,b0,c0')#ΓΓ)  v  t1" and 
    " Θ; ; Γ'@(x,b0,c0)#ΓΓ  c0'" 
  shows "Θ; ; Γ'@((x,b0,c0)#ΓΓ)  v  t1"
proof - 
  obtain t1' where "Θ; ; Γ'@((x,b0,c0)#ΓΓ)  v  t1'" using ctx_subtype_v assms by metis
  moreover have "replace_in_g (Γ'@((x,b0,c0')#ΓΓ)) x c0 =  Γ'@((x,b0,c0)#ΓΓ)" using replace_in_g_inside infer_v_wf assms by metis
  ultimately show ?thesis using infer_v_uniqueness_rig assms by metis
qed

lemma ctx_subtype_check_v_eq:
  assumes  "Θ; ; Γ'@((x,b0,c0')#ΓΓ)  v  t1" and " Θ; ; Γ'@(x,b0,c0)#ΓΓ  c0'"
  shows "Θ; ; Γ'@((x,b0,c0)#ΓΓ)  v  t1"
proof - 
  obtain t2 where t2: "Θ; ; Γ'@((x,b0,c0')#ΓΓ)  v  t2    Θ; ; Γ'@((x,b0,c0')#ΓΓ)  t2  t1" 
    using check_v_elims assms by blast
  hence t3: "Θ; ; Γ'@((x,b0,c0)#ΓΓ)   v  t2"
    using assms ctx_subtype_v_eq by blast

  have "Θ; ; Γ'@((x,b0,c0)#ΓΓ)   v  t2" using t3 by auto
  moreover have " Θ; ; Γ'@((x,b0,c0)#ΓΓ)   t2  t1" proof -

    have " Θ; ; Γ'@((x,b0,c0')#ΓΓ)  t2  t1" using t2 by auto
    thus  ?thesis using subtype_trans
      using assms(2) ctx_subtype_subtype by blast
  qed
  ultimately show ?thesis using check_v.intros by presburger 
qed

text ‹ Basically the same as @{text "ctx_subtype_v_eq"} but in a different form›
lemma ctx_subtype_v_rig_eq:
  fixes v::v
  assumes "replace_in_g_subtyped  Θ  Γ' [(x,c0)] Γ" and  
    "Θ; ; Γ'   v  t1" 
  shows "Θ; ; Γ  v  t1"
proof - 
  obtain b and c0' and G and G' where "Γ' = G' @ (x,b,c0')#ΓG   Γ = G' @ (x,b,c0)#ΓG   Θ; ; G'@ (x,b,c0)#ΓG   c0'"
    using assms replace_in_g_inside_valid  infer_v_wf by metis
  thus ?thesis using ctx_subtype_v_eq[of Θ  G' x b c0' G v t1 c0] assms by simp
qed

lemma ctx_subtype_v_rigs_eq:
  fixes v::v
  assumes "replace_in_g_subtyped Θ  Γ' xcs Γ" and  
    "Θ; ; Γ'   v  t1" 
  shows "Θ; ; Γ  v  t1"
  using assms proof(induct xcs arbitrary: Γ Γ' t1 )
  case Nil
  then show ?case by auto
next
  case (Cons a xcs)
  then obtain x and c where "a=(x,c)" by fastforce

  then obtain b and c' where bc: "Some (b, c') = lookup Γ' x 
         replace_in_g_subtyped  Θ  (replace_in_g Γ' x c) xcs Γ   Θ; ; Γ'  wf c 
         x  fst ` set xcs    Θ; ; (replace_in_g Γ' x c)   c' "   
    using replace_in_g_subtyped_elims(3)[of  Θ  Γ' x c xcs Γ] Cons  by (metis valid.simps)

  hence *: "replace_in_g_subtyped  Θ  Γ' [(x,c)] (replace_in_g Γ' x c)" using replace_in_g_subtyped_consI 
    by (meson image_iff list.distinct(1) list.set_cases replace_in_g_subtyped_nilI)
  hence   t2: "Θ; ; (replace_in_g Γ' x c)  v  t1 " using ctx_subtype_v_rig_eq[OF * Cons(3)] by blast
  moreover have **: "replace_in_g_subtyped  Θ  (replace_in_g Γ' x c) xcs Γ" using bc by auto
  ultimately have  t2': "Θ; ; Γ  v  t1" using Cons by blast
  thus ?case by blast
qed

lemma ctx_subtype_check_v_rigs_eq:
  assumes "replace_in_g_subtyped Θ  Γ' xcs Γ" and  
    "Θ; ; Γ'   v  t1" 
  shows "Θ; ; Γ  v  t1"
proof - 
  obtain t2 where  "Θ; ; Γ'   v  t2   Θ; ; Γ'  t2  t1" using check_v_elims assms by fast
  hence "Θ; ; Γ   v  t2   Θ; ; Γ  t2  t1" using ctx_subtype_v_rigs_eq ctx_subtype_subtype_rigs 
    using assms(1) by blast
  thus ?thesis 
    using check_v_subtypeI by blast
qed

section ‹Expressions›

lemma valid_wfC:
  fixes c0::c
  assumes  "Θ; ; Γ'@(x,b0,c0)#ΓΓ  c0'" 
  shows "Θ; ; (x, b0, TRUE) #Γ Γ  wf c0"
  using  wfG_elim2 valid.simps wfG_suffix 
  using assms valid_g_wf by metis

lemma ctx_subtype_e_eq:
  fixes G::Γ
  assumes
    "Θ ; Φ ;  ; G ; Δ  e  t1" and "G =  Γ'@((x,b0,c0')#ΓΓ)"
    "Θ; ; Γ'@(x,b0,c0)#ΓΓ  c0'" 
  shows "Θ ; Φ ;  ; Γ'@((x,b0,c0)#ΓΓ) ; Δ  e  t1"
  using assms proof(nominal_induct t1 avoiding: c0 rule: infer_e.strong_induct)
  case (infer_e_valI Θ  Γ'' Δ Φ v τ)
  show ?case proof
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  wf Δ using wf_replace_inside2(6) valid_wfC infer_e_valI by auto
    show Θ  wf Φ using infer_e_valI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v  τ using infer_e_valI ctx_subtype_v_eq by auto
  qed
next
  case (infer_e_plusI Θ  Γ'' Δ Φ v1 z1 c1 v2 z2 c2 z3)
  show ?case proof 
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  wf Δ using wf_replace_inside2(6) valid_wfC infer_e_plusI by auto
    show Θ  wf Φ  using infer_e_plusI by auto
    show *:Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v1   z1 : B_int  | c1  using infer_e_plusI ctx_subtype_v_eq by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v2   z2 : B_int  | c2  using infer_e_plusI ctx_subtype_v_eq by auto
    show atom z3  AE_op Plus v1 v2 using infer_e_plusI by auto
    show   atom z3  Γ' @ (x, b0, c0) #Γ Γ using * infer_e_plusI fresh_replace_inside  infer_v_wf  by metis
  qed
next
  case (infer_e_leqI Θ  Γ'' Δ Φ v1 z1 c1 v2 z2 c2 z3)
  show ?case proof 
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  wf Δ using wf_replace_inside2(6) valid_wfC infer_e_leqI by auto
    show Θ  wf Φ  using infer_e_leqI by auto
    show *:Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v1   z1 : B_int  | c1  using infer_e_leqI ctx_subtype_v_eq by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v2   z2 : B_int  | c2  using infer_e_leqI ctx_subtype_v_eq by auto
    show atom z3  AE_op LEq v1 v2 using infer_e_leqI by auto
    show   atom z3  Γ' @ (x, b0, c0) #Γ Γ using * infer_e_leqI fresh_replace_inside  infer_v_wf  by metis
  qed
next
  case (infer_e_eqI Θ  Γ'' Δ Φ v1 z1 bb c1 v2 z2 c2 z3)
  show ?case proof 
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  wf Δ using wf_replace_inside2(6) valid_wfC infer_e_eqI by auto
    show Θ  wf Φ  using infer_e_eqI by auto
    show *:Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v1   z1 : bb  | c1  using infer_e_eqI ctx_subtype_v_eq by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v2   z2 : bb  | c2  using infer_e_eqI ctx_subtype_v_eq by auto
    show atom z3  AE_op Eq v1 v2 using infer_e_eqI by auto
    show   atom z3  Γ' @ (x, b0, c0) #Γ Γ using * infer_e_eqI fresh_replace_inside  infer_v_wf  by metis
    show "bb  {B_bool, B_int, B_unit}" using infer_e_eqI by auto
  qed
next
  case (infer_e_appI Θ  Γ'' Δ Φ f x' b c τ' s' v τ)
  show ?case proof
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  wf Δ using wf_replace_inside2(6) valid_wfC infer_e_appI by auto
    show Θ  wf Φ using  infer_e_appI by auto
    show Some (AF_fundef f (AF_fun_typ_none (AF_fun_typ x' b c τ' s'))) = lookup_fun Φ f  using infer_e_appI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v   x' : b  | c  using infer_e_appI ctx_subtype_check_v_eq by auto
    thus atom x'  (Θ, Φ, , Γ' @ (x, b0, c0) #Γ Γ, Δ, v, τ) 
      using infer_e_appI fresh_replace_inside[of Θ  Γ' x b0 c0' Γ c0 x']  infer_v_wf by auto
    show τ'[x'::=v]v = τ using infer_e_appI by auto
  qed
next
  case (infer_e_appPI Θ  Γ1 Δ Φ b' f bv x1 b c τ' s' v τ)
  show ?case proof
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ wf Δ using wf_replace_inside2(6) valid_wfC infer_e_appPI by auto
    show Θ  wf Φ using infer_e_appPI by auto
    show Θ;   wf b' using infer_e_appPI by auto
    show Some (AF_fundef f (AF_fun_typ_some bv (AF_fun_typ x1 b c τ' s'))) = lookup_fun Φ f using infer_e_appPI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v   x1 : b[bv::=b']b  | c[bv::=b']b  using infer_e_appPI  ctx_subtype_check_v_eq subst_defs by auto
    thus  atom x1  Γ' @ (x, b0, c0) #Γ Γ using  fresh_replace_inside[of Θ  Γ' x b0 c0' Γ  c0 x1 ] infer_v_wf infer_e_appPI by auto
    show τ'[bv::=b']b[x1::=v]v = τ using infer_e_appPI by auto
    have "atom bv  Γ' @ (x, b0, c0') #Γ Γ" using infer_e_appPI by metis
    hence "atom bv   Γ' @ (x, b0, c0) #Γ Γ" 
      unfolding fresh_append_g fresh_GCons fresh_prod3 using  atom bv  c0 fresh_append_g by metis
    thus  atom bv   (Θ, Φ, , Γ' @ (x, b0, c0) #Γ Γ, Δ, b', v, τ) using infer_e_appPI by auto
  qed
next
  case (infer_e_fstI Θ  Γ'' Δ Φ v z' b1 b2 c z)
  show ?case proof 
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  wf Δ using wf_replace_inside2(6) valid_wfC infer_e_fstI by auto
    show Θ wf Φ using infer_e_fstI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v   z' : B_pair b1 b2  | c  using infer_e_fstI ctx_subtype_v_eq by auto
    thus atom z  Γ' @ (x, b0, c0) #Γ Γ using infer_e_fstI fresh_replace_inside[of Θ  Γ' x b0 c0' Γ c0 z]  infer_v_wf by auto
    show atom z  AE_fst v using infer_e_fstI by auto
  qed
next
  case (infer_e_sndI Θ  Γ'' Δ Φ v z' b1 b2 c z)
  show ?case proof 
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  wf Δ using wf_replace_inside2(6) valid_wfC infer_e_sndI by auto
    show Θ wf Φ using infer_e_sndI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v   z' : B_pair b1 b2  | c  using infer_e_sndI ctx_subtype_v_eq by auto
    thus atom z  Γ' @ (x, b0, c0) #Γ Γ using infer_e_sndI fresh_replace_inside[of Θ  Γ' x b0 c0' Γ c0 z]  infer_v_wf by auto
    show atom z  AE_snd v using infer_e_sndI by auto
  qed
next
  case (infer_e_lenI Θ  Γ'' Δ Φ v z' c z)
  show ?case proof 
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  wf Δ using wf_replace_inside2(6) valid_wfC infer_e_lenI by auto
    show Θ wf Φ using infer_e_lenI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v   z' : B_bitvec  | c  using infer_e_lenI ctx_subtype_v_eq by auto
    thus atom z  Γ' @ (x, b0, c0) #Γ Γ using infer_e_lenI fresh_replace_inside[of Θ  Γ' x b0 c0' Γ c0 z]  infer_v_wf by auto
    show atom z  AE_len v using infer_e_lenI by auto
  qed
next
  case (infer_e_mvarI Θ  Γ'' Φ Δ u τ)
  show ?case proof 
    show "Θ; ; Γ' @ (x, b0, c0) #Γ Γ  wf Δ"   using wf_replace_inside2(6) valid_wfC infer_e_mvarI by auto
    thus "Θ;  wf Γ' @ (x, b0, c0) #Γ Γ" using infer_e_mvarI fresh_replace_inside  wfD_wf   by blast 
    show "Θ wf Φ "  using infer_e_mvarI by auto
    show "(u, τ)  setD Δ" using infer_e_mvarI by auto
  qed
next
  case (infer_e_concatI Θ   Γ'' Δ Φ v1 z1 c1 v2 z2 c2 z3)
  show ?case proof 
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  wf Δ using wf_replace_inside2(6) valid_wfC infer_e_concatI by auto
    thus  atom z3  Γ' @ (x, b0, c0) #Γ Γ using infer_e_concatI fresh_replace_inside[of Θ  Γ' x b0 c0' Γ c0 z3]  infer_v_wf wfX_wfY by metis
    show Θ wf Φ using infer_e_concatI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v1   z1 : B_bitvec  | c1  using infer_e_concatI ctx_subtype_v_eq by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ   v2   z2 : B_bitvec  | c2  using infer_e_concatI ctx_subtype_v_eq by auto
    show atom z3  AE_concat v1 v2 using infer_e_concatI by auto  
  qed
next
  case (infer_e_splitI Θ  Γ'' Δ Φ v1 z1 c1 v2 z2 z3)
  show ?case proof
    show *:Θ; ; Γ' @ (x, b0, c0) #Γ Γ wf Δ using wf_replace_inside2(6) valid_wfC infer_e_splitI by auto  
    show Θ  wf Φ using infer_e_splitI by auto
    show Θ; ; Γ' @ (x, b0, c0) #Γ Γ  v1   z1 : B_bitvec  | c1  using infer_e_splitI  ctx_subtype_v_eq by auto
    show Θ; ; Γ' @
                 (x, b0, c0) #Γ
                 Γ   v2   z2 : B_int  | [ leq [ [ L_num 0 ]v ]ce [ [ z2 ]v ]ce ]ce  ==  [ [ L_true ]v ]ce AND
                                 [ leq [ [ z2 ]v ]ce [| [ v1 ]ce |]ce ]ce  ==  [ [ L_true ]v ]ce    
      using infer_e_splitI  ctx_subtype_check_v_eq by auto

    show  atom z1  Γ' @ (x, b0, c0) #Γ Γ using  fresh_replace_inside[of Θ  Γ' x b0 c0' Γ c0 z1] infer_e_splitI  infer_v_wf wfX_wfY * by metis
    show  atom z2  Γ' @ (x, b0, c0) #Γ Γ using  fresh_replace_inside[of Θ  Γ' x b0 c0' Γ c0 ] infer_e_splitI  infer_v_wf wfX_wfY * by metis
    show  atom z3  Γ' @ (x, b0, c0) #Γ Γ using  fresh_replace_inside[of Θ  Γ' x b0 c0' Γ c0 ] infer_e_splitI  infer_v_wf wfX_wfY * by metis
    show atom z1  AE_split v1 v2 using infer_e_splitI by auto
    show atom z2  AE_split v1 v2 using infer_e_splitI by auto
    show atom z3  AE_split v1 v2 using infer_e_splitI by auto
  qed
qed

lemma ctx_subtype_e_rig_eq:
  assumes "replace_in_g_subtyped Θ  Γ' [(x,c0)] Γ" and  
    "Θ ; Φ ;  ; Γ' ; Δ  e  t1" 
  shows "Θ ; Φ ;  ; Γ ; Δ  e  t1"
proof - 
  obtain b and c0' and G and G' where "Γ' = G' @ (x,b,c0')#ΓG   Γ = G' @ (x,b,c0)#ΓG   Θ; ; G'@ (x,b,c0)#ΓG   c0'"
    using assms replace_in_g_inside_valid infer_e_wf by meson
  thus  ?thesis 
    using assms ctx_subtype_e_eq by presburger
qed

lemma ctx_subtype_e_rigs_eq:
  assumes "replace_in_g_subtyped Θ  Γ' xcs Γ" and  
    "Θ ; Φ ;  ; Γ'; Δ  e  t1" 
  shows "Θ ; Φ ;  ; Γ ; Δ  e  t1"
  using assms proof(induct xcs arbitrary: Γ Γ' t1 )
  case Nil
  moreover have "Γ' = Γ" using replace_in_g_subtyped_nilI 
    using calculation(1) by blast
  moreover have "Θ;;Γ  t1  t1" using subtype_reflI2 Nil infer_e_t_wf by blast
  ultimately show ?case by blast
next
  case (Cons a xcs)

  then obtain x and c where "a=(x,c)" by fastforce
  then obtain b and c' where bc: "Some (b, c') = lookup Γ' x 
         replace_in_g_subtyped Θ  (replace_in_g Γ' x c) xcs Γ  Θ; ; Γ'  wf c 
         x  fst ` set xcs    Θ; ; (replace_in_g Γ' x c)   c' " using replace_in_g_subtyped_elims(3)[of  Θ  Γ' x c xcs Γ] Cons
    by (metis valid.simps)

  hence *: "replace_in_g_subtyped Θ  Γ' [(x,c)] (replace_in_g Γ' x c)" using replace_in_g_subtyped_consI 
    by (meson image_iff list.distinct(1) list.set_cases replace_in_g_subtyped_nilI)
  hence   t2: "Θ ; Φ ;  ; (replace_in_g Γ' x c) ; Δ  e  t1 " using ctx_subtype_e_rig_eq[OF * Cons(3)] by blast
  moreover have **: "replace_in_g_subtyped  Θ  (replace_in_g Γ' x c) xcs Γ" using bc by auto
  ultimately have  t2': "Θ ; Φ ;  ; Γ ; Δ  e  t1" using Cons by blast
  thus  ?case  by blast
qed

section ‹Statements›

lemma ctx_subtype_s_rigs:
  fixes c0::c and s::s and G'::Γ and xcs :: "(x*c) list" and css::branch_list
  shows
    "check_s Θ Φ  G Δ  s  t1  wsX G xcs   replace_in_g_subtyped Θ  G xcs G'   check_s Θ Φ  G' Δ  s  t1" and 
    "check_branch_s Θ Φ  G Δ tid cons const v cs  t1   wsX G xcs   replace_in_g_subtyped  Θ  G xcs G'   check_branch_s Θ Φ  G' Δ tid cons const v cs t1"
    "check_branch_list Θ Φ  G Δ tid dclist v css  t1   wsX G xcs   replace_in_g_subtyped  Θ  G xcs G'   check_branch_list Θ Φ  G' Δ tid dclist v css t1"
proof(induction   arbitrary:  xcs G' and xcs G' and xcs G' rule: check_s_check_branch_s_check_branch_list.inducts)
  case (check_valI Θ  Γ Δ Φ v τ' τ)
  hence *:"Θ; ; G'   v  τ'   Θ; ; G'   τ'  τ" using ctx_subtype_v_rigs_eq ctx_subtype_subtype_rigs 
    by (meson check_v.simps)
  show ?case proof
    show Θ; ; G' wf Δ using check_valI wfD_rig by auto
    show Θ wf Φ using check_valI by auto
    show Θ; ; G'   v  τ' using * by auto
    show Θ; ; G'   τ'  τ using * by auto
  qed
next
  case (check_letI x Θ Φ  Γ Δ e τ z' s b' c')

  show ?case proof
    have wfG: "Θ;  wf Γ  Θ;  wf G'" using infer_e_wf check_letI replace_in_g_wfG   using infer_e_wf(2) by (auto simp add: freshers)
    hence "atom x  G'" using check_letI replace_in_g_fresh replace_in_g_wfG  by auto
    thus  "atom x  (Θ, Φ, , G', Δ, e, τ)" using check_letI by auto
    have "atom z'  G'" apply(rule replace_in_g_fresh[OF check_letI(7)]) 
      using replace_in_g_wfG check_letI fresh_prodN infer_e_wf by metis+
    thus "atom z'  (x, Θ, Φ, , G', Δ, e, τ, s)" using check_letI fresh_prodN by metis

    show "Θ ; Φ ;  ; G' ; Δ   e   z' : b'  | c' " 
      using check_letI ctx_subtype_e_rigs_eq by blast 
    show "Θ ; Φ ;  ; (x, b', c'[z'::=V_var x]v) #Γ G' ; Δ   s  τ" 
    proof(rule  check_letI(5))
      have vld: "Θ;;((x, b', c'[z'::=V_var x]v) #Γ Γ)   c'[z'::=V_var x]cv" proof -
        have "wfG Θ  ((x, b', c'[z'::=V_var x]v) #Γ Γ)" using check_letI check_s_wf  by metis
        hence "wfC Θ  ((x, b', c'[z'::=V_var x]v) #Γ Γ) (c'[z'::=V_var x]cv)" using wfC_refl subst_defs by auto
        thus ?thesis using  valid_reflI[of  Θ  x b' "c'[z'::=V_var x]v" Γ " c'[z'::=V_var x]v"] subst_defs by auto
      qed
      have xf: "x  fst ` set xcs" proof -
        have  "atom ` fst ` set xcs  atom_dom Γ" using check_letI wsX_iff by meson 
        moreover have "wfG Θ  Γ" using infer_e_wf check_letI by metis
        ultimately show ?thesis using fresh_def  check_letI  wfG_dom_supp 
          using wsX_fresh by auto
      qed
      show "replace_in_g_subtyped Θ  ((x, b', c'[z'::=V_var x]v) #Γ Γ) ((x, c'[z'::=V_var x]v) # xcs) ((x, b', c'[z'::=V_var x]v) #Γ G')" proof -

        have "Some (b', c'[z'::=V_var x]v) =  lookup ((x, b', c'[z'::=V_var x]v) #Γ Γ) x" by auto

        moreover have "Θ; ; replace_in_g ((x, b', c'[z'::=V_var x]v) #Γ Γ) x  (c'[z'::=V_var x]v)   c'[z'::=V_var x]v" proof -
          have "replace_in_g ((x, b', c'[z'::=V_var x]v) #Γ Γ) x  (c'[z'::=V_var x]v) = ((x, b', c'[z'::=V_var x]v) #Γ Γ)" 
            using replace_in_g.simps by presburger
          thus ?thesis  using vld subst_defs by auto
        qed

        moreover have " replace_in_g_subtyped Θ  (replace_in_g ((x, b', c'[z'::=V_var x]v) #Γ Γ) x (c'[z'::=V_var x]v)) xcs ( ((x, b', c'[z'::=V_var x]v) #Γ G'))" proof -
          have "wfG Θ  ( ((x, b', c'[z'::=V_var x]v) #Γ Γ))"  using check_letI check_s_wf  by metis
          hence "replace_in_g_subtyped Θ  ( ((x, b', c'[z'::=V_var x]v) #Γ Γ)) xcs ( ((x, b', c'[z'::=V_var x]v) #Γ G'))" 
            using check_letI replace_in_g_subtyped_cons xf by meson
          moreover have "replace_in_g ((x, b', c'[z'::=V_var x]v) #Γ Γ) x (c'[z'::=V_var x]v) = ( ((x, b', c'[z'::=V_var x]v) #Γ Γ))"
            using replace_in_g.simps by presburger
          ultimately show ?thesis by argo
        qed      
        moreover  have "Θ; ; (x, b', c'[z'::=V_var x]v) #Γ Γ  wf  c'[z'::=V_var x]v " using vld subst_defs by auto
        ultimately show ?thesis using  replace_in_g_subtyped_consI xf replace_in_g.simps(2) by metis
      qed

      show " wsX ((x, b', c'[z'::=V_var x]v) #Γ Γ) ((x, c'[z'::=V_var x]v) # xcs)" 
        using check_letI xf subst_defs  by (simp add: wsX_cons)  
    qed
  qed

next
  case (check_branch_list_consI Θ Φ  Γ Δ tid dclist v cs τ css)
  then show ?case using Typing.check_branch_list_consI by auto
next
  case (check_branch_list_finalI Θ Φ  Γ Δ tid dclist v cs τ)
  then show ?case using Typing.check_branch_list_finalI by auto
next
  case (check_branch_s_branchI Θ  Γ Δ τ const x Φ tid cons v s)

  have wfcons: "wfG Θ  ((x, b_of const, CE_val v  ==  CE_val (V_cons tid cons (V_var x))  AND c_of const x) #Γ Γ)" using check_s_wf check_branch_s_branchI
    by meson
  hence wf: "wfG Θ  Γ" using  wfG_cons by metis

  moreover have "atom x  (const, G',v)"  proof -
    have "atom x  G'"  using check_branch_s_branchI wf replace_in_g_fresh 
        wfG_dom_supp replace_in_g_wfG by simp
    thus ?thesis using check_branch_s_branchI fresh_prodN by simp
  qed

  moreover have st: "Θ ; Φ ;  ; (x, b_of const, CE_val v  ==  CE_val(V_cons tid cons (V_var x))  AND  c_of const x) #Γ G' ; Δ   s  τ " proof -
    have " wsX ((x, b_of const, CE_val v  ==  CE_val(V_cons tid cons (V_var x))   AND c_of const x) #Γ Γ) xcs" using check_branch_s_branchI wsX_cons2 wsX_fresh wf by force
    moreover have "replace_in_g_subtyped Θ  ((x,  b_of const, CE_val v  ==  CE_val (V_cons tid cons (V_var x))   AND  c_of const x) #Γ Γ) xcs ((x,  b_of const, CE_val v  ==  CE_val(V_cons tid cons (V_var x)) AND  c_of const x) #Γ G' )" 
      using replace_in_g_subtyped_cons wsX_fresh wf check_branch_s_branchI wfcons by auto
    thus ?thesis using check_branch_s_branchI  calculation by meson
  qed
  moreover have wft: " wfT Θ  G' τ " using
      check_branch_s_branchI ctx_subtype_subtype_rigs subtype_reflI2 subtype_wf by metis
  moreover have "wfD Θ  G' Δ" using check_branch_s_branchI wfD_rig by presburger
  ultimately show ?case using 
      Typing.check_branch_s_branchI 
    using check_branch_s_branchI.hyps by simp

next
  case (check_ifI z Θ Φ  Γ Δ v s1 s2 τ)
  hence wf:"wfG Θ  Γ" using check_s_wf by presburger
  show ?case proof(rule check_s_check_branch_s_check_branch_list.check_ifI)
    show atom z  (Θ, Φ, , G', Δ, v, s1, s2, τ) using fresh_prodN replace_in_g_fresh1 wf check_ifI by auto
    show Θ; ; G'   v   z : B_bool  | TRUE  using ctx_subtype_check_v_rigs_eq check_ifI by presburger
    show Θ ; Φ ;  ; G' ; Δ   s1   z : b_of τ  | CE_val v  ==  CE_val (V_lit L_true)   IMP  c_of τ z   using  check_ifI by auto
    show Θ ; Φ ;  ; G' ; Δ   s2   z : b_of τ  | CE_val v  ==  CE_val (V_lit L_false)   IMP  c_of τ z   using  check_ifI by auto
  qed
next

  case (check_let2I x P Φ  G Δ t s1 τ s2 )
  show ?case proof
    have "wfG P  G" using check_let2I check_s_wf by metis
    show  *: "P ; Φ ;  ; G' ; Δ   s1 t" using check_let2I by blast
    show  "atom x  (P, Φ, , G', Δ, t, s1, τ)" proof -
      have "wfG P  G'" using check_s_wf * by blast
      hence "atom_dom G = atom_dom G'" using check_let2I rigs_atom_dom_eq by presburger
      moreover have "atom x  G" using check_let2I by auto
      moreover have "wfG P  G" using check_s_wf *  replace_in_g_wfG  check_let2I by simp
      ultimately have "atom x  G'" using wfG_dom_supp fresh_def wfG P  G' by metis
      thus ?thesis using check_let2I by auto
    qed
    show "P ; Φ ;  ;(x, b_of t, c_of t x) #Γ G' ; Δ   s2  τ " proof - 
      have "wsX ((x, b_of t, c_of t x) #Γ G) xcs" using check_let2I wsX_cons2  wsX_fresh wfG P  G by simp
      moreover have "replace_in_g_subtyped P  ((x,  b_of t, c_of t x) #Γ G) xcs ((x,  b_of t, c_of t x) #Γ G')" proof(rule  replace_in_g_subtyped_cons )
        show "replace_in_g_subtyped P  G xcs G'" using check_let2I by auto
        have "atom x  G" using check_let2I by auto
        moreover have "wfT P  G t" using check_let2I check_s_wf by metis

        moreover have "atom x  t" using check_let2I check_s_wf wfT_supp by auto
        ultimately show "wfG P  ((x,  b_of t, c_of t x) #Γ G)" using wfT_wf_cons b_of_c_of_eq[of x t] by auto
        show "x  fst ` set xcs" using check_let2I wsX_fresh wfG P  G by simp
      qed
      ultimately show ?thesis using check_let2I by presburger
    qed  
  qed
next
  case (check_varI u Θ Φ  Γ Δ τ' v τ s)
  show ?case proof
    have "atom u  G'" unfolding fresh_def
      apply(rule  u_not_in_g , rule replace_in_g_wfG)
      using check_v_wf check_varI by simp+
    thus  atom u  (Θ, Φ, , G', Δ, τ', v, τ) unfolding fresh_prodN using check_varI by simp
    show Θ; ; G'   v  τ' using ctx_subtype_check_v_rigs_eq check_varI by auto
    show Θ ; Φ ;  ; G' ; (u, τ') #Δ Δ   s  τ using  check_varI by auto
  qed
next
  case (check_assignI P Φ  G Δ u τ v z τ')
  show ?case proof
    show P  wf Φ using  check_assignI by auto
    show P ;  ; G'  wf Δ  using  check_assignI wfD_rig by auto
    show (u, τ)  setD Δ  using  check_assignI by auto
    show P ;  ; G'   v  τ using ctx_subtype_check_v_rigs_eq check_assignI by auto
    show P ;  ; G'    z : B_unit  | TRUE   τ'  using ctx_subtype_subtype_rigs check_assignI by auto
  qed
next
  case (check_whileI Δ G P s1 z s2 τ')
  then show ?case using Typing.check_whileI
    by (meson ctx_subtype_subtype_rigs)
next
  case (check_seqI Δ G P s1 z s2 τ)
  then show ?case 
    using check_s_check_branch_s_check_branch_list.check_seqI by blast
next
  case (check_caseI Θ Φ  Γ Δ tid dclist v cs τ z)
  show ?case proof
    show " Θ ;  Φ ;  ; G' ; Δ ; tid ; dclist ; v  cs  τ" using check_caseI ctx_subtype_check_v_rigs_eq by auto
    show "AF_typedef tid dclist  set  Θ" using check_caseI by auto
    show "Θ; ; G'   v   z : B_id tid  | TRUE " using check_caseI ctx_subtype_check_v_rigs_eq by auto
    show "wf Θ " using check_caseI by auto
  qed
next
  case (check_assertI x Θ Φ  Γ Δ c τ s)
  show ?case proof
    have wfG: "Θ;  wf Γ  Θ;  wf G'" using check_s_wf check_assertI replace_in_g_wfG wfX_wfY by metis
    hence "atom x  G'" using check_assertI replace_in_g_fresh replace_in_g_wfG  by auto
    thus  atom x  (Θ, Φ, , G', Δ, c, τ, s) using check_assertI fresh_prodN by auto
    show Θ ; Φ ;  ; (x, B_bool, c) #Γ G' ; Δ   s  τ proof(rule check_assertI(5) )
      show "wsX ((x, B_bool, c) #Γ Γ) xcs" using check_assertI wsX_cons3   by simp
      show "Θ;    (x, B_bool, c) #Γ Γ  xcs   (x, B_bool, c) #Γ G'" proof(rule  replace_in_g_subtyped_cons)
        show Θ;    Γ  xcs   G' using check_assertI by auto
        show Θ;   wf (x, B_bool, c) #Γ Γ using check_assertI check_s_wf by metis
        thus x  fst ` set xcs using check_assertI wsX_fresh wfG_elims wfX_wfY by metis
      qed
    qed
    show Θ; ; G'   c using check_assertI replace_in_g_valid by auto
    show Θ; ; G' wf Δ using check_assertI wfD_rig by auto
  qed
qed

lemma replace_in_g_subtyped_empty:
  assumes "wfG Θ  (Γ' @ (x, b, c[z::=V_var x]cv) #Γ Γ)" 
  shows  "replace_in_g_subtyped Θ  (replace_in_g (Γ' @ (x, b, c[z::=V_var x]cv) #Γ Γ) x (c'[z'::=V_var x]cv)) [] (Γ' @ (x, b, c'[z'::=V_var x]cv) #Γ Γ)"
proof -
  have "replace_in_g (Γ' @ (x, b, c[z::=V_var x]cv) #Γ Γ) x (c'[z'::=V_var x]cv) = (Γ' @ (x, b, c'[z'::=V_var x]cv) #Γ Γ)" 
    using assms proof(induct Γ' rule: Γ_induct)
    case GNil
    then show ?case using replace_in_g.simps by auto
  next
    case (GCons x1 b1 c1 Γ1)
    have "x  fst ` toSet ((x1,b1,c1)#ΓΓ1)"  using GCons wfG_inside_fresh atom_dom.simps dom.simps toSet.simps append_g.simps by fast
    hence "x1  x" using assms wfG_inside_fresh GCons by force
    hence "((x1,b1,c1) #Γ (Γ1 @ (x, b, c[z::=V_var x]cv) #Γ Γ))[xc'[z'::=V_var x]cv] = (x1,b1,c1) #Γ (Γ1 @ (x, b, c'[z'::=V_var x]cv) #Γ Γ)"
      using replace_in_g.simps GCons wfG_elims append_g.simps by metis
    thus ?case using append_g.simps by simp
  qed
  thus ?thesis using replace_in_g_subtyped_nilI by presburger
qed

lemma ctx_subtype_s:
  fixes  s::s
  assumes "Θ ; Φ ;  ; Γ'@((x,b,c[z::=V_var x]cv)#ΓΓ) ; Δ  s  τ" and 
    "Θ; ; Γ   z' : b | c'    z : b | c " and 
    "atom x  (z,z',c,c')"
  shows "Θ ; Φ ;  ; Γ'@(x,b,c'[z'::=V_var x]cv)#ΓΓ ; Δ  s  τ"
proof - 

  have wf: "wfG Θ  (Γ'@((x,b,c[z::=V_var x]cv)#ΓΓ))" using check_s_wf assms by meson
  hence *:"x  fst ` toSet Γ'" using wfG_inside_fresh by force
  have "wfG Θ  ((x,b,c[z::=V_var x]cv)#ΓΓ)" using wf wfG_suffix by metis
  hence xfg: "atom x  Γ" using wfG_elims by metis
  have "x  z'"  using assms fresh_at_base fresh_prod4 by metis
  hence  a2: "atom x  c'" using assms fresh_prod4 by metis

  have "atom x  (z', c', z, c, Γ)" proof -       
    have "x  z" using assms  using assms fresh_at_base fresh_prod4 by metis
    hence  a1 : "atom x  c" using assms subtype_wf   subtype_wf assms wfT_fresh_c xfg by meson
    thus ?thesis using a1 a2 atom x  (z,z',c,c') fresh_prod4 fresh_Pair xfg by simp
  qed
  hence wc1:" Θ; ; (x, b, c'[z'::=V_var x]v) #Γ Γ   c[z::=V_var x]v"
    using  subtype_valid assms fresh_prodN by metis  

  have vld: "Θ; ; (Γ'@(x, b, c'[z'::=V_var x]cv) #Γ Γ)  c[z::=V_var x]cv" proof - 

    have "toSet ((x, b, c'[z'::=V_var x]cv) #Γ Γ)  toSet (Γ'@(x, b, c'[z'::=V_var x]cv) #Γ Γ)" by auto
    moreover have "wfG Θ  (Γ'@(x, b, c'[z'::=V_var x]cv) #Γ Γ)" proof -
      have *:"wfT Θ  Γ ( z' : b | c' )" using subtype_wf assms by meson
      moreover have "atom x  (c',Γ)" using xfg a2 by simp
      ultimately have "wfG Θ  ((x, b, c'[z'::=V_var x]cv) #Γ Γ)" using wfT_wf_cons_flip  freshers by blast
      thus ?thesis using wfG_replace_inside2 check_s_wf assms  by metis
    qed
    ultimately show ?thesis using wc1 valid_weakening subst_defs by metis
  qed
  hence  wbc: "Θ; ; Γ' @ (x, b, c'[z'::=V_var x]cv) #Γ Γ  wf c[z::=V_var x]cv" using valid.simps by auto
  have wbc1: "Θ; ; (x, b, c'[z'::=V_var x]cv) #Γ Γ  wf c[z::=V_var x]cv" using wc1 valid.simps subst_defs by auto
  have "wsX  (Γ'@((x,b,c[z::=V_var x]cv)#ΓΓ)) [(x, c'[z'::=V_var x]cv)]" proof 
    show "wsX (Γ' @ (x, b, c[z::=V_var x]cv) #Γ Γ) []" using wsX_NilI by auto
    show "atom x  atom_dom (Γ' @ (x, b, c[z::=V_var x]cv) #Γ Γ)" by simp
    show "x  fst ` set []" by auto
  qed
  moreover have "replace_in_g_subtyped Θ  (Γ'@((x,b,c[z::=V_var x]cv)#ΓΓ)) [(x, c'[z'::=V_var x]cv)] (Γ'@(x,b,c'[z'::=V_var x]cv)#ΓΓ)" proof
    show "Some (b, c[z::=V_var x]cv) = lookup (Γ' @ (x, b, c[z::=V_var x]cv) #Γ Γ) x" using lookup_inside* by auto
    show "Θ; ; replace_in_g (Γ' @ (x, b, c[z::=V_var x]cv) #Γ Γ) x (c'[z'::=V_var x]cv)   c[z::=V_var x]cv"  using vld replace_in_g_split wf by metis
    show "replace_in_g_subtyped Θ  (replace_in_g (Γ' @ (x, b, c[z::=V_var x]cv) #Γ Γ) x (c'[z'::=V_var x]cv)) [] (Γ' @ (x, b, c'[z'::=V_var x]cv) #Γ Γ)" 
      using replace_in_g_subtyped_empty wf by presburger
    show "x  fst ` set []" by auto
    show "Θ; ; Γ' @ (x, b, c[z::=V_var x]cv) #Γ Γ  wf c'[z'::=V_var x]cv" 
    proof(rule wf_weakening)
      show Θ; ; (x, b, c[z::=V_var x]cv) #Γ Γ  wf c'[z'::=[ x ]v]cv   using wfC_cons_switch[OF wbc1] wf_weakening(6) check_s_wf assms toSet.simps  by metis 
      show Θ;   wf Γ' @ (x, b, c[z::=[ x ]v]cv) #Γ Γ   using wfC_cons_switch[OF wbc1] wf_weakening(6) check_s_wf assms toSet.simps  by metis
      show toSet ((x, b, c[z::=V_var x]cv) #Γ Γ)  toSet (Γ' @ (x, b, c[z::=[ x ]v]cv) #Γ Γ) using append_g.simps toSet.simps by auto
    qed    
  qed
  ultimately show ?thesis using ctx_subtype_s_rigs(1)[OF assms(1)] by presburger 
qed

end