Open FMorschel opened 3 days ago
Summary: The stack trace in Dart's uncaught exceptions
does not include the user's code when using a tear-off function, making it difficult to pinpoint the source of the error. This issue hinders debugging, especially in larger projects with multiple files.
That looks correct.
The controller2
is not a synchronous controller, so the call to the function argument to controller2.listen
happens in a later microtask. At that point there is nothing on the stack except the internal Stream
code that tries to call that function.
Then it calls the function, which is the tear-off controller1.add
, which is exactly what shows up in the stack trace.
There is no code from main
on the stack at this point, so the stack trace is correct.
In the first example, the argument function was (x) { controller1.add(x); }
, not controller.add1
. That adds one extra stack frame when called, which shows the location of controller.add(x)
in main
as that position that calls contoller1.add
.
Errors that happen in asynchronous code do not have the original stack any more, that's just how event loops work.
I know this is the current behaviour. Sorry if I was not clear on my request.
I'd like to ask if there is any way for the call stack to know about the call being a tear off (at least when developing). If this is possible, we could possibly show more information to the programmer in cases like the above so it's easier to find errors even in asynchronous code.
I guess could be technically possible for an instance member tear-off to record where in the code the tear-off occurred, at least in development mode. It will still be equal (==
) to another tear-off of the same function from the same object that happens in another place, but could maybe look different in stack traces.
Just to be clear, for the above case as an example, are you talking about controller1.add
knowing where it got used or controller2.stream.listen
knowing it received a tear off and where?
Just because both could help here but they would show slightly different things in the stack trace I believe.
I'm talking about controller.add
knowing where it was torn off, so that can show up in stack traces.
I doubt the caller itself will know where the function came from, anything special had to happen in the method.
I don't know how the tear-off works.
If there is no code in it, and calling it directly invokes the torn off method, there is nothing on the stack to recognize that it was involved.
If it contains any code, even if just a jmp
to the real method, it should be possible to do something else in development mode, like changing jmp
to call
+ret
, and have a stack entry.
(But I'll stop guessing now and leave this to people who actually know what the VM is doing.)
Repro:
This code throws an error:
Focus on line 1 (not 0) where it tells me the file, function, line and offset of where the error was thrown.
If you use a tear off:
This is the output:
I have no more reference as to where this happened on my code. I think this should be better handled for better DX. I was struggling for more than half an hour on my Flutter project with many different files and pages when I realized where this could be happening. The
uncaught exceptions
also triggers inside the framework code and there is no way for you to go back to your own code.