Asti's Notes
FP, Rx, EDA
Incorrect stack traces in F#
The stack trace missing a few calls?

Consider the following simple program:

let foo () =
    failwithf "foo"

[<EntryPoint>]
let main argv =
    foo ()
    0

Pretty straightforward. But depending on the circumstances, you may never see that foo in the stack trace.

Unhandled Exception: System.Exception: foo
   at Microsoft.FSharp.Core.PrintfModule.PrintFormatToStringThenFail@1639.Invoke(String message)
   at Program.main(String[] argv) in Program.fs:line 13

And the reason for that is optimizations. For fsc, optimizations are turned on by default.

Inlining

This is the most common thing you’re likely to see. foo() isn’t even called - if the method body is small enough, fsc will easily inline it. The resulting IL is equivalent to (all inlined):

let main argv =
	PrintfModule.PrintFormatToStringThenFail(new PrintfFormat<_>("foo"));
	0

Inlining can be disabled with --optimize-

fsc -g --optimize- Program.fs

Tail-call optimization

A tail-call optimization avoids allocating a new stack frame for a function call. Tail call optimizations can be applied for functions whose return value is the call to another function (or itself). And since it works by the elimination of stack-frames, you don’t see it in the stack trace.

foo meets this criteria as it shorts main.

Tail calls can be turned off this off with --tailcalls-.

Turning off optimizations

For the full debugging experience, go with a standard DEBUG configuration:

fsc --debug:full --define:DEBUG --define:TRACE --optimize- --tailcalls- Program.fs

The stack trace should be as expected:

Unhandled Exception: System.Exception: foo
   at Microsoft.FSharp.Core.PrintfModule.PrintFormatToStringThenFail@1639.Invoke(String message)
   at Program.foo[a]() in Program.fs:line 4
   at Program.main(String[] argv) in Program.fs:line 13

Last modified on 2020-03-23

Comments Disabled.