sdk
sdk copied to clipboard
dart2js internal naming conflict/shadowing between deferred parts and generics
Hi, my team noticed what seems to be a dart2js compiler bug involving internal dart2js variables shadowing each other.
The error we're getting looks like this:
Uncaught Error: NoSuchMethodError: method not found: 'memoize0__memo3$closure' (A1.memoize0__memo3$closure is not a function)
at Selector3Arg1.Selector3Arg1$_$5$customMemoizer (foo.dart.js_399.part.js:301672:34)
at Object.Selector3Arg1$_ (foo.dart.js_399.part.js:95754:10)
at Object.createSelector3Arg1 (foo.dart.js_399.part.js:95722:16)
at foo.dart.js_399.part.js:395563:16
at holder.<computed> (foo.dart.js:99:35)
at Object.Bar_create (foo.dart.js_399.part.js:73710:16)
With the dart2js line it was throwing on:
Selector3Arg1$_$5$customMemoizer(_selector1, _selector2, _selector3, resultFunc, customMemoizer, $S, A1, R1, R2, R3, $T) {
var t1 = A.instantiate4(A1.memoize0__memo3$closure(), R1, R2, R3, $T).call$1(new A.Selector3Arg1$__closure(this, R1, R2, R3, $T));
// ^^^^^^^^^^^^^^^^^^^^^^^
this.__Selector3Arg1__memoizedResultFunc_F !== $ && B.throwUnnamedLateFieldAI();
this.__Selector3Arg1__memoizedResultFunc_F = t1;
},
I did some local debugging, and it seems like the parameter name A1 corresponding to a generic parameter is shadowing the variable A1 corresponding to a Dart deferred part
Note how other code without an A1 generic references the correct A1 (outlined in magenta) as opposed to the incorrect A1 (outlined in green).
Dart source for dart2js-compiled code shown in the screenshot
// Application code
class Selector3Arg1<S, A1, R1, R2, R3, T> extends _Selector {
final R1 Function(S, A1) _selector1;
final R2 Function(S, A1) _selector2;
final R3 Function(S, A1) _selector3;
@visibleForTesting
final T Function(R1, R2, R3) resultFunc;
late final T Function(R1, R2, R3) _memoizedResultFunc;
Selector3Arg1._(
this._selector1, this._selector2, this._selector3, this.resultFunc,
{Selector3Memoizer<T, R1, R2, R3>? customMemoizer}) {
_memoizedResultFunc = (customMemoizer ?? memo3)((R1 r1, R2 r2, R3 r3) {
_recomputations++;
return resultFunc(r1, r2, r3);
});
}
T call(S state, A1 arg1) => _memoizedResultFunc(
_selector1(state, arg1),
_selector2(state, arg1),
_selector3(state, arg1),
);
}
class Selector3<S, R1, R2, R3, T> extends _Selector {
final R1 Function(S) _selector1;
final R2 Function(S) _selector2;
final R3 Function(S) _selector3;
@visibleForTesting
final T Function(R1, R2, R3) resultFunc;
late final T Function(R1, R2, R3) _memoizedResultFunc;
Selector3._(
this._selector1, this._selector2, this._selector3, this.resultFunc,
{Selector3Memoizer<T, R1, R2, R3>? customMemoizer}) {
_memoizedResultFunc = (customMemoizer ?? memo3)((R1 r1, R2 r2, R3 r3) {
_recomputations++;
return resultFunc(r1, r2, r3);
});
}
T call(S state) => _memoizedResultFunc(
_selector1(state),
_selector2(state),
_selector3(state),
);
}
// Relevant code from pub.dev/packages/memoize 3.0.0
typedef R Func3<A, B, C, R>(A a, B b, C c);
Func3<A, B, C, R> memo3<A, B, C, R>(Func3<A, B, C, R> func) {
late A prevArgA;
late B prevArgB;
late C prevArgC;
late R prevResult;
bool isInitial = true;
return ((A argA, B argB, C argC) {
if (!isInitial &&
argA == prevArgA &&
argB == prevArgB &&
argC == prevArgC) {
return prevResult;
} else {
prevArgA = argA;
prevArgB = argB;
prevArgC = argC;
prevResult = func(argA, argB, argC);
isInitial = false;
return prevResult;
}
});
}
Info on our SDK and build setup:
- Dart SDK: 2.19.6
- we're not able to build this specific app just yet with the latest Dart, but are actively working toward being able to
dart2js_argsin build:yaml:--csp -O3- We tried using different
-O…arguments and got different errors, which we're still investigating, and might be related - We found that it reproduces with either
--no-minifyand--minify
- We tried using different
I could try creating a reduced test case, but it seemed like it might be difficult to replicate the necessary conditions, so I figured I'd start with just reporting the issue.