[MLton] Bug in optimizations related to ref cells?

Vesa Karvonen vesa.karvonen@cs.helsinki.fi
Sat, 16 Jul 2005 18:01:28 +0300


The below code passes the MLton typechecker (-stop tc), but fails in a later
optimization pass. Both SML/NJ (110.42) and Hamlet (1.2) appear to evaluate
the code correctly. (The code is part of *unfinished* conversion of SRFI-45
(http://srfi.schemers.org/srfi-45/) to Standard ML.)


$ cat bug-ref-mlton.sml

datatype ('a, 'b) either = LEFT of 'a | RIGHT of 'b

fun eval thunk =
    LEFT (thunk ()) handle e => RIGHT e

datatype 'a status = LAZY of unit -> 'a promise
                   | EAGER of ('a, exn) either
withtype 'a promise = 'a status ref ref

fun lazy exp =
    ref (ref (LAZY exp))

fun delay exp =
    lazy (fn () => ref (ref (EAGER (eval exp))))

fun force promise =
    case !(!promise)
     of EAGER (LEFT x) => x
      | EAGER (RIGHT x) => raise x
      | LAZY exp =>
        let
          val promise' = exp ()
        in
          (case !(!promise)
            of LAZY _ => (!promise := !(!promise') ;
                          promise' := !promise)
             | _ => ())
        ; force promise
        end

exception Assertion

fun check (b, e) = if b then () else raise e
fun verify b = check (b, Assertion)

val () =
    let
      val r = delay (fn () => (print "hi" ; 1))
      val s = lazy (fn () => r)
      val t = lazy (fn () => s)
    in
      verify (1 = force t)
    ; verify (1 = force r)
    end



$ mlton
MLton MLTONVERSION (built Sat Jul 16 16:50:43 2005 on grape)
$ mlton bug-ref-mlton.sml
Type error: SSa2.TypeCheck2.coerce
{from = (status_0 ref), to = status_0}
Type error: analyze raised exception unhandled exception: TypeError

unhandled exception: TypeError



$ mlton
MLton 20041109 (built Tue Nov 09 23:59:39 2004 on debian30)
$ mlton bug-ref-mlton.sml
Type error: TypeCheck.coerce
{from = (status_0 ref), to = status_0}
Type error: analyze raised exception force_0: loopStatement: promise'_0 := x_0:

unhandled exception: TypeError



Standard ML of New Jersey v110.42 [FLINT v1.5], October 16, 2002
- use "bug-ref-mlton.sml";
[opening bug-ref-mlton.sml]
hidatatype ('a,'b) either = LEFT of 'a | RIGHT of 'b
val eval = fn : (unit -> 'a) -> ('a,exn) either
datatype 'a status
  = EAGER of ('a,exn) either | LAZY of unit -> 'a status ref ref
type 'a promise = 'a status ref ref
val lazy = fn : (unit -> 'a promise) -> 'a status ref ref
val delay = fn : (unit -> 'a) -> 'a status ref ref
val force = fn : 'a status ref ref -> 'a
exception Assertion
val check = fn : bool * exn -> unit
val verify = fn : bool -> unit
val it = () : unit



HaMLet 1.2 - To Be Or Not To Be Standard ML
[loading standard basis library]
- use "bug-ref-mlton.sml";
val it = () : unit
[processing /home/vk/work/sml/articles/bug-ref-mlton.sml]
hitype 'a promise = 'a status ref ref
datatype ('a, 'b) either = LEFT of 'a | RIGHT of 'b
datatype 'a status =
  EAGER of ('a, exn) either | LAZY of unit -> 'a status ref ref
exception Assertion
val check = <fn> : bool * exn -> unit
val delay = <fn> : (unit -> 'a) -> 'a status ref ref
val eval = <fn> : (unit -> 'a) -> ('a, exn) either
val force = <fn> : 'a status ref ref -> 'a
val lazy = <fn> : (unit -> 'a status ref ref) -> 'a status ref ref
val verify = <fn> : bool -> unit