Description
The current dart sourcemap encodes a 1-to-1 mapping from JavaScript locations to Dart locations.
This is inadequate to decode the JavaScript stack to the correct Dart stack.
The JavaScript location below can be on the stack for two reasons:
a.foo();
^
(1) a
was null
, undefined
, or an object without a callable foo
. This case will be first frame of the stack.
(2) foo
was called and this is not the error location and is not the first stack frame.
These two cases can correspond to different Dart locations due to the optimization to remove null checks when the code will fail immediately after the null check.
Consider:
class Thing {
void bar() => this.foo();
// ^ [3]
void foo() { ... }
}
main() {
Thing? a = ...
final x = a!;
// ^ [1]
x.bar();
// ^ [2]
}
With the null-check optimization and inlining of bar()
, the generated code is a.foo()
.
The JavaScript stack needs to be decoded to two different stacks:
(1) When a.◆foo()
is at the top of the stack it corresponds to the location[1]
.
(2) When a.◆foo()
is in another stack frame it corresponds to the location [3]
called from [2]
.
Decoding the location to (2) when the location is the error location is confusing to users since it looks like bar
was called and somehow this
is impossibly null
.
To fix this situation the sourcemap needs extra information so that the error location at the top of the stack can be decoded independently of a successful call location below the top of the stack.