[MLton] cvs commit: improved exception history for Overflow
Stephen Weeks
MLton@mlton.org
Sun, 22 May 2005 18:40:09 -0700
> Here is another thought for improving exception history.
I like it.
> 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.
I've implemented your suggestion, and here is what is now displayed.
unhandled exception: Fail: here
with history:
loop.raise z.sml 4.24
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
> That eta expansion seems to be something that could easily be
> done in implementExceptions.
I don't think eta-expansion in XML is the way to go. The
Enter/Leave's have already been inserted, so going this way would mean
adding source position info to XML. It seems more direct to insert
Enter/Leave pairs (not eta-expand) at the same pass where all the
other Enter/Leave stuff is done.
> 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
True.
> 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".
Elaborate chooses the name when it inserts the Enter/Leave (see
elaborate-core.fun), so it can do anything it wants.
I ended up going for a two-piece solution that didn't require changing
any ILs. The elaborator wraps an Enter/Leave around each raise
expression, just as it does around each function body. The (still
horribly misnamed) defunctorizer wraps an Enter/Leave around each
raise {Bind,Match} that the match compiler generates. Fortunately, we
already had the source position info there for the warnings generated
by match compilation.
> 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.
This is true of the approach I took too. And I agree; it doesn't seem
bad to me.