Skip to content

Commit b25873f

Browse files
srujzsCommit Queue
authored and
Commit Queue
committed
[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 <[email protected]> Commit-Queue: Srujan Gaddam <[email protected]>
1 parent 54faa31 commit b25873f

File tree

2 files changed

+54
-6
lines changed

2 files changed

+54
-6
lines changed

pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,7 @@ class _TypeSubstitutor extends ReplacementVisitor {
135135
}
136136
}
137137

138-
/// Erases usage of `@JS` classes that are annotated with `@staticInterop` in
139-
/// favor of `JavaScriptObject`.
138+
/// Erases usage of `@JS` classes that are annotated with `@staticInterop`.
140139
class StaticInteropClassEraser extends Transformer {
141140
final CloneVisitorNotMembers _cloner = CloneVisitorNotMembers();
142141
late final _StaticInteropConstantReplacer _constantReplacer;
@@ -259,7 +258,7 @@ class StaticInteropClassEraser extends Transformer {
259258
//
260259
// In order to circumvent this, we introduce a new static method that
261260
// clones the factory body and has a return type of
262-
// `JavaScriptObject`. Invocations of the factory are turned into
261+
// the erased type. Invocations of the factory are turned into
263262
// invocations of the static method. The original factory is still kept
264263
// in order to make modular compilations work.
265264
_findOrCreateFactoryStub(node);
@@ -290,7 +289,7 @@ class StaticInteropClassEraser extends Transformer {
290289
@override
291290
TreeNode visitConstructorInvocation(ConstructorInvocation node) {
292291
if (hasStaticInteropAnnotation(node.target.enclosingClass)) {
293-
// Add a cast so that the result gets typed as `JavaScriptObject`.
292+
// Add a cast so that the result gets typed as the erased type.
294293
var newInvocation = super.visitConstructorInvocation(node) as Expression;
295294
return AsExpression(
296295
newInvocation,
@@ -321,10 +320,12 @@ class StaticInteropClassEraser extends Transformer {
321320
return StaticInvocation(stub, args, isConst: node.isConst)
322321
..fileOffset = node.fileOffset;
323322
} else {
324-
// Add a cast so that the result gets typed as `JavaScriptObject`.
323+
// Add a cast so that the result gets typed as the erased type.
325324
var newInvocation = super.visitStaticInvocation(node) as Expression;
326325
return AsExpression(
327-
newInvocation, node.target.function.returnType as InterfaceType)
326+
newInvocation,
327+
_eraseStaticInteropType(
328+
node.target.function.returnType as InterfaceType))
328329
..fileOffset = newInvocation.fileOffset;
329330
}
330331
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// Test type parameters on @staticInterop factories.
6+
7+
import 'package:js/js.dart';
8+
import 'package:expect/minitest.dart';
9+
10+
@JS()
11+
@staticInterop
12+
class Array<T, U extends String> {
13+
external factory Array(T t, U u);
14+
factory Array.nonExternal(T t, U u) => Array(t, u);
15+
}
16+
17+
extension on Array {
18+
external Object operator [](int index);
19+
}
20+
21+
@JS()
22+
@staticInterop
23+
@anonymous
24+
class Anonymous<T, U extends String> {
25+
external factory Anonymous({T? t, U? u});
26+
factory Anonymous.nonExternal({T? t, U? u}) => Anonymous(t: t, u: u);
27+
}
28+
29+
extension AnonymousExtension<T, U extends String> on Anonymous<T, U> {
30+
external T get t;
31+
external U get u;
32+
}
33+
34+
void main() {
35+
final arr1 = Array(true, '');
36+
expect(arr1[0], true);
37+
expect(arr1[1], '');
38+
final arr2 = Array<bool, String>(false, '');
39+
expect(arr2[0], false);
40+
expect(arr2[1], '');
41+
final anon1 = Anonymous(t: true, u: '');
42+
expect(anon1.t, true);
43+
expect(anon1.u, '');
44+
final anon2 = Anonymous<bool, String>(t: false, u: '');
45+
expect(anon2.t, false);
46+
expect(anon2.u, '');
47+
}

0 commit comments

Comments
 (0)