Compiler Theory

Type Safety Proof

Prerequisites

A type safety proof for our languages requires

Examples

We first have to define some equivalence relation ab**, in order to talk about some results ofeval being equivalent.

v ≡ᵥ v Value equivalence

————————
 n ≡ᵥ n
————————
 b ≡ᵥ b
 v₁ ≡ᵥ v₁'     v₂ ≡ᵥ v₂'
—————————————————————————
 (v₁, v₂) ≡ᵥ (v₁', v₂')

a ≡ b Equivalence

 a ≡ᵥ b
————————
 a ≡ b
 a ≡ b     b ≡ c
—————————————————
      a ≡ c

Theorems

Theorem: for all n, m : Nat, eval(n + add1 m)eval(add1 n + m).

Proof (by induction on n):

Case 0: eval(0 + add1 m)eval(add1 0 + m)

Case add1 n': eval(add1 n' + add1 m)eval(add1 (add1 n') + m).

QED.

Theorem: for all n, m : Nat, eval(add1 n + m)eval(add1 (n + m)).

Proof (by induction on n):

Case 0: eval(add1 0 + m)eval(add1 (0 + m))

Case add1 n': eval(add1 (add1 n') + m)eval(add1 (add1 n' + m))

QED.

Theorem: for all n : Nat, eval(n + 0)eval(n).

Proof (by induction on n):

Case 0: eval(0 + 0)eval(0)

Case add1 m: eval(add1 m + 0)eval(add1 m)

QED.

Theorem: for all n, m : Nat, eval(n + m)eval(m + n).

Proof (by induction on n):

Case 0: eval(0 + m)eval(m + 0)

Case add1 n': eval(add1 n' + m)eval(m + add1 n')

QED.

Type safety proof

Proof (by induction on • ⊢ e : A):

Case Nat: if • ⊢ n : Nat, then eval(n) = n.

Case Bool: elided for brevity

Case If: If • ⊢ e : Bool implies eval(e) = v, • ⊢ e₁ : A implies eval(e₁) = v₁, • ⊢ e₂ : A implies eval(e₂) = v₂, then • ⊢ if e then e₁ else e2 implies eval(if e then e₁ else e₂) = v₃.

Case λ: If x : A ⊢ e : B implies then • ⊢ λx:A.e : A → B implies eval(λx:A.e) = v.

A way out

In order to prove type safety, we need to strengthen the theorem: we have to prove progress and preservation instead. In addition, for convenience, we define irreducibles and call values observables.

i ::= x | v | λx:A.`e

Lemma (progress): if • ⊢ e : A then either e is irreducible or e → e’.

Lemma (preservation): if Γ ⊢ e : A and e → e’ then Γ ⊢ e’ : A.

Furthermore, we define valid top level programs ⊢ e in order to rule out evaluating λs at the top level.

⊢ e Valid top level programs

 • ⊢ e : Nat
—————————————
     ⊢ e
 • ⊢ e : Bool
——————————————
      ⊢ e

Type safety, redefined

Theorem (type safety): if ⊢ e then eval(e) = v or eval(e`)** = Ω.

Proof: By progress, since • ⊢ e : A, either e is irreducible or e → e’.

Case e is irreducible: by canonical form, eval(e) = v, either e = n or e = b.

Case e → e’: we must show that either e’ is a value or by progress, e’ can continue computing, i.e. eval(e) = Ω.

Proof of progress

In order to prove progress, we have to change our model to include congruence closure.

We also change syntax for reduction relation to e ⊳ e.

The older syntax e → e is now reserved for congruence closure has all congruence rules (hence the name).

Conversion rules e →* e now only contain reflexivity and transitivity rules.

Also, congruence closure has a new rule.

 e ⊳ e'
————————
 e → e'

Proof (for progress):

Case Var: impossible

Case Add:

 • ⊢ e₁ : Nat     • ⊢ e₂ : Nat
———————————————————————————————
      • ⊢ e₁ + e₂ : Nat

And so on.

Note

Progress and preservation is a particular proof technique to prove type safety.