import TabularTypes.«F⊗⊕ω».Lemmas.Value import TabularTypes.«F⊗⊕ω».Lemmas.Term import TabularTypes.«F⊗⊕ω».Semantics.Term macro "rwomega" equality:term : tactic => `(tactic | (have _eq : $equality := (by omega); rw [_eq]; clear _eq)) namespace TabularTypes.«F⊗⊕ω» open Std private theorem _root_.Membership.mem.inc {r : Range} (h : i ∈ r) : i ∈ { r with stop := r.stop + 1 } := ⟨h.lower, Nat.lt_add_right _ h.upper, h.step⟩ private theorem progress.sandwich {f : Nat → α} (h : i < n) : [0:n].map (fun j => f j) = [:i].map (fun j => f j) ++ f i :: [(i + 1) - (i + 1):n - (i + 1)].map (fun j => f (j + (i + 1))) := by rw [← List.singleton_append, Range.map_shift (Nat.le_refl _)] have : [f i] = List.map (fun j => f j) [i:i + 1] := by rw [Range.toList, if_pos (Nat.lt_succ_self _), Range.toList, if_neg (Nat.not_lt_of_le (Nat.le_refl _)), List.map, List.map] rw [this] rw [Range.map_append (Nat.le_succ _) (Nat.succ_le_of_lt h), Range.map_append (Nat.zero_le _) (Nat.le_of_lt h)] private theorem progress.fold {E : Nat → Term} (EtyA : ∀ i ∈ [0:n], [[ε ⊢ E@i : A@i]]) (h : ∀ i ∈ [0:n], (∃ E', [[E@i -> E']]) ∨ (E i).IsValue) : (∃ i ∈ [0:n], (∀ j ∈ [0:i], (E j).IsValue) ∧ ∃ E', [[E@i -> E']]) ∨ (∀ i ∈ [0:n], (E i).IsValue) := by induction n · case zero => right intro _ ⟨_, lt_zero, _⟩ contradiction · case succ j ih' => match ih' (fun j mem => EtyA j mem.inc) (fun j mem => h j mem.inc) with | .inl ⟨i, mem, ⟨E'', toE''⟩⟩ => exact .inl ⟨i, mem.inc, ⟨E'', toE''⟩⟩ | .inr IsValue => have jmem : j ∈ [0:j + 1] := ⟨Nat.zero_le _, Nat.lt_succ_self _, Nat.mod_one _⟩ match h j jmem with | .inl ⟨E'', toE''⟩ => exact .inl ⟨j, jmem, ⟨IsValue, ⟨E'', toE''⟩⟩⟩ | .inr jIsValue => right intro i mem by_cases i = j · case pos h => rw [h] exact jIsValue · case neg h => exact IsValue i ⟨Nat.zero_le _, Nat.lt_of_le_of_ne (Nat.le_of_lt_succ mem.upper) h, Nat.mod_one _⟩ local instance : Inhabited Value where default := ⟨.prodIntro [], .prodIntro nofun⟩ in theorem progress (EtyA : [[ε ⊢ E : A]]) : (∃ E', [[E -> E']]) ∨ E.IsValue := by generalize Δeq : Environment.empty = Δ at EtyA induction EtyA <;> cases Δeq · case var xinε => cases xinε · case lam => exact .inr .lam · case app E' A' B F E'tyA'arrB _ ih₁ ih₂ => match ih₁ rfl with | .inl ⟨E'', E'toE''⟩ => exact .inl <| .intro _ <| .appL E'toE'' | .inr E'IsValue => match ih₂ rfl with | .inl ⟨F', FtoF'⟩ => exact .inl <| .intro _ <| .appR (V := ⟨E', E'IsValue⟩) FtoF' | .inr FIsValue => let VE' : Value := ⟨E', E'IsValue⟩ have : E' = VE'.1 := rfl have A'Blc := E'tyA'arrB.TypeVarLocallyClosed_of have ⟨_, _, VE'eq⟩ := VE'.canonical_form_of_arr E'tyA'arrB rw [this, VE'eq] exact .inl <| .intro _ <| .lamApp (V := ⟨F, FIsValue⟩) · case typeLam => exact .inr .typeLam · case typeApp E' K _ _ E'ty _ ih => match ih rfl with | .inl ⟨E'', E'toE''⟩ => exact .inl <| .intro _ <| .typeApp E'toE'' | .inr E'IsValue => let V : Value := ⟨E', E'IsValue⟩ have : E' = V.1 := rfl have ⟨_, _, Veq⟩ := V.canonical_form_of_forall E'ty rw [this, Veq] exact .inl <| .intro _ <| .typeLamApp · case prodIntro n E' A b h wf E'ty ih => match progress.fold E'ty (fun i mem => ih i mem rfl) with | .inl ⟨i, ⟨_, iltn, _⟩, IsValue, E'', toE''⟩ => let V j : Value := if h' : j < i then ⟨E' j, IsValue j ⟨Nat.zero_le _, h', Nat.mod_one _⟩⟩ else default rw [progress.sandwich iltn, Range.map_eq_of_eq_of_mem'' (fun j jmem => by show E' j = (V j).val dsimp only [V] rw [dif_pos jmem.upper] ), Nat.sub_self] exact .inl <| .intro _ <| .prodIntro toE'' | .inr IsValue => exact .inr <| .prodIntro fun E Emem => by have ⟨i, imem, Eeq⟩ := Range.mem_of_mem_map Emem rw [Eeq] exact IsValue i imem · case prodElim E' n _ _ i mem E'ty ih => match ih rfl with | .inl ⟨E'', E'toE''⟩ => exact .inl <| .intro _ <| .prodElim E'toE'' | .inr E'IsValue => let V : Value := ⟨E', E'IsValue⟩ have : E' = V.1 := rfl have ⟨_, Veq, h⟩ := V.canonical_form_of_prod E'ty rw [this, Veq] exact .inl <| .intro _ <| .prodElimIntro mem · case sumIntro ih => match ih rfl with | .inl ⟨E', toE'⟩ => exact .inl <| .intro _ <| .sumIntro toE' | .inr E'IsValue => exact .inr <| .sumIntro E'IsValue · case sumElim E' n As _ F _ E'ty Fty Fki ih₁ ih₂ => match ih₁ rfl with | .inl ⟨E'', E'toE''⟩ => exact .inl <| .intro _ <| .sumElimL E'toE'' | .inr E'IsValue => let VE' : Value := ⟨E', E'IsValue⟩ have ⟨n', mem, VE'', VE'_eq, _⟩ := VE'.canonical_form_of_sum E'ty cases VE'_eq match progress.fold Fty (fun i mem => ih₂ i mem rfl) with | .inl ⟨j, ⟨_, jltn, _⟩, IsValue, F', toF'⟩ => let VF k : Value := if h' : k < j then ⟨F k, IsValue k ⟨Nat.zero_le _, h', Nat.mod_one _⟩⟩ else default rw [progress.sandwich jltn, Range.map_eq_of_eq_of_mem'' (fun j jmem => by show F j = (VF j).val dsimp only [VF] rw [dif_pos jmem.upper] ), Nat.sub_self] exact .inl <| .intro _ <| .sumElimR (V := VE') toF' | .inr FIsValue => let VF j : Value := if h : j < n then ⟨F j, FIsValue j ⟨Nat.zero_le _, h, Nat.mod_one _⟩⟩ else default rw [Range.map_eq_of_eq_of_mem'' (fun i mem => by show F i = (VF i).val dsimp only [VF] rw [dif_pos mem.upper] )] exact .inl ⟨_, .sumElimIntro mem⟩ · case equiv ih => exact ih rfl namespace Typing open Environment TermVarInEnvironment in theorem weakening_r' (EtyT: [[ Δ, Δ'' ⊢ E: T ]]) (wf: [[ ⊢ Δ, Δ', Δ'' ]]): [[ Δ, Δ', Δ'' ⊢ E: T ]] := by generalize Δ_eq : [[ (Δ, Δ'') ]] = Δ_ at EtyT induction EtyT generalizing Δ'' case var Δ_ x T wf' xin => subst Δ_ refine .var wf ?_ clear wf' induction Δ' generalizing Δ'' . case empty => simp_all [empty_append] . case typeExt Δ' a K ih => rw [<- append_type_assoc] apply ih . simp_all [append_type_assoc] . apply append_elim at xin cases xin . case inl xin => apply TermVarInEnvironment.weakening_r . simp_all [TermVarNotInDom, TermVarInDom, termVarDom_append, termVarDom] . simp_all . case inr xin => simp_all [TermVarInEnvironment.weakening_l] . case termExt _ Δ' x' T' ih => rw [<- append_term_assoc] apply ih . simp_all [append_term_assoc] . rw [append_term_assoc] apply TermVarInEnvironment.append_elim at xin cases xin . case inl xin => apply TermVarInEnvironment.weakening_r . simp_all . by_cases (x = x') . case pos eq => subst x' rw [<- append_term_assoc, append_assoc] at wf have xinfv := wf.append_termVar_fresh_l x (by simp_all [termVarDom_append, termVarDom]) rw [termVarDom_append] at xinfv aesop (add norm TermVarNotInDom, norm TermVarInDom, safe forward TermVarInDom_of) . case neg neq => constructor <;> simp_all [TermVarNe] . case inr xin => simp_all [TermVarInEnvironment.weakening_l] case lam Δ_ A E T I EtyT ih => subst Δ_ refine .lam (I := I ++ Δ.termVarDom ++ Δ'.termVarDom ++ Δ''.termVarDom) (λ x xnin => ?_) rw [append_termExt_assoc, append_termExt_assoc] refine ih x (by simp_all) ?_ (by rw [append_termExt_assoc]) -- wts. ⊢ Δ, Δ', Δ'', x: A refine .termVarExt wf (by simp_all [TermVarNotInDom, TermVarInDom, termVarDom_append]) ?_ -- wts. Δ, Δ', Δ'' ⊢ A: * have := EtyT x (by simp_all) have := this.WellFormedness_of cases this; case termVarExt h1 h2 AkiStar => refine AkiStar.weakening_r' (λ a anin => ?_) exact wf.append_typeVar_fresh_l a (by simp_all [typeVarDom_append]) case typeLam Δ_ A E T I EtyT ih => subst Δ_ refine .typeLam (I := I ++ Δ.typeVarDom ++ Δ'.typeVarDom ++ Δ''.typeVarDom) (λ a anin => ?_) rw [append_typeExt_assoc, append_typeExt_assoc] refine ih a (by simp_all) ?_ (by rw [append_typeExt_assoc]) exact .typeVarExt wf (by simp_all [TypeVarNotInDom, TypeVarInDom, typeVarDom_append]) case typeApp Δ_ E K T B EtyT BkiK ih => subst Δ_ refine .typeApp (ih wf rfl) ?_ apply BkiK.weakening_r' (λ a anin => ?_) exact wf.append_typeVar_fresh_l a (by simp_all [typeVarDom_append]) case sumIntro i n Δ_ _ T _ mem ty TkiStar h ih => subst Δ_ refine .sumIntro mem (ty.weakening wf) (λ x xin => ?_) h specialize TkiStar x xin refine TkiStar.weakening_r' (λ a anin => ?_) exact wf.append_typeVar_fresh_l a (by simp_all [typeVarDom_append]) case sumElim Δ_ E n T _ F B EtyT FtyTB BkiStar ih1 ih2 => subst Δ_ refine .sumElim (ih1 wf rfl) (λ x xin => ih2 x xin wf rfl) ?_ apply BkiStar.weakening_r' (λ a anin => ?_) exact wf.append_typeVar_fresh_l a (by simp_all [typeVarDom_append]) case equiv Δ_ E T T' EtyT equiv ih => subst Δ_ refine .equiv (ih wf rfl) (equiv.weakening wf.EnvironmentTypeWellFormedness_of) all_goals aesop (add unsafe constructors Typing) (config := { enableSimp := false }) theorem weakening_r (EtyT: [[ Δ ⊢ E: T ]]) (wf: [[ ⊢ Δ, Δ' ]]): [[ Δ, Δ' ⊢ E: T ]] := by apply weakening_r' (Δ'' := Environment.empty) <;> simp_all [Environment.append] theorem term_subst' (EtyA: [[ Δ, x: T, Δ' ⊢ E: A ]]) (FtyT : [[ Δ ⊢ F: T ]]): [[ Δ, Δ' ⊢ E[F/x] : A ]] := by generalize Δ_eq : [[ (Δ, x:T, Δ') ]] = Δ_ at EtyA induction EtyA generalizing Δ' <;> try simp_all [Term.TermVar_subst] . case var Δ_ x' A wf x'in => subst Δ_ by_cases (x = x') . case pos eq => simp_all subst x' -- 1. by wf we know x ∉ Δ'.typeVarDom have fresh := wf.append_termVar_fresh_r x (by constructor) -- 2. then by uniqueness we know from x'In that A = T have eq := x'in.unique (T':=T) (by apply TermVarInEnvironment.weakening_r fresh constructor ) subst A -- 3. then wts Δ, Δ' ⊢ F: T, by weakening FtyT we are done apply weakening_r FtyT wf.TermVar_drop . case neg neq => simp_all -- 1. by x'in we know x': A is either in (Δ, x: T) or Δ' apply TermVarInEnvironment.append_elim at x'in refine .var wf.TermVar_drop ?_ cases x'in . case inl x'in => -- 2a. If x': A ∈ Δ, x: T, we also know that x': A ∉ dom(Δ') obtain ⟨notInΔ', x'in⟩ := x'in -- 3a. and by x ≠ x' we know x': A ∈ Δ. -- wts. x': A ∈ Δ, Δ', by weakening we are done exact TermVarInEnvironment.weakening_r notInΔ' (by cases x'in <;> simp_all) . case inr x'in => -- 2b. If x': A ∈ Δ', similarly by weakening we are done exact TermVarInEnvironment.weakening_l x'in . case lam Δ_ A E B I EtyB ih => subst Δ_ refine .lam (I := x :: I) (λ x' x'nin => ?_) rw [<- FtyT.TermVarLocallyClosed_of.TermVar_open_TermVar_subst_comm (by aesop)] exact ih x' (by simp_all) (by rw [Environment.append_termExt_assoc]) . case app Δ_ E1 A B E2 E1tyAB E2tyA ih1 ih2 => subst Δ_ exact .app (ih1 rfl) (ih2 rfl) . case typeLam Δ_ K E A I EtyA ih => subst Δ_ refine .typeLam (I := x :: (I ++ F.freeTypeVars)) (λ a' a'nin => ?_) rw [<- FtyT.TermTypeVarLocallyClosed_of.TermVar_open_TypeVar_subst_comm] exact ih a' (by simp_all) (by rw [Environment.append_typeExt_assoc]) . case typeApp Δ_ E K A B EtyA BkiK ih => subst Δ_ exact .typeApp (ih rfl) BkiK.TermVar_drop . case prodIntro Δ_ _ _ _ _ wf _ h ih => subst Δ_ exact .prodIntro wf.TermVar_drop (ih · · rfl) h . case prodElim Δ_ _ n _ _ _ _ _ ih => subst Δ_ exact .prodElim (n := n) (ih rfl) (by simp_all) . case sumIntro _ n Δ_ _ _ _ mem EtyA AkiStar h ih => subst Δ_ exact .sumIntro (n := n) mem (ih rfl) (λ x xin => AkiStar x xin |>.TermVar_drop) h . case sumElim Δ_ _ n _ _ _ _ _ _ BkiStar ih1 ih2 => subst Δ_ exact .sumElim (n := n) (ih1 rfl) (λ x xin => ih2 x xin rfl) BkiStar.TermVar_drop . case equiv Δ_ E A B EtyA equiv ih => subst Δ_ exact .equiv (ih rfl) equiv.TermVar_drop theorem term_subst (EtyA: [[ Δ, x: T ⊢ E: A ]]) (FtyT : [[ Δ ⊢ F: T ]]): [[ Δ ⊢ E[F/x] : A ]] := Typing.term_subst' (Δ' := [[(ε)]]) EtyA FtyT theorem Term_open (EtyA : Typing [[(Δ, x : B, Δ')]] (.TermVar_open E x n) A) (xnin : x ∉ E.freeTermVars) (FtyB : [[Δ ⊢ F : B]]) : Typing [[(Δ, Δ')]] (.Term_open E F n) A := by rw [← Term.TermVar_open_TermVar_subst_eq_Term_open_of_not_mem_freeTermVars xnin] exact EtyA.term_subst' FtyB theorem Term_multi_open (EtyA : [[Δ,,, , Δ' ⊢ E^^^x#n : A]]) (xninE : ∀ i, x i ∉ E.freeTermVars) (xninF : ∀ i, ∀ j ∈ [:n], x i ∉ (F j).freeTermVars) (xinj : x.Injective') (FtyB : ∀ i ∈ [:n], [[Δ ⊢ F@i : B@i]]) : [[Δ, Δ' ⊢ E^^^^F@@i#n/x : A]] := by match n with | 0 => rw [Range.map_same_eq_nil, Environment.multiTermExt, Term.TermVar_multi_open] at EtyA exact EtyA | n' + 1 => rw [Term.Term_multi_open] let mem : n' ∈ [:n'+1] := ⟨Nat.zero_le _, Nat.le.refl, Nat.mod_one _⟩ apply Term_multi_open _ (Term.not_mem_freeTermVars_Term_open_intro (xninE _) <| xninF · _ mem) (by intro i j mem exact xninF i _ ⟨Nat.zero_le _, Nat.lt_add_right _ mem.upper, Nat.mod_one _⟩ ) xinj (FtyB · ⟨Nat.zero_le _, Nat.lt_add_right _ ·.upper, Nat.mod_one _⟩) rw [Range.map_eq_snoc_of_lt (Nat.zero_lt_succ _), Environment.multiTermExt_snoc, Nat.succ_sub_one, Term.TermVar_multi_open, Term.TermVar_multi_open_comm Nat.le.refl] at EtyA rw [Term.Term_open_TermVar_multi_open_comm (FtyB _ mem |>.TermVarLocallyClosed_of) Nat.le.refl] let Δxwf := EtyA.WellFormedness_of.weakening.TermVar_drop (Δ' := .empty) apply EtyA.Term_open · apply Term.not_mem_freeTermVars_TermVar_multi_open_intro <| xninE n' intro i lt eq exact Nat.ne_of_lt lt <| xinj _ _ eq.symm · rw [← Environment.append_empty (Δ := .multiTermExt ..), Environment.multiTermExt_eq_append (Δ' := .empty), Environment.append_empty] at Δxwf ⊢ exact FtyB _ mem |>.weakening Δxwf (Δ'' := .empty) open Environment TermVarInEnvironment in theorem type_subst' (EtyA: [[ Δ, a: K, Δ' ⊢ E: A ]]) (BkiK : [[ Δ ⊢ B: K ]]): [[ Δ, Δ'[B/a] ⊢ E[B/a] : A[B/a] ]] := by generalize Δ_eq : [[ (Δ, a:K, Δ') ]] = Δ_ at EtyA induction EtyA generalizing Δ' <;> try simp_all [Term.TypeVar_subst, Type.TypeVar_subst] . case var Δ_ x' A wf x'in => subst Δ_ refine .var (wf.TypeVar_subst BkiK) ?_ obtain ⟨x'nin, x'in'⟩ | x'in' := x'in.append_elim . case inl.intro => -- a) x': A ∈ Δ, wts. x': A[B/α] ∈ Δ refine append_intro_l ?_ (by clear * - x'nin simp_all [TermVarNotInDom, TermVarInDom] induction Δ' <;> simp_all [TypeVar_subst, termVarDom] ) -- 1. by wf we know ∀x: A ∈ Δ, a ∉ A.freeTypeVars cases x'in'; case typeVarExt x'in' => rw [<- append_type_assoc] at wf have anin := x'in'.freeTypeVars_in_Δ wf.weakening a |>.mt (wf.append_typeVar_fresh_l a (by simp_all [typeVarDom_append, typeVarDom])) -- 2. so a ∉ A, therefore A[B/a] = A, so x': A[B/α] ∈ Δ. Done. rw [Type.TypeVar_subst_id_of_not_mem_freeTypeVars anin] exact x'in' . case inr => -- b) x': A ∈ Δ', by definition of Env.TypeVar_subst and Kind.TypeVar_subst we are done. clear * - x'in' induction x'in' <;> simp_all [TypeVar_subst] <;> constructor <;> simp_all . case lam Δ_ A1 E A2 I EtyA2 ih => subst Δ_ refine .lam (I := I ++ Δ.termVarDom ++ Δ'.termVarDom) (λ x xnin => ?_) rw [<- Term.TypeVar_open_TermVar_subst_comm] exact ih x (by simp_all) (by rw [append_termExt_assoc]) . case app Δ_ E1 A B E2 E1tyAB E2tyA ih1 ih2 => subst Δ_ exact .app (ih1 rfl) (ih2 rfl) . case typeLam Δ_ K' E A I EtyA ih => subst Δ_ refine .typeLam (I := a :: I ++ Δ.typeVarDom ++ Δ'.typeVarDom) (λ a' a'nin => ?_) rw [ <- BkiK.TypeVarLocallyClosed_of.Term_TypeVar_open_TypeVar_subst_comm (by aesop), <- BkiK.TypeVarLocallyClosed_of.TypeVar_open_TypeVar_subst_comm (by aesop) ] exact ih a' (by simp_all) (by rw [append_typeExt_assoc]) . case typeApp Δ_ E K2 A1 A2 EtyA1 A2kiK2 ih => subst Δ_ rw [BkiK.TypeVarLocallyClosed_of.Type_open_TypeVar_subst_dist] refine .typeApp (ih rfl) ?_ exact A2kiK2.subst' EtyA1.WellFormedness_of BkiK . case prodIntro Δ_ _ _ _ _ wf _ h _ => subst Δ_ refine .prodIntro (wf.subst BkiK) (by simp_all) h . case prodElim Δ_ E n A _ i EtyA iRange ih => subst Δ_ specialize ih rfl rw [Range.map_eq_of_eq_of_mem (fun _ _ => Function.comp.eq_def ..)] at ih have ⟨A', A'eq⟩: ∃A': ℕ → «Type», ∀i, A' i = (A i).TypeVar_subst a B := ⟨λi => (A i).TypeVar_subst a B, λi => by simp⟩ rw [<- A'eq i]; rw [<- funext (λi => A'eq i)] at ih refine .prodElim (n := n) ih iRange . case sumIntro _ n Δ_ _ _ _ _ EtyA A'kiStar h _ => subst Δ_ refine .sumIntro (n := n) (by simp_all) (by simp_all) (λ x xin => ?_) h exact A'kiStar x xin |>.subst' EtyA.WellFormedness_of BkiK . case sumElim Δ_ E n _ _ _ _ EtyA _ B'kiStar ih1 ih2 => subst Δ_ exact .sumElim (n := n) (ih1 rfl) (λ x xin => ih2 x xin rfl) (B'kiStar.subst' EtyA.WellFormedness_of BkiK) . case equiv Δ_ E A A' EtyA equiv ih => subst Δ_ refine .equiv (ih rfl) (equiv.subst' EtyA.TypeVarLocallyClosed_of EtyA.WellFormedness_of BkiK) theorem type_subst (EtyA: [[ Δ, a: K ⊢ E: A ]]) (BkiK : [[ Δ ⊢ B: K ]]): [[ Δ ⊢ E[B/a] : A[B/a] ]] := Typing.type_subst' (Δ' := [[(ε)]]) EtyA BkiK theorem Type_open (EtyA : Typing [[(Δ, a : K, Δ')]] (.TypeVar_open E a n) (.TypeVar_open A a n)) (aninE : a ∉ E.freeTypeVars) (aninA : a ∉ A.freeTypeVars) (Bki : [[Δ ⊢ B : K]]) : Typing [[(Δ, Δ' [B / a])]] (.Type_open E B n) (.Type_open A B n) := by rw [← Term.TypeVar_open_TypeVar_subst_eq_Type_open_of_not_mem_freeTypeVars aninE, ← Type.TypeVar_open_TypeVar_subst_eq_Type_open_of_not_mem_freeTypeVars aninA] exact EtyA.type_subst' Bki theorem Type_open_Type_open (EtyA : Typing [[(Δ, a : K, Δ')]] (.TypeVar_open E a m) (.Type_open A (.TypeVar_open B a n) l)) (aninE : a ∉ E.freeTypeVars) (aninA : a ∉ A.freeTypeVars) (aninB : a ∉ B.freeTypeVars) (B'ki : [[Δ ⊢ B' : K]]) : Typing [[(Δ, Δ' [B' / a])]] (.Type_open E B' m) (.Type_open A (.Type_open B B' n) l) := by let B'lc := B'ki.TypeVarLocallyClosed_of.weaken (n := l) rw [Nat.zero_add] at B'lc rw [← Term.TypeVar_open_TypeVar_subst_eq_Type_open_of_not_mem_freeTypeVars aninE, ← Type.TypeVar_open_TypeVar_subst_eq_Type_open_of_not_mem_freeTypeVars aninB, ← Type.TypeVar_subst_id_of_not_mem_freeTypeVars aninA, ← B'lc.Type_open_TypeVar_subst_dist] exact EtyA.type_subst' B'ki theorem Type_open_Type_multi_open (EtyA : [[Δ,, , Δ' ⊢ E^^^a#n : A^^(B^^^a#n)]]) (aninE : ∀ i, a i ∉ E.freeTypeVars) (aninA : ∀ i, a i ∉ A.freeTypeVars) (aninB : ∀ i, a i ∉ B.freeTypeVars) (aninB' : ∀ i, ∀ j ∈ [:n], a i ∉ (B' j).freeTypeVars) (ainj : a.Injective') (B'ki : ∀ i ∈ [:n], [[Δ ⊢ B'@i : K@i]]) : [[Δ, (Δ' ! ) ⊢ E^^^^B'@@i#n/a : A^^(B^^^^B'@@i#n/a)]] := by match n with | 0 => rw [Range.map_same_eq_nil, Environment.TypeVar_multi_subst] rw [Range.map_same_eq_nil, Environment.multiTypeExt, Term.TypeVar_multi_open, Type.TypeVar_multi_open] at EtyA exact EtyA | n' + 1 => rw [Range.map_eq_snoc_of_lt (Nat.zero_lt_succ _), Environment.TypeVar_multi_subst_snoc, Nat.succ_sub_one, Term.Type_multi_open, Type.Type_multi_open] let mem : n' ∈ [:n'+1] := ⟨Nat.zero_le _, Nat.le.refl, Nat.mod_one _⟩ apply Type_open_Type_multi_open _ (Term.not_mem_freeTypeVars_Type_open_intro (aninE _) <| aninB' · _ mem) aninA (Type.not_mem_freeTypeVars_Type_open_intro (aninB _) <| aninB' · _ mem) (aninB' · · ⟨Nat.zero_le _, Nat.lt_add_right _ ·.upper, Nat.mod_one _⟩) ainj (B'ki · ⟨Nat.zero_le _, Nat.lt_add_right _ ·.upper, Nat.mod_one _⟩) rw [Range.map_eq_snoc_of_lt (Nat.zero_lt_succ _), Environment.multiTypeExt_snoc, Nat.succ_sub_one, Term.TypeVar_multi_open, Term.TypeVar_multi_open_comm Nat.le.refl, Type.TypeVar_multi_open, Type.TypeVar_open_TypeVar_multi_open_comm Nat.le.refl] at EtyA let Blc := B'ki _ mem |>.TypeVarLocallyClosed_of rw [Term.Type_open_TypeVar_multi_open_comm Blc Nat.le.refl, Blc.Type_open_TypeVar_multi_open_comm Nat.le.refl] let .typeVarExt Δawf .. := EtyA.WellFormedness_of.weakening apply EtyA.Type_open_Type_open (Term.not_mem_freeTypeVars_TypeVar_multi_open_intro (aninE _) fun _ lt eq => Nat.ne_of_lt lt <| ainj _ _ eq.symm) (aninA _) (Type.not_mem_freeTypeVars_TypeVar_multi_open_intro (aninB _) fun _ lt eq => Nat.ne_of_lt lt <| ainj _ _ eq.symm) specialize B'ki _ mem rw [← Environment.append_empty (Δ := .multiTypeExt ..), Environment.multiTypeExt_eq_append (Δ' := .empty)] at Δawf ⊢ exact B'ki.weakening Δawf (Δ'' := .empty) end Typing theorem preservation.sandwich {α: Type} {nl nr : ℕ} {F1 F3: ℕ → α} {F2: α}: let G i := if i < nl then F1 i else if i = nl then F2 else F3 (i - nl - 1) [0:nl].map (λi => F1 i) ++ F2 :: [0:nr].map (λi => F3 i) = [0:nl + 1 + nr].map G := by intro G rw [progress.sandwich (n := nl + 1 + nr) (i := nl) (by omega)] simp_all refine List.append_eq_append ?_ ?_ . exact Std.Range.map_eq_of_eq_of_mem (λ i iltnl => by simp_all [Membership.mem]) . refine List.cons_eq_cons.mpr ⟨rfl, ?_⟩ refine Std.Range.map_eq_of_eq_of_mem (λ i iltnl => ?_) repeat' rw [if_neg (by omega)] exact congrArg _ (by omega) local instance : Inhabited Term where default := .prodIntro [] theorem preservation (EtyA: [[Δ ⊢ E : A]]) (EE': [[E -> E']]): [[Δ ⊢ E' : A]] := by induction EtyA generalizing E' <;> (try cases EE'; done) -- values can't step . case app Δ E A B F EtyAarrB FtyA ihE ihF => cases EE' . case appL E' EE' => exact .app (ihE EE') FtyA . case appR F' E FF' => exact .app EtyAarrB (ihF FF') . case lamApp A' E F => have ⟨eqA'A, I, EtyAarrB⟩ := EtyAarrB.inv_arr have ⟨x, notIn⟩ := (I ++ E.freeTermVars).exists_fresh rw [<- Term.TermVar_subst_intro_of_not_mem_freeTermVars (a := x) (by simp_all)] exact EtyAarrB x (by simp_all) |>.term_subst (.equiv FtyA eqA'A.symm) . case typeApp Δ E K A B EtyA BkiK ih => cases EE' . case typeApp E' EE' => exact .typeApp (ih EE') BkiK . case typeLamApp K' E => have ⟨Keq, I, EtyA⟩ := EtyA.inv_forall subst K' have ⟨a, notIn⟩ := (I ++ E.freeTypeVars ++ A.freeTypeVars).exists_fresh specialize EtyA a (by simp_all) rw [<- Term.TypeVar_subst_intro_of_not_mem_freeTypeVars (a := a) (by simp_all)] rw [<- Type.TypeVar_subst_intro_of_not_mem_freeTypeVars (a := a) (by simp_all)] exact EtyA.type_subst BkiK . case prodIntro Δ n E A _ wf EtyA h ih => generalize eqE_: Term.prodIntro ([0:n].map (λi => E i)) = E_ at EE' cases EE' <;> try cases eqE_ . case prodIntro E_ E' nl V nr Er EE' => injection eqE_ with eq have llt : nl < n := by have := congrArg List.length eq simp [List.length_append, List.length_cons, List.length_map, Std.Range.length_toList] at this omega rw [progress.sandwich llt] at eq have ⟨eql, eqr⟩ := List.append_inj eq (by simp_all [Std.Range.length_toList]); clear eq have eqEV := Std.Range.eq_of_mem_of_map_eq eql; clear eql injection eqr with eqEE_ eqr; simp at eqr; subst eqEE_ have := Std.Range.length_eq_of_mem_eq eqr; subst this have eqEEr_shift := Std.Range.eq_of_mem_of_map_eq eqr; clear eqr rw [preservation.sandwich] simp_all; rwomega nl + 1 + (n - (nl + 1)) = n refine .prodIntro wf (λ i iltn => ?_) h repeat' split . case _ iltnl => rw [← eqEV i (by simp_all [Membership.mem])] exact EtyA i (by simp_all [Membership.mem]) . case _ igenl ieqnl => subst i exact ih nl (by simp_all) EE' . case _ igenl inenl => rw [← eqEEr_shift _ (by simp_all [Membership.mem]; omega)] rwomega i - nl - 1 + (nl + 1) = i exact EtyA i (by simp_all [Membership.mem]) . case prodElim Δ E n A i EtyA iltn ih => cases EE' . case prodElim E' EE' => exact .prodElim (ih EE') iltn . case prodElimIntro n' E iltn' => clear ih have ⟨eqn'n, EtyA⟩ := EtyA.inv_prod simp_all [NatInZeroRange] . case sumIntro i n Δ E A ilen EtyA AkiStar ih => cases EE'; constructor <;> simp_all . case sumElim Δ E n A _ F B EtyA FtyAB BkiStar ih1 ih2 => generalize eqEF: [[ case E {} ]] = EF at EE' cases EE' <;> try cases eqEF . case sumElimL E_ E' n_ F_ EE' => injection eqEF with eqEE_ eq; subst E_ have eqnn_ := Std.Range.length_eq_of_mem_eq eq; subst eqnn_ have eqFF_ := Std.Range.eq_of_mem_of_map_eq eq; clear eq refine .sumElim (ih1 EE') (λ x xin => by simp_all) BkiStar . case sumElimR F_ F' V nl V' nr Fr FF' => simp_all obtain ⟨eqEV, eq⟩ := eqEF; subst E let G i := if i < nl then (V' i).val else if i = nl then F_ else Fr (i - nl - 1) let G' i := if i < nl then (V' i).val else if i = nl then F' else Fr (i - nl - 1) have Geq : [0:nl].map (λ i => (V' i).val) ++ F_ :: [0:nr].map (λ j => Fr j) = [0:nl + 1 + nr].map G := preservation.sandwich rw [Geq] at eq have G'eq : [0:nl].map (λ i => (V' i).val) ++ F' :: [0:nr].map (λ j => Fr j) = [0:nl + 1 + nr].map G' := preservation.sandwich rw [G'eq] have eqn := Std.Range.length_eq_of_mem_eq eq; subst eqn have : F nl = F_ := by clear * - Geq eq have eqFG : F nl = G nl := by clear * - eq have := congrArg (λ i => i.get! nl) eq simp only at this rw [ Std.Range.get!_map (by omega), Std.Range.get!_map (by omega)] at this exact this clear eq have := congrArg (λ i => i.get! nl) Geq simp only at this rw [Std.Range.get!_map (by omega)] at this rw [List.get!_eq_getD, List.getD_eq_getElem?_getD, List.getElem?_append, if_neg (by simp_all [Std.Range.length_toList]), List.length_map, Std.Range.length_toList] at this simp_all subst F_ have F'tyAB := ih2 nl (by simp_all [Membership.mem]; omega) FF' refine .sumElim EtyA (λ i iltn => ?_) BkiStar simp_all split . case isTrue iltnl => have eqFG := eq i (Std.Range.mem_toList_of_mem (by simp_all [Membership.mem])) specialize FtyAB i (by simp_all [Membership.mem]) rw [eqFG] at FtyAB unfold G at FtyAB simp_all . case isFalse igenl => split . case isTrue ieqnl => subst i exact ih2 nl (by simp_all) FF' . case isFalse inenl => have eqFG := eq i (Std.Range.mem_toList_of_mem (by simp_all [Membership.mem])) specialize FtyAB i (by simp_all [Membership.mem]) rw [eqFG] at FtyAB unfold G at FtyAB rw [← ite_not] at FtyAB simp_all . case sumElimIntro i n_ V V' iltn_ => injection eqEF with eqEV eq; subst E have eqnn_ := Std.Range.length_eq_of_mem_eq eq; subst eqnn_ have eqFV' := Std.Range.eq_of_mem_of_map_eq eq; clear eq have ⟨_, VtyA, _⟩ := EtyA.inv_sum refine .app (by simp_all) VtyA . case equiv Δ E A B EtyA eq ih => exact .equiv (ih EE') eq end TabularTypes.«F⊗⊕ω»