crosslang/golang-lean/GolangLean/Core/Preservation.lean
Maximus Gorog fd3d42ae33 Add 'golang-lean/' from commit 'f5f17019224c6a6c319387214ceb8e29d09251c6'
git-subtree-dir: golang-lean
git-subtree-mainline: 6487c7046f
git-subtree-split: f5f1701922
2026-05-12 02:59:14 -06:00

218 lines
7.8 KiB
Text

import GolangLean.Core.TypeSoundness
namespace GolangLean.Core
/-! # Preservation theorem for big-step semantics.
`Γ ⊢ e : T ∧ HasTypeH ht h ∧ HasTypeEnv ht env Γ ∧ BigStep h env e v h'
⟹ ∃ ht', HeapTy.extends ht ht' ∧ HasTypeH ht' h' ∧ HasTypeV ht' v T ∧ HasTypeEnv ht' env Γ`
By induction on the big-step derivation, with case-splits on the typing
hypothesis. Each rule case threads heap-typings through its sub-derivations
and weakens earlier results across the extension.
Big-step preservation has no progress analogue — the theorem only speaks
about derivations that exist. -/
/-! ## Heap extension by push. -/
theorem HeapTy.extends_push (ht : HeapTy) (T : Ty) : ht.extends (ht.push T) := by
refine ⟨by simp [Array.size_push], ?_⟩
intros i T' hL
rw [Array.getElem?_push]
by_cases heq : i = ht.size
· subst heq
have hnone : ht[ht.size]? = none := Array.getElem?_eq_none (Nat.le_refl _)
rw [hnone] at hL
contradiction
· simp [heq]; exact hL
/-! ## Heap-conformance preservation. -/
theorem HasTypeH.push
{ht : HeapTy} {h : Heap} {v : Value} {T : Ty}
(hH : HasTypeH ht h) (hV : HasTypeV ht v T) :
HasTypeH (ht.push T) (h.push v) := by
refine ⟨by simp [Array.size_push, hH.1], ?_⟩
intros i T' hL
rw [Array.getElem?_push] at hL
by_cases heq : i = ht.size
· subst heq
simp at hL
subst hL
refine ⟨v, ?_, hV.weaken (HeapTy.extends_push ht T)⟩
rw [Array.getElem?_push]
simp [hH.1]
· simp [heq] at hL
have ⟨v', hgv, hVT⟩ := hH.2 i T' hL
refine ⟨v', ?_, hVT.weaken (HeapTy.extends_push ht T)⟩
rw [Array.getElem?_push]
have hisize : i ≠ h.size := hH.1 ▸ heq
simp [hisize, hgv]
theorem HasTypeH.setIfInBounds
{ht : HeapTy} {h : Heap} {loc : Nat} {v : Value} {T : Ty}
(hH : HasTypeH ht h) (hV : HasTypeV ht v T)
(hLoc : (ht[loc]? : Option Ty) = some T) :
HasTypeH ht (h.setIfInBounds loc v) := by
refine ⟨by rw [Array.size_setIfInBounds]; exact hH.1, ?_⟩
intros i T' hL
by_cases hi : loc = i
· subst hi
rw [hL] at hLoc
simp at hLoc
subst hLoc
have hloc_lt : loc < h.size := by
rw [← hH.1]
rcases Nat.lt_or_ge loc ht.size with hlt | hge
· exact hlt
· rw [Array.getElem?_eq_none hge] at hL
contradiction
have heq : (h.setIfInBounds loc v)[loc]? = some v := by
rw [Array.getElem?_setIfInBounds]; simp [hloc_lt]
exact ⟨v, heq, hV⟩
· have ⟨v', hgv, hVT⟩ := hH.2 i T' hL
have heq : (h.setIfInBounds loc v)[i]? = some v' := by
rw [Array.getElem?_setIfInBounds, if_neg hi]; exact hgv
exact ⟨v', heq, hVT⟩
/-! ## Inversion for binop typing. -/
theorem binop_apply_sound
{ht : HeapTy} {op : BinOp} {v1 v2 v : Value} {T1 T2 T : Ty}
(hOp : op.typeOf T1 T2 = some T)
(hV1 : HasTypeV ht v1 T1) (hV2 : HasTypeV ht v2 T2)
(hApp : op.apply v1 v2 = some v) :
HasTypeV ht v T := by
cases op <;> cases T1 <;> cases T2 <;> simp [BinOp.typeOf] at hOp <;>
(try (cases hOp; cases hV1; cases hV2; simp [BinOp.apply] at hApp; cases hApp; constructor))
/-! ## Preservation. -/
theorem preservation :
∀ {h env e v h'} (D : BigStep h env e v h')
{ht Γ T} (hT : HasType Γ e T)
(hH : HasTypeH ht h) (hE : HasTypeEnv ht env Γ),
∃ ht', HeapTy.extends ht ht' ∧ HasTypeH ht' h' ∧
HasTypeV ht' v T ∧ HasTypeEnv ht' env Γ := by
intros h env e v h' D
induction D with
| unitR =>
intros ht Γ T hT hH hE
cases hT
exact ⟨ht, HeapTy.extends_refl _, hH, .vUnit, hE⟩
| intLitR n =>
intros ht Γ T hT hH hE
cases hT
exact ⟨ht, HeapTy.extends_refl _, hH, .vInt n, hE⟩
| boolLitR b =>
intros ht Γ T hT hH hE
cases hT
exact ⟨ht, HeapTy.extends_refl _, hH, .vBool b, hE⟩
| varR hLook =>
intros ht Γ T hT hH hE
cases hT with
| var hLookT =>
have ⟨v', hLook', hTV⟩ := hE.lookup_correspondence hLookT
rw [hLook] at hLook'
cases hLook'
exact ⟨ht, HeapTy.extends_refl _, hH, hTV, hE⟩
| lamR x body =>
intros ht Γ T hT hH hE
cases hT with
| lam hBody => exact ⟨ht, HeapTy.extends_refl _, hH, .vClos hE hBody, hE⟩
| appR _ _ _ ih1 ih2 ihb =>
intros ht Γ T hT hH hE
cases hT with
| app hT1 hT2 =>
have ⟨ht1, ext01, hH1, hClosT, hE1⟩ := ih1 hT1 hH hE
cases hClosT with
| vClos hEnv' hBody =>
have ⟨ht2, ext12, hH2, hArgT, _⟩ := ih2 hT2 hH1 hE1
have hEnv2 := hEnv'.weaken ext12
have ⟨ht3, ext23, hH3, hValT, _⟩ :=
ihb hBody hH2 (HasTypeEnv.cons hArgT hEnv2)
let totalExt := HeapTy.extends_trans (HeapTy.extends_trans ext01 ext12) ext23
exact ⟨ht3, totalExt, hH3, hValT, hE.weaken totalExt⟩
| letInR _ _ ih1 ih2 =>
intros ht Γ T hT hH hE
cases hT with
| letIn hT1 hT2 =>
have ⟨ht1, ext01, hH1, hV1, hE1⟩ := ih1 hT1 hH hE
have ⟨ht2, ext12, hH2, hV2, _⟩ :=
ih2 hT2 hH1 (HasTypeEnv.cons hV1 hE1)
let totalExt := HeapTy.extends_trans ext01 ext12
exact ⟨ht2, totalExt, hH2, hV2, hE.weaken totalExt⟩
| ifTR _ _ ihc iht =>
intros ht Γ T hT hH hE
cases hT with
| ifte hTc hT1 _ =>
have ⟨ht1, ext01, hH1, _, hE1⟩ := ihc hTc hH hE
have ⟨ht2, ext12, hH2, hV2, _⟩ := iht hT1 hH1 hE1
let totalExt := HeapTy.extends_trans ext01 ext12
exact ⟨ht2, totalExt, hH2, hV2, hE.weaken totalExt⟩
| ifFR _ _ ihc ihf =>
intros ht Γ T hT hH hE
cases hT with
| ifte hTc _ hT2 =>
have ⟨ht1, ext01, hH1, _, hE1⟩ := ihc hTc hH hE
have ⟨ht2, ext12, hH2, hV2, _⟩ := ihf hT2 hH1 hE1
let totalExt := HeapTy.extends_trans ext01 ext12
exact ⟨ht2, totalExt, hH2, hV2, hE.weaken totalExt⟩
| binopR _ _ hOp ih1 ih2 =>
intros ht Γ T hT hH hE
cases hT with
| binop hT1 hT2 hOpT =>
have ⟨ht1, ext01, hH1, hV1, hE1⟩ := ih1 hT1 hH hE
have ⟨ht2, ext12, hH2, hV2, _⟩ := ih2 hT2 hH1 hE1
let totalExt := HeapTy.extends_trans ext01 ext12
have hV1ext := hV1.weaken ext12
have hVT := binop_apply_sound hOpT hV1ext hV2 hOp
exact ⟨ht2, totalExt, hH2, hVT, hE.weaken totalExt⟩
| refMkR _ ih =>
intros ht Γ T hT hH hE
cases hT with
| @refMk _ _ T_inner hT1 =>
have ⟨ht1, ext01, hH1, hV, _⟩ := ih hT1 hH hE
have extPush := HeapTy.extends_push ht1 T_inner
have newExt := HeapTy.extends_trans ext01 extPush
have hHnew := hH1.push hV
have hVnew : HasTypeV (ht1.push T_inner) (.vLoc ht1.size) (.ref T_inner) := by
apply HasTypeV.vLoc
rw [Array.getElem?_push]
simp
rw [hH1.1] at hVnew
exact ⟨ht1.push T_inner, newExt, hHnew, hVnew, hE.weaken newExt⟩
| derefR _ Hget ih =>
intros ht Γ T hT hH hE
cases hT with
| @deref _ _ T_inner hT1 =>
have ⟨ht1, ext01, hH1, hVLoc, _⟩ := ih hT1 hH hE
cases hVLoc with
| vLoc hLocT =>
have ⟨v', hgv, hVT⟩ := hH1.2 _ _ hLocT
rw [Hget] at hgv
cases hgv
exact ⟨ht1, ext01, hH1, hVT, hE.weaken ext01⟩
| assignR _ _ Hin ih1 ih2 =>
intros ht Γ T hT hH hE
cases hT with
| @assign _ _ _ T_target hT1 hT2 =>
have ⟨ht1, ext01, hH1, hVLoc, hE1⟩ := ih1 hT1 hH hE
have ⟨ht2, ext12, hH2, hV2, _⟩ := ih2 hT2 hH1 hE1
cases hVLoc with
| vLoc hLocT =>
have hLocT2 := ext12.2 _ _ hLocT
have hH2new := hH2.setIfInBounds hV2 hLocT2
have totalExt := HeapTy.extends_trans ext01 ext12
exact ⟨ht2, totalExt, hH2new, .vUnit, hE.weaken totalExt⟩
| seqR _ _ ih1 ih2 =>
intros ht Γ T hT hH hE
cases hT with
| seq hT1 hT2 =>
have ⟨ht1, ext01, hH1, _, hE1⟩ := ih1 hT1 hH hE
have ⟨ht2, ext12, hH2, hV2, _⟩ := ih2 hT2 hH1 hE1
let totalExt := HeapTy.extends_trans ext01 ext12
exact ⟨ht2, totalExt, hH2, hV2, hE.weaken totalExt⟩
end GolangLean.Core