mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
[dart2js] Erase static interop type in static invocation
Static invocations of external factories are casted so that the result, which is a @staticInterop type, can be treated as the erased type instead. This CL fixes the issue where the type that it was casted to was never replaced with the erased type. Change-Id: Ic6eb529349ea2b5c42f91c2740d501d4f81bc38e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/323505 Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Srujan Gaddam <srujzs@google.com>
This commit is contained in:
parent
54faa31964
commit
b25873f11c
2 changed files with 54 additions and 6 deletions
|
@ -135,8 +135,7 @@ class _TypeSubstitutor extends ReplacementVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Erases usage of `@JS` classes that are annotated with `@staticInterop` in
|
||||
/// favor of `JavaScriptObject`.
|
||||
/// Erases usage of `@JS` classes that are annotated with `@staticInterop`.
|
||||
class StaticInteropClassEraser extends Transformer {
|
||||
final CloneVisitorNotMembers _cloner = CloneVisitorNotMembers();
|
||||
late final _StaticInteropConstantReplacer _constantReplacer;
|
||||
|
@ -259,7 +258,7 @@ class StaticInteropClassEraser extends Transformer {
|
|||
//
|
||||
// In order to circumvent this, we introduce a new static method that
|
||||
// clones the factory body and has a return type of
|
||||
// `JavaScriptObject`. Invocations of the factory are turned into
|
||||
// the erased type. Invocations of the factory are turned into
|
||||
// invocations of the static method. The original factory is still kept
|
||||
// in order to make modular compilations work.
|
||||
_findOrCreateFactoryStub(node);
|
||||
|
@ -290,7 +289,7 @@ class StaticInteropClassEraser extends Transformer {
|
|||
@override
|
||||
TreeNode visitConstructorInvocation(ConstructorInvocation node) {
|
||||
if (hasStaticInteropAnnotation(node.target.enclosingClass)) {
|
||||
// Add a cast so that the result gets typed as `JavaScriptObject`.
|
||||
// Add a cast so that the result gets typed as the erased type.
|
||||
var newInvocation = super.visitConstructorInvocation(node) as Expression;
|
||||
return AsExpression(
|
||||
newInvocation,
|
||||
|
@ -321,10 +320,12 @@ class StaticInteropClassEraser extends Transformer {
|
|||
return StaticInvocation(stub, args, isConst: node.isConst)
|
||||
..fileOffset = node.fileOffset;
|
||||
} else {
|
||||
// Add a cast so that the result gets typed as `JavaScriptObject`.
|
||||
// Add a cast so that the result gets typed as the erased type.
|
||||
var newInvocation = super.visitStaticInvocation(node) as Expression;
|
||||
return AsExpression(
|
||||
newInvocation, node.target.function.returnType as InterfaceType)
|
||||
newInvocation,
|
||||
_eraseStaticInteropType(
|
||||
node.target.function.returnType as InterfaceType))
|
||||
..fileOffset = newInvocation.fileOffset;
|
||||
}
|
||||
}
|
||||
|
|
47
tests/lib/js/static_interop_test/generic_factory_test.dart
Normal file
47
tests/lib/js/static_interop_test/generic_factory_test.dart
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Test type parameters on @staticInterop factories.
|
||||
|
||||
import 'package:js/js.dart';
|
||||
import 'package:expect/minitest.dart';
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class Array<T, U extends String> {
|
||||
external factory Array(T t, U u);
|
||||
factory Array.nonExternal(T t, U u) => Array(t, u);
|
||||
}
|
||||
|
||||
extension on Array {
|
||||
external Object operator [](int index);
|
||||
}
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
@anonymous
|
||||
class Anonymous<T, U extends String> {
|
||||
external factory Anonymous({T? t, U? u});
|
||||
factory Anonymous.nonExternal({T? t, U? u}) => Anonymous(t: t, u: u);
|
||||
}
|
||||
|
||||
extension AnonymousExtension<T, U extends String> on Anonymous<T, U> {
|
||||
external T get t;
|
||||
external U get u;
|
||||
}
|
||||
|
||||
void main() {
|
||||
final arr1 = Array(true, '');
|
||||
expect(arr1[0], true);
|
||||
expect(arr1[1], '');
|
||||
final arr2 = Array<bool, String>(false, '');
|
||||
expect(arr2[0], false);
|
||||
expect(arr2[1], '');
|
||||
final anon1 = Anonymous(t: true, u: '');
|
||||
expect(anon1.t, true);
|
||||
expect(anon1.u, '');
|
||||
final anon2 = Anonymous<bool, String>(t: false, u: '');
|
||||
expect(anon2.t, false);
|
||||
expect(anon2.u, '');
|
||||
}
|
Loading…
Reference in a new issue