[MLton] cvs commit: improved exception history for Overflow
Matthew Fluet
fluet@cs.cornell.edu
Fri, 20 May 2005 09:53:27 -0400 (EDT)
Here is another thought for improving exception history.
Consider a program like the following:
-------------------------------------------------------------------
fun loop n =
if n > 12345
then let
val () = raise Fail "here"
in 2
end
else 1 + (loop (4 * n))
handle Overflow => 1
val _ = loop 1
-------------------------------------------------------------------
With -const 'Exn.keepHistory true' we get:
unhandled exception: Fail: here
with history:
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
This is fine, but I find it a little disappointing that the actual line
where the exception is raised is not in the history. If loop were a big
function with multiple occurences of raise Fail "here" it is ambiguous as
to which one is being raised. (As a more realistic example, consider a
large function with multiple non-exhaustive patterns. Then a Bind
exception is very ambiguous.) I note that if I change the program to the
following:
-------------------------------------------------------------------
fun loop n =
if n > 12345
then let
val () = (fn e => raise e) (Fail "here")
in 2
end
else 1 + (loop (4 * n))
handle Overflow => 1
val _ = loop 1
-------------------------------------------------------------------
Then we get:
with history:
loop.anon z.sml 4.17
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
loop z.sml 1.5
Which marks the exact point of the raised exception, along with the entire
call stack. That eta expansion seems to be something that could easily be
done in implementExceptions. Actually, since elaborate took care of
inserting the profile statements, the "eta expansion" would simply be to
wrap the raise expression with a new Enter/Leave pair. Note, we don't
want to do the eta expansion in or before elaborate for a couple of
reasons:
1) The compiler inserts Bind and Match exceptions after elaborate
2) The default profile insertion of elaborate would name the function
"anon" or some such, whereas if we do it later, we could give it a
better name of "raise".
On the other hand, adding the profile expressions in implementExceptions
is late enough in the game that we've lost the distinction between the
basis and the user code. So, that means that _all_ raised exceptions
would report the origin, not just those that were raised in user code.
This is different than the current behavior where an exception raised in
the basis is only given its point of origin when -profile-basis true is a
compile option. On the other hand, it is exactly one more entry in the
history, so it doesn't seem that bad.