(* * Copyright (c) 2009 Robert Dockins and Aquinas Hobor. * *)
(** Here we prove that the "obvious" typing rule for allp introduction is incorrect. The correct rule has the "value restriction."  We want to show that this typing rule would allow us to type an unsafe program.  Here is the form of the incorrect rule. *)
Definition bad_UnivI_rule :=
forall G e (X:pred world -> pred world),
(forall tau, Typ G e (X tau)) ->
Typ G e (allp X).
(* Here is the program.  The problem is that the reference 'r' is used at two incompatible types. This program eventually attepmts to apply the nat 5 to the nat 42 which gets stuck.  The program, in pseudo-ML, is:  let f := (let r := new none in fun x => r := some x; r) in let a := f (fun z => z) in let b := f 5 in out (fun z => z) (!a) 42  *)
Definition crash :=
e_let
(* f := *)
( e_let (* r := *) (New none) (* in *)
(Lam (* x *)
(Update (Var 1 (*r*))
(*:=*) (App some (Var 0 (*x*))) (* ; *) (Var 1 (*r*))))) (* in *)
( e_let (* a := *) (App (Var 0 (*f*)) (Lam (Var 0))) (* in *)
(e_let (* b := *) (App (Var 1 (*f*)) (Nat 5))       (* in *)
(App (App (App out (Lam (Var 0))) (Deref (Var 1 (*a*)))) (Nat 42))
)).
(* In contrast, the following slight modification is safe.  We've inserted a lambda to make sure that the reference cell "inside" f isn't allocated until after polymorphic type instantiation.  This makes the expression a value, and allows us to apply the allp introduction rule with the value restriction. *)
Definition ok_program :=
e_let
(* f := *)
(Lam
( e_let (* r := *) (New none) (* in *)
(Lam (* x *)
(Update (Var 1 (*r*))
(*:=*) (App some (Var 0 (*x*))) (* ; *) (Var 1 (*r*)))))) (* in *)
( e_let (* a := *) (App (App (Var 0 (*f*)) (Nat 0)) (Lam (Var 0))) (* in *)
(e_let (* b := *) (App (App (Var 1 (*f*)) (Nat 0)) (Nat 5))       (* in *)
(App (App (App out (Lam (Var 0))) (Deref (Var 1 (*a*)))) (Nat 42))
)).

Theorem ok_program_safe :
safe_prog ok_program.