enso-org / enso

Hybrid visual and textual functional programming.
https://enso.org
Apache License 2.0
7.31k stars 318 forks source link

Enso stack traces should correctly show stack traces of polyglot calls #5390

Open wdanilo opened 1 year ago

wdanilo commented 1 year ago

This task is automatically imported from the old Task Issue Board and it was originally created by Radosław Waśko. Original issue is here.


Why

As an Enso developer I want to be able to read stacktraces of failed calls, for example within tests So that I can locate the source of a failure

Acceptance Criteria

Scenario: 
Given a test suite calling a polyglot Java function
When an exception is thrown somewhere deep from the call-stack of the Java call
Then I want to be able to see the whole stacktrace when I catch the panic on Enso side

Notes:

To illustrate create a new project, compile Foo.java with contents shown below and place the result in polyglot/java directory:

package bar;

public class Foo {
    public static void foo() { bar(); }
    public static void bar() { baz(); }
    public static void baz() { throw new RuntimeException("Catch me if you can"); }
}

Now, modify src/Main.enso to:

from Standard.Base import all
polyglot java import bar.Foo
f1 = Foo.foo
f2 = f1
f3 = f2
main =
    Panic.catch Any f3 caught->
        caught.stack_trace.each IO.println
    f3

And run the project. You should see something like:

(Stack_Trace_Element 'com.oracle.truffle.host.HostObject.doInvoke' Nothing)
(Stack_Trace_Element 'com.oracle.truffle.host.HostObject.doInvoke' Nothing)
(Stack_Trace_Element 'Main.f1' (Source_Location src/Main.enso:5:6-12))
(Stack_Trace_Element 'Main.f2' (Source_Location src/Main.enso:7:6-7))
(Stack_Trace_Element 'Main.f3' (Source_Location src/Main.enso:9:6-7))
(Stack_Trace_Element 'argument<2>' (Source_Location src/Main.enso:12:21-22))
(Stack_Trace_Element 'Panic.catch_primitive' Nothing)
(Stack_Trace_Element 'Panic.catch' (Source_Location /home/radeusgd/NBO/enso/built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Error/Common.enso:381-391))
(Stack_Trace_Element 'Main.main' (Source_Location src/Main.enso:12-14))
(Stack_Trace_Element 'org.graalvm.polyglot.Value<Function>.execute' Nothing)
Execution finished with an error: Catch me if you can
        at <java> bar.Foo.baz(Foo.java:19)
        at <java> bar.Foo.bar(Foo.java:15)
        at <java> bar.Foo.foo(Foo.java:11)
        at <enso> Main.f1(src/Main.enso:5:6-12)
        at <enso> Main.f2(src/Main.enso:7:6-7)
        at <enso> Main.f3(src/Main.enso:9:6-7)
        at <enso> Main.main(src/Main.enso:15:5-6)

First, we see the stack trace accessible programmatically from Enso. We can see that the last interesting frame for us is the Main.f1 call pin-pointing that we call the polyglot method Foo.foo. But we know nothing more, as above that there are just two HostObject.doInvoke frames - which are really internal to the interpreter and I think ideally they shouldn't even exposed to the user, unless in some debug mode or on critical interpreter failure.

However, below we see the stack trace printed when the whole Enso program crashed (so it is printed by the program runner, not from within the Enso program itself). And here we see the complete stacktrace with foo calling bar and then baz - and now here we can correctly locate the true origin of the thrown exception.

This demonstrates that this exception info must be available somewhere, since the runner is able to extract it, but our programmatic methods for extracting stack traces from panics for some reason do not get that information in the way we'd like.

jdunkerley commented 1 year ago

This may have been fixed by simplifying the polyglot exception - should be checked still an issue before starting work.