Revert "[dart:js_interop] Add literal constructors for inline classes"
This reverts commit 1f6d4ae1a885f8958c2624381390dfa9a146d165.
Reason for revert: Broke Flutter with dart2wasm
Original change's description:
> [dart:js_interop] Add literal constructors for inline classes
>
> Adds @ObjectLiteral annotation to denote object literal constructors,
> and implements it in all the backends. For dart2js, this involves
> modifying the SSA and for dart2wasm, we create a one-per-shape
> forwarding procedure to a specialized JS method that returns the
> literal. This also modifies @anonymous semantics in dart2wasm to
> be consistent with the other backends.
>
> CoreLibraryReviewExempt: Backend-specific, just adding annotation.
> Change-Id: I4d7a9ea9ed097f4f378709b40f8bd74f02e26b23
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/283922
> Commit-Queue: Srujan Gaddam <srujzs@google.com>
> Reviewed-by: Joshua Litt <joshualitt@google.com>
Change-Id: Ifce611e1150d8aa275f9e312743bded56a572176
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/285342
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Srujan Gaddam <srujzs@google.com>
diff --git a/pkg/_js_interop_checks/lib/js_interop_checks.dart b/pkg/_js_interop_checks/lib/js_interop_checks.dart
index 00a6c68..c7ca65c 100644
--- a/pkg/_js_interop_checks/lib/js_interop_checks.dart
+++ b/pkg/_js_interop_checks/lib/js_interop_checks.dart
@@ -318,16 +318,12 @@
}
// Check JS Interop positional and named parameters.
- var isObjectLiteralFactory =
- _classHasAnonymousAnnotation && node.isFactory ||
- node.isInlineClassMember && hasObjectLiteralAnnotation(node);
- if (isObjectLiteralFactory) {
- var positionalParams = node.function.positionalParameters;
- if (node.isInlineClassMember) {
- positionalParams = positionalParams.skip(1).toList();
- }
- if (node.function.positionalParameters.isNotEmpty) {
- var firstPositionalParam = positionalParams[0];
+ var isAnonymousFactory = _classHasAnonymousAnnotation && node.isFactory;
+ if (isAnonymousFactory) {
+ // ignore: unnecessary_null_comparison
+ if (node.function != null &&
+ node.function.positionalParameters.isNotEmpty) {
+ var firstPositionalParam = node.function.positionalParameters[0];
_diagnosticsReporter.report(
messageJsInteropAnonymousFactoryPositionalParameters,
firstPositionalParam.fileOffset,
diff --git a/pkg/_js_interop_checks/lib/src/js_interop.dart b/pkg/_js_interop_checks/lib/src/js_interop.dart
index 73817ae..9eaa3ee 100644
--- a/pkg/_js_interop_checks/lib/src/js_interop.dart
+++ b/pkg/_js_interop_checks/lib/src/js_interop.dart
@@ -40,11 +40,6 @@
bool hasNativeAnnotation(Annotatable a) =>
a.annotations.any(_isNativeAnnotation);
-/// Returns true iff the node has an `@ObjectLiteral(...)` annotation from
-/// `dart:js_interop`.
-bool hasObjectLiteralAnnotation(Annotatable a) =>
- a.annotations.any(_isObjectLiteralAnnotation);
-
/// If [a] has a `@JS('...')` annotation, returns the value inside the
/// parentheses.
///
@@ -105,7 +100,6 @@
final _packageJs = Uri.parse('package:js/js.dart');
final _internalJs = Uri.parse('dart:_js_annotations');
final _jsHelper = Uri.parse('dart:_js_helper');
-final _jsInterop = Uri.parse('dart:js_interop');
/// Returns true if [value] is the interop annotation whose class is
/// [annotationClassName] from `package:js` or from `dart:_js_annotations`.
@@ -147,15 +141,6 @@
c.enclosingLibrary.importUri == _jsHelper;
}
-/// Returns true if [value] is the `ObjectLiteral` annotation from
-/// `dart:js_interop`.
-bool _isObjectLiteralAnnotation(Expression value) {
- var c = annotationClass(value);
- return c != null &&
- c.name == 'ObjectLiteral' &&
- c.enclosingLibrary.importUri == _jsInterop;
-}
-
/// Returns the class of the instance referred to by metadata annotation [node].
///
/// For example:
diff --git a/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart b/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
index dd48073..e45a224 100644
--- a/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
+++ b/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
@@ -14,7 +14,6 @@
hasInternalJSInteropAnnotation,
hasJSInteropAnnotation,
hasNativeAnnotation,
- hasObjectLiteralAnnotation,
hasStaticInteropAnnotation,
hasTrustTypesAnnotation;
@@ -175,9 +174,8 @@
if (node.isInlineClassMember) {
var kind =
_inlineExtensionIndex.getInlineDescriptor(node.reference)?.kind;
- return (kind == InlineClassMemberKind.Constructor ||
- kind == InlineClassMemberKind.Factory) &&
- !hasObjectLiteralAnnotation(node);
+ return kind == InlineClassMemberKind.Constructor ||
+ kind == InlineClassMemberKind.Factory;
} else {
return node.kind == ProcedureKind.Factory &&
node.enclosingClass != null &&
diff --git a/pkg/compiler/lib/src/common/names.dart b/pkg/compiler/lib/src/common/names.dart
index c216790..470f3f1 100644
--- a/pkg/compiler/lib/src/common/names.dart
+++ b/pkg/compiler/lib/src/common/names.dart
@@ -265,9 +265,6 @@
static final Uri dart__js_annotations =
Uri(scheme: 'dart', path: '_js_annotations');
- /// The URI for 'dart:js_interop'.
- static final Uri dart__js_interop = Uri(scheme: 'dart', path: 'js_interop');
-
/// The URI for 'package:meta/dart2js.dart'.
static final Uri package_meta_dart2js =
Uri(scheme: 'package', path: 'meta/dart2js.dart');
diff --git a/pkg/compiler/lib/src/ir/annotations.dart b/pkg/compiler/lib/src/ir/annotations.dart
index 6f4e99d..9dd62f4 100644
--- a/pkg/compiler/lib/src/ir/annotations.dart
+++ b/pkg/compiler/lib/src/ir/annotations.dart
@@ -18,7 +18,6 @@
final Map<ir.Class, String> _jsInteropClassNames = {};
final Set<ir.Class> _anonymousJsInteropClasses = {};
final Map<ir.Member, String> _jsInteropMemberNames = {};
- final Set<ir.Member> _jsInteropObjectLiterals = {};
final Map<ir.Member, List<PragmaAnnotationData>> _memberPragmaAnnotations =
{};
@@ -53,10 +52,6 @@
bool isAnonymousJsInteropClass(ir.Class node) =>
_anonymousJsInteropClasses.contains(node);
- // Returns `true` if [node] is annotated with `@ObjectLiteral`.
- bool isJsInteropObjectLiteral(ir.Member node) =>
- _jsInteropObjectLiterals.contains(node);
-
// Returns the text from the `@JS(<text>)` annotation of [node], if any.
String? getJsInteropMemberName(ir.Member node) => _jsInteropMemberNames[node];
@@ -79,15 +74,11 @@
});
}
- void forEachJsInteropMember(
- void Function(ir.Member, String?,
- {required bool isJsInteropObjectLiteral})
- f) {
+ void forEachJsInteropMember(void Function(ir.Member, String?) f) {
_jsInteropLibraryNames.forEach((ir.Library library, _) {
for (ir.Member member in library.members) {
if (member.isExternal) {
- f(member, _jsInteropMemberNames[member] ?? member.name.text,
- isJsInteropObjectLiteral: isJsInteropObjectLiteral(member));
+ f(member, _jsInteropMemberNames[member] ?? member.name.text);
}
}
});
@@ -98,7 +89,7 @@
if (member.isExternal) {
name ??= member.name.text;
}
- f(member, name, isJsInteropObjectLiteral: false);
+ f(member, name);
}
});
}
@@ -151,12 +142,6 @@
data._jsInteropMemberNames[member] = jsName;
}
- bool isJsInteropObjectLiteralMember =
- _isJsInteropObjectLiteral(constant);
- if (isJsInteropObjectLiteralMember) {
- data._jsInteropObjectLiterals.add(member);
- }
-
bool isNativeMember = _isNativeMember(constant);
if (isNativeMember) {
data._nativeMembers.add(member);
@@ -333,12 +318,6 @@
Uris.dart__js_annotations);
}
-bool _isJsInteropObjectLiteral(ir.Constant constant) {
- return constant is ir.InstanceConstant &&
- constant.classNode.name == 'ObjectLiteral' &&
- constant.classNode.enclosingLibrary.importUri == Uris.dart__js_interop;
-}
-
class PragmaAnnotationData {
// TODO(johnniwinther): Support non 'dart2js:' pragma names if necessary.
final String suffix;
diff --git a/pkg/compiler/lib/src/js_backend/native_data.dart b/pkg/compiler/lib/src/js_backend/native_data.dart
index cbfc682..f8b2141 100644
--- a/pkg/compiler/lib/src/js_backend/native_data.dart
+++ b/pkg/compiler/lib/src/js_backend/native_data.dart
@@ -35,9 +35,6 @@
/// The JavaScript members implemented via typed JavaScript interop.
final Map<MemberEntity, String> _jsInteropMembers = {};
- /// The JavaScript interop members annotated with `@ObjectLiteral`.
- final Set<MemberEntity> _jsInteropObjectLiterals = {};
-
/// Sets the native tag info for [cls].
///
/// The tag info string contains comma-separated 'words' which are either
@@ -102,8 +99,7 @@
/// Marks [element] as an explicit part of js interop and sets the explicit js
/// interop [name] for the member [element].
- void markAsJsInteropMember(MemberEntity element, String name,
- {required bool isJsInteropObjectLiteral}) {
+ void markAsJsInteropMember(MemberEntity element, String name) {
assert(
!_closed,
failedAt(
@@ -111,7 +107,6 @@
"NativeBasicDataBuilder is closed. "
"Trying to mark $element as a js-interop member."));
_jsInteropMembers[element] = name;
- if (isJsInteropObjectLiteral) _jsInteropObjectLiterals.add(element);
}
/// Creates the [NativeBasicData] object for the data collected in this
@@ -125,8 +120,7 @@
_jsInteropLibraries,
_jsInteropClasses,
_anonymousJsInteropClasses,
- _jsInteropMembers,
- _jsInteropObjectLiterals);
+ _jsInteropMembers);
}
void reopenForTesting() {
@@ -162,9 +156,6 @@
/// The JavaScript members implemented via typed JavaScript interop.
final Map<MemberEntity, String?> _jsInteropMembers;
- /// JavaScript interop constructors annotated with `@ObjectLiteral`.
- final Set<MemberEntity> _jsInteropObjectLiterals;
-
NativeBasicData(
this._env,
this._isAllowInteropUsed,
@@ -172,8 +163,7 @@
this._jsInteropLibraries,
this._jsInteropClasses,
this._anonymousJsInteropClasses,
- this._jsInteropMembers,
- this._jsInteropObjectLiterals);
+ this._jsInteropMembers);
factory NativeBasicData.fromIr(
KernelToElementMap map, IrAnnotationData data) {
@@ -183,7 +173,6 @@
Map<ClassEntity, String> jsInteropClasses = {};
Set<ClassEntity> anonymousJsInteropClasses = {};
Map<MemberEntity, String?> jsInteropMembers = {};
- Set<MemberEntity> jsInteropObjectLiterals = {};
data.forEachNativeClass((ir.Class node, String text) {
nativeClassTagInfo[map.getClass(node)] = NativeClassTag(text);
@@ -200,27 +189,17 @@
anonymousJsInteropClasses.add(cls);
}
});
- data.forEachJsInteropMember((ir.Member node, String? name,
- {required bool isJsInteropObjectLiteral}) {
+ data.forEachJsInteropMember((ir.Member node, String? name) {
// TODO(49428): Are there other members that we should ignore here?
// There are non-external and unannotated members because the source code
// doesn't contain them. (e.g. default constructor) Does it make sense to
// consider these valid JS members?
if (memberIsIgnorable(node)) return;
jsInteropMembers[map.getMember(node)] = name;
- if (isJsInteropObjectLiteral)
- jsInteropObjectLiterals.add(map.getMember(node));
});
- return NativeBasicData(
- env,
- false,
- nativeClassTagInfo,
- jsInteropLibraries,
- jsInteropClasses,
- anonymousJsInteropClasses,
- jsInteropMembers,
- jsInteropObjectLiterals);
+ return NativeBasicData(env, false, nativeClassTagInfo, jsInteropLibraries,
+ jsInteropClasses, anonymousJsInteropClasses, jsInteropMembers);
}
/// Deserializes a [NativeBasicData] object from [source].
@@ -241,7 +220,6 @@
Set<ClassEntity> anonymousJsInteropClasses = source.readClasses().toSet();
Map<MemberEntity, String?> jsInteropMembers = source
.readMemberMap((MemberEntity member) => source.readStringOrNull());
- Set<MemberEntity> jsInteropObjectLiterals = source.readMembers().toSet();
source.end(tag);
return NativeBasicData(
elementEnvironment,
@@ -250,8 +228,7 @@
jsInteropLibraries,
jsInteropClasses,
anonymousJsInteropClasses,
- jsInteropMembers,
- jsInteropObjectLiterals);
+ jsInteropMembers);
}
/// Serializes this [NativeBasicData] to [sink].
@@ -267,7 +244,6 @@
sink.writeClasses(_anonymousJsInteropClasses);
sink.writeMemberMap(_jsInteropMembers,
(MemberEntity member, String? name) => sink.writeStringOrNull(name));
- sink.writeMembers(_jsInteropObjectLiterals);
sink.end(tag);
}
@@ -372,8 +348,6 @@
map.toBackendClassSet(_anonymousJsInteropClasses);
Map<MemberEntity, String?> jsInteropMembers =
map.toBackendMemberMap(_jsInteropMembers, identity);
- Set<MemberEntity> jsInteropObjectLiterals =
- map.toBackendMemberSet(_jsInteropObjectLiterals);
return NativeBasicData(
environment,
isAllowInteropUsed,
@@ -381,8 +355,7 @@
jsInteropLibraries,
jsInteropClasses,
anonymousJsInteropClasses,
- jsInteropMembers,
- jsInteropObjectLiterals);
+ jsInteropMembers);
}
}
@@ -596,20 +569,11 @@
Map<MemberEntity, String?> get _jsInteropMembers =>
_nativeBasicData._jsInteropMembers;
- @override
- Set<MemberEntity> get _jsInteropObjectLiterals =>
- _nativeBasicData._jsInteropObjectLiterals;
-
/// Returns `true` if [element] has an `@Anonymous` annotation.
bool isAnonymousJsInteropClass(ClassEntity element) {
return _anonymousJsInteropClasses.contains(element);
}
- /// Returns `true` if [element] has an `@ObjectLiteral` annotation.
- bool isJsInteropObjectLiteral(MemberEntity element) {
- return _jsInteropObjectLiterals.contains(element);
- }
-
@override
bool isNativeClass(ClassEntity element) =>
_nativeBasicData.isNativeClass(element);
diff --git a/pkg/compiler/lib/src/kernel/native_basic_data.dart b/pkg/compiler/lib/src/kernel/native_basic_data.dart
index a82e311..7aa06f3 100644
--- a/pkg/compiler/lib/src/kernel/native_basic_data.dart
+++ b/pkg/compiler/lib/src/kernel/native_basic_data.dart
@@ -86,9 +86,7 @@
/*reporter.reportErrorMessage(
function, MessageKind.JS_INTEROP_NON_EXTERNAL_MEMBER);*/
} else {
- _nativeBasicDataBuilder.markAsJsInteropMember(function, memberName,
- isJsInteropObjectLiteral:
- annotationData.isJsInteropObjectLiteral(memberNode));
+ _nativeBasicDataBuilder.markAsJsInteropMember(function, memberName);
// TODO(johnniwinther): It is unclear whether library can be
// implicitly js-interop. For now we allow it.
isJsLibrary = true;
@@ -130,8 +128,7 @@
// TODO(johnniwinther): The documentation states that explicit
// member name annotations are not allowed on instance members.
_nativeBasicDataBuilder.markAsJsInteropMember(
- function, memberName,
- isJsInteropObjectLiteral: false);
+ function, memberName);
}
}
});
@@ -148,8 +145,7 @@
// TODO(johnniwinther): The documentation states that explicit
// member name annotations are not allowed on instance members.
_nativeBasicDataBuilder.markAsJsInteropMember(
- constructor, memberName,
- isJsInteropObjectLiteral: false);
+ constructor, memberName);
}
});
}
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index a42be0a..133a7ec 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -3908,16 +3908,11 @@
List.from(_visitPositionalArguments(arguments));
if (target.namedParameters.isNotEmpty) {
- // Only anonymous factory or inline class literal constructors involving
- // JS interop are allowed to have named parameters. Otherwise, throw an
- // error.
+ // Only anonymous factory constructors involving JS interop are allowed to
+ // have named parameters. Otherwise, throw an error.
final function =
_elementMap.getMember(target.parent as ir.Member) as FunctionEntity;
- if (function is ConstructorEntity &&
- function.isFactoryConstructor &&
- _nativeData.isAnonymousJsInteropClass(function.enclosingClass) ||
- function.isTopLevel &&
- _nativeData.isJsInteropObjectLiteral(function)) {
+ if (function is ConstructorEntity && function.isFactoryConstructor) {
// TODO(sra): Have a "CompiledArguments" structure to just update with
// what values we have rather than creating a map and de-populating it.
Map<String, HInstruction> namedValues = _visitNamedArguments(arguments);
@@ -5424,11 +5419,11 @@
assert(closedWorld.nativeData.isJsInteropMember(element));
if (element is ConstructorEntity &&
- element.isFactoryConstructor &&
- _nativeData.isAnonymousJsInteropClass(element.enclosingClass) ||
- element.isTopLevel && _nativeData.isJsInteropObjectLiteral(element)) {
- // Constructor that is syntactic sugar for creating a JavaScript object
- // literal.
+ element.isFactoryConstructor &&
+ _nativeData.isAnonymousJsInteropClass(element.enclosingClass)) {
+ // Factory constructor that is syntactic sugar for creating a JavaScript
+ // object literal.
+ ConstructorEntity constructor = element;
int i = 0;
int positions = 0;
List<HInstruction> filteredArguments = [];
@@ -5440,7 +5435,7 @@
// TODO(johnniwinther): can we elide those parameters? This should be
// consistent with what we do with instance methods.
final node =
- _elementMap.getMemberDefinition(element).node as ir.Procedure;
+ _elementMap.getMemberDefinition(constructor).node as ir.Procedure;
List<ir.VariableDeclaration> namedParameters =
node.function.namedParameters.toList();
namedParameters.sort(nativeOrdering);
diff --git a/pkg/dart2wasm/lib/js_runtime_generator.dart b/pkg/dart2wasm/lib/js_runtime_generator.dart
index 2d93a7ae..e377a15 100644
--- a/pkg/dart2wasm/lib/js_runtime_generator.dart
+++ b/pkg/dart2wasm/lib/js_runtime_generator.dart
@@ -7,9 +7,8 @@
calculateTransitiveImportsOfJsInteropIfUsed,
getJSName,
hasAnonymousAnnotation,
- hasJSInteropAnnotation,
- hasObjectLiteralAnnotation,
- hasStaticInteropAnnotation;
+ hasStaticInteropAnnotation,
+ hasJSInteropAnnotation;
import 'package:_js_interop_checks/src/transformations/js_util_optimizer.dart'
show InlineExtensionIndex;
import 'package:_js_interop_checks/src/transformations/static_interop_class_eraser.dart';
@@ -37,64 +36,32 @@
final Procedure procedure;
final _MethodType type;
final String jsString;
- final StaticInvocation? invocation;
final InlineExtensionIndex _inlineExtensionIndex;
late final bool isConstructor =
type == _MethodType.jsObjectLiteralConstructor ||
type == _MethodType.constructor;
late final bool firstParameterIsObject =
_inlineExtensionIndex.isInstanceInteropMember(procedure);
- late final List<VariableDeclaration> parameters = _parameters;
- late final List<Expression> arguments = _arguments;
+ late final List<VariableDeclaration> parameters =
+ type == _MethodType.jsObjectLiteralConstructor
+ ? function.namedParameters
+ : function.positionalParameters;
+ late String tag = procedure.name.text.replaceAll(RegExp(r'[^a-zA-Z_]'), '_');
- _MethodLoweringConfig(this.procedure, this.type, this.jsString,
- this.invocation, this._inlineExtensionIndex);
+ _MethodLoweringConfig(
+ this.procedure, this.type, this.jsString, this._inlineExtensionIndex);
FunctionNode get function => procedure.function;
Uri get fileUri => procedure.fileUri;
- // The parameters that determine arity (and key names in the case of object
- // literals) of the interop procedure that is created from this config.
- List<VariableDeclaration> get _parameters {
- if (type == _MethodType.jsObjectLiteralConstructor) {
- // Compute the parameters that were used in the given `invocation`. Note
- // that we preserve the procedure's ordering and not the invocations.
- Set<String> usedArgs =
- invocation!.arguments.named.map((expr) => expr.name).toSet();
- return function.namedParameters
- .where((decl) => usedArgs.contains(decl.name))
- .toList();
- }
- return function.positionalParameters;
- }
-
- // The arguments that will be passed into the interop procedure that is
- // created from this config.
- List<Expression> get _arguments {
- if (type == _MethodType.jsObjectLiteralConstructor) {
- // Return the args in the order of the procedure's parameters and not the
- // invocation.
- Map<String, Expression> namedArgs = {};
- for (NamedExpression expr in invocation!.arguments.named) {
- namedArgs[expr.name] = expr.value;
- }
- return parameters
- .map<Expression>((decl) => namedArgs[decl.name!]!)
- .toList();
- }
- return function.positionalParameters
- .map((decl) => VariableGet(decl))
- .toList();
- }
-
- String generateJS(List<String> parameterNames) {
+ String generateJS(List<String> parameters) {
String object = isConstructor
? ''
: firstParameterIsObject
- ? parameterNames[0]
+ ? parameters[0]
: 'globalThis';
List<String> callArguments =
- firstParameterIsObject ? parameterNames.sublist(1) : parameterNames;
+ firstParameterIsObject ? parameters.sublist(1) : parameters;
String callArgumentsString = callArguments.join(',');
String functionParameters = firstParameterIsObject
? '$object${callArguments.isEmpty ? '' : ',$callArgumentsString'}'
@@ -102,10 +69,11 @@
String bodyString;
switch (type) {
case _MethodType.jsObjectLiteralConstructor:
- List<String> keys = parameters.map((named) => named.name!).toList();
+ List<String> keys =
+ function.namedParameters.map((named) => named.name!).toList();
List<String> keyValuePairs = [];
- for (int i = 0; i < parameterNames.length; i++) {
- keyValuePairs.add('${keys[i]}: ${parameterNames[i]}');
+ for (int i = 0; i < parameters.length; i++) {
+ keyValuePairs.add('${keys[i]}: ${parameters[i]}');
}
bodyString = '({${keyValuePairs.join(',')}})';
break;
@@ -131,7 +99,7 @@
}
break;
}
- if (parametersNeedParens(parameterNames)) {
+ if (parametersNeedParens(parameters)) {
return '($functionParameters) => $bodyString';
} else {
return '$functionParameters => $bodyString';
@@ -173,7 +141,6 @@
int _methodN = 1;
late Library _library;
late String _libraryJSString;
- final Map<Procedure, Map<String, Procedure>> _jsObjectLiteralMethods = {};
final CoreTypes _coreTypes;
late InlineExtensionIndex _inlineExtensionIndex;
@@ -255,19 +222,6 @@
return _functionToJS(node.target, functionType as FunctionType, argument);
} else if (node.target == _inlineJSTarget) {
return _expandInlineJS(node.target, node);
- } else if ((node.target.isInlineClassMember &&
- node.target.isExternal &&
- hasObjectLiteralAnnotation(node.target)) ||
- (node.target.isFactory &&
- node.target.isExternal &&
- hasAnonymousAnnotation(node.target.enclosingClass!))) {
- assert(node.arguments.positional.isEmpty);
- return _specializeJSMethod(_MethodLoweringConfig(
- node.target,
- _MethodType.jsObjectLiteralConstructor,
- '',
- node,
- _inlineExtensionIndex));
}
return node;
}
@@ -317,7 +271,11 @@
Class cls = node.enclosingClass!;
jsString = _getTopLevelJSString(cls, cls.name);
if (node.isFactory) {
- if (!hasAnonymousAnnotation(cls)) type = _MethodType.constructor;
+ if (hasAnonymousAnnotation(cls)) {
+ type = _MethodType.jsObjectLiteralConstructor;
+ } else {
+ type = _MethodType.constructor;
+ }
} else {
String memberSelectorString = _getJSString(node, node.name.text);
jsString = '$jsString.$memberSelectorString';
@@ -331,9 +289,8 @@
_inlineExtensionIndex.getInlineClass(node.reference)!;
InlineClassMemberKind kind = nodeDescriptor.kind;
jsString = _getTopLevelJSString(cls, cls.name);
- if ((kind == InlineClassMemberKind.Constructor ||
- kind == InlineClassMemberKind.Factory) &&
- !hasObjectLiteralAnnotation(node)) {
+ if (kind == InlineClassMemberKind.Constructor ||
+ kind == InlineClassMemberKind.Factory) {
type = _MethodType.constructor;
} else if (nodeDescriptor.isStatic) {
String memberSelectorString =
@@ -375,11 +332,8 @@
type = _getTypeForNonExtensionMember(node);
}
if (type != null) {
- Expression invocation = _specializeJSMethod(_MethodLoweringConfig(
- node, type, jsString, null, _inlineExtensionIndex));
- transformedBody = node.function.returnType is VoidType
- ? ExpressionStatement(invocation)
- : ReturnStatement(invocation);
+ transformedBody = _specializeJSMethod(
+ _MethodLoweringConfig(node, type, jsString, _inlineExtensionIndex));
}
}
if (transformedBody != null) {
@@ -703,9 +657,9 @@
functionType:
target.function.computeFunctionType(Nullability.nonNullable));
- /// Creates a Dart procedure that calls out to a specialized JS method for the
- /// given [config] and returns the created procedure.
- Procedure _getInteropProcedure(_MethodLoweringConfig config) {
+ // Specializes a JS method for a given [_MethodLoweringConfig] and returns an
+ // invocation of the specialized method.
+ Statement _specializeJSMethod(_MethodLoweringConfig config) {
// Initialize variable declarations.
List<String> jsParameterStrings = [];
List<VariableDeclaration> originalParameters = config.parameters;
@@ -733,61 +687,40 @@
jsMethods[dartProcedure] =
"$jsMethodName: ${config.generateJS(jsParameterStrings)}";
- return dartProcedure;
- }
-
- /// Specializes a JS method for a given [config] and returns an invocation of
- /// the specialized method.
- Expression _specializeJSMethod(_MethodLoweringConfig config) {
- Procedure interopProcedure;
- if (config.type == _MethodType.jsObjectLiteralConstructor) {
- // To avoid one method for every invocation, we optimize and compute one
- // method per invocation shape. For example, `Cons(a: 0, b: 0)`,
- // `Cons(a: 0)`, and `Cons(a: 1, b: 1)` only create two shapes:
- // `{a: value, b: value}` and `{a: value}`. Therefore, we only need two
- // methods to handle the `Cons` invocations.
- String shape = config.parameters
- .map((VariableDeclaration decl) => decl.name)
- .join('|');
- _jsObjectLiteralMethods
- .putIfAbsent(config.procedure, () => {})
- .putIfAbsent(shape, () => _getInteropProcedure(config));
- interopProcedure = _jsObjectLiteralMethods[config.procedure]![shape]!;
- } else {
- interopProcedure = _getInteropProcedure(config);
- }
// Return the replacement body.
// Because we simply don't have enough information, we leave all JS numbers
// as doubles. However, in cases where we know the user expects an `int` we
// insert a cast. We also let static interop types flow through without
// conversion, both as arguments, and as the return type.
DartType returnType = config.function.returnType;
- List<Expression> positionalArgs = config.arguments
- .map((expr) => StaticInvocation(
- _jsifyTarget(expr.getStaticType(_staticTypeContext)),
- Arguments([expr])))
- .toList();
- Expression invocation =
- StaticInvocation(interopProcedure, Arguments(positionalArgs));
+ Expression invocation = StaticInvocation(
+ dartProcedure,
+ Arguments(originalParameters
+ .map<Expression>((value) => StaticInvocation(
+ _jsifyTarget(value.type), Arguments([VariableGet(value)])))
+ .toList()));
DartType returnTypeOverride = returnType == _coreTypes.intNullableRawType
? _coreTypes.doubleNullableRawType
: returnType == _coreTypes.intNonNullableRawType
? _coreTypes.doubleNonNullableRawType
: returnType;
- if (returnType is! VoidType) {
+ if (returnType is VoidType) {
+ return ExpressionStatement(invocation);
+ } else {
+ Expression expression;
if (_isStaticInteropType(returnType)) {
// TODO(joshualitt): Expose boxed `JSNull` and `JSUndefined` to Dart
// code after migrating existing users of js interop on Dart2Wasm.
- // invocation = _createJSValue(invocation);
- invocation = _invokeOneArg(_jsValueBoxTarget, invocation);
+ // expression = _createJSValue(invocation);
+ expression = _invokeOneArg(_jsValueBoxTarget, invocation);
} else {
- invocation = AsExpression(
+ expression = AsExpression(
_convertReturnType(returnType, returnTypeOverride,
_invokeOneArg(_dartifyRawTarget, invocation)),
returnType);
}
+ return ReturnStatement(expression);
}
- return invocation;
}
// Handles any necessary return type conversions. Today this is just for
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index b25d2af..68ddc72 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -6088,17 +6088,6 @@
}
}
}
- if (target.isExternal &&
- target.isInlineClassMember &&
- hasObjectLiteralAnnotation(target)) {
- // Only JS interop inline class object literal constructors have the
- // `@ObjectLiteral(...)` annotation.
- assert(node.arguments.positional.isEmpty);
- return _emitObjectLiteral(
- Arguments(node.arguments.positional,
- types: node.arguments.types, named: node.arguments.named),
- target);
- }
if (target == _coreTypes.identicalProcedure) {
return _emitCoreIdenticalCall(node.arguments.positional);
}
diff --git a/pkg/dev_compiler/lib/src/kernel/js_interop.dart b/pkg/dev_compiler/lib/src/kernel/js_interop.dart
index e2cd4f4..b78ee59 100644
--- a/pkg/dev_compiler/lib/src/kernel/js_interop.dart
+++ b/pkg/dev_compiler/lib/src/kernel/js_interop.dart
@@ -67,7 +67,7 @@
bool isJSAnnotation(Expression value) =>
_annotationIsFromJSLibrary('JS', value) || isJSName(value);
-/// Returns [true] if [value] is the `JS` annotation from `package:js`.
+/// Returns [true] if [e] is the `JS` annotation from `package:js`.
bool isPublicJSAnnotation(Expression value) =>
_annotationIsFromJSLibrary('JS', value);
@@ -113,18 +113,6 @@
bool isUndefinedAnnotation(Expression value) =>
isBuiltinAnnotation(value, '_js_helper', '_Undefined');
-bool isObjectLiteralAnnotation(Expression value) {
- var c = getAnnotationClass(value);
- return c != null &&
- c.name == 'ObjectLiteral' &&
- _isLibrary(c.enclosingLibrary, ['dart:js_interop']);
-}
-
-/// Returns whether [a] is annotated with the `@ObjectLiteral(...)` annotation
-/// from `dart:js_interop`.
-bool hasObjectLiteralAnnotation(Annotatable a) =>
- a.annotations.any(isObjectLiteralAnnotation);
-
/// Returns true iff the class has an `@JS(...)` annotation from `package:js`.
///
/// Note: usually [_usesJSInterop] should be used instead of this.
diff --git a/sdk/lib/js_interop/js_interop.dart b/sdk/lib/js_interop/js_interop.dart
index 860c5f0..264334d 100644
--- a/sdk/lib/js_interop/js_interop.dart
+++ b/sdk/lib/js_interop/js_interop.dart
@@ -23,21 +23,6 @@
/// `package:js` classes.
export 'dart:_js_annotations' show JS;
-/// The annotation for object literal constructors.
-///
-/// Use this on an external constructor for an interop inline class that only
-/// has named args in order to create object literals performantly. The
-/// resulting object literal will use the parameter names as keys and the
-/// provided arguments as the values.
-///
-/// Note that object literal constructors ignore the default values of
-/// parameters and only include the arguments you provide in the invocation of
-/// the constructor. This is similar to the `@anonymous` annotation in
-/// `package:js`.
-class ObjectLiteral {
- const ObjectLiteral();
-}
-
/// The overall top type in the JS types hierarchy.
typedef JSAny = js_types.JSAny;
diff --git a/tests/lib/js/static_interop_test/inline_class/object_literal_constructor_test.dart b/tests/lib/js/static_interop_test/inline_class/object_literal_constructor_test.dart
deleted file mode 100644
index e8fb6d9..0000000
--- a/tests/lib/js/static_interop_test/inline_class/object_literal_constructor_test.dart
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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.
-
-// SharedOptions=--enable-experiment=inline-class
-
-@JS()
-library object_literal_constructor_test;
-
-import 'dart:js_interop';
-import 'dart:js_util';
-
-import 'package:expect/minitest.dart';
-
-@JS()
-inline class Literal {
- final JSObject obj;
- @ObjectLiteral()
- external Literal({double? a, String b = 'unused', bool? c = null});
-}
-
-@JS('Object.keys')
-external JSArray objectKeys(Literal literal);
-
-void main() {
- // Test that the properties we assumed to exist in `literal` actually exist
- // and that their values are as expected. Note that we don't check the order
- // of the keys in the literal. This is not guaranteed to be the same across
- // different backends.
- void testProperties(Literal literal, {double? a, String? b, bool? c}) {
- if (a != null) {
- expect(hasProperty(literal, 'a'), true);
- expect(getProperty<double>(literal, 'a'), a);
- }
- if (b != null) {
- expect(hasProperty(literal, 'b'), true);
- expect(getProperty<String>(literal, 'b'), b);
- }
- if (c != null) {
- expect(hasProperty(literal, 'c'), true);
- expect(getProperty<bool>(literal, 'c'), c);
- }
- }
-
- testProperties(Literal());
- testProperties(Literal(a: 0.0), a: 0.0);
- testProperties(Literal(b: ''), b: '');
- testProperties(Literal(c: true), c: true);
-
- testProperties(Literal(a: 0.0, b: ''), a: 0.0, b: '');
- testProperties(Literal(a: 0.0, c: true), a: 0.0, c: true);
- testProperties(Literal(b: '', c: true), b: '', c: true);
-
- testProperties(Literal(a: 0.0, b: '', c: true), a: 0.0, b: '', c: true);
- // Re-run with the same shape for dart2wasm optimization check.
- testProperties(Literal(a: 0.0, b: '', c: true), a: 0.0, b: '', c: true);
- // Test that passing in a different order doesn't change the values.
- testProperties(Literal(c: true, a: 0.0, b: ''), a: 0.0, b: '', c: true);
-}
\ No newline at end of file
diff --git a/tests/web/wasm/static_interop_test.dart b/tests/web/wasm/static_interop_test.dart
index d863f52..2436e3e 100644
--- a/tests/web/wasm/static_interop_test.dart
+++ b/tests/web/wasm/static_interop_test.dart
@@ -307,24 +307,23 @@
extension AnonymousJSClassExtension on AnonymousJSClass {
external String? get foo;
- external String? get bar;
+ external String get bar;
external String? get bleep;
external int? get goo;
- external int? get ooo;
+ external int get ooo;
external List<double>? saz;
- external List<double>? zoo;
+ external List<double> zoo;
}
void anonymousTest() {
- final anonymousJSClass = AnonymousJSClass.factory(
- foo: 'boo', bleep: 'bleep', saz: const [1.0, 2.0], goo: 0);
+ final anonymousJSClass = AnonymousJSClass.factory(foo: 'boo');
Expect.equals('boo', anonymousJSClass.foo);
- Expect.equals(null, anonymousJSClass.bar);
- Expect.equals('bleep', anonymousJSClass.bleep);
- Expect.equals(0, anonymousJSClass.goo);
- Expect.equals(null, anonymousJSClass.ooo);
- Expect.listEquals(const [1.0, 2.0], anonymousJSClass.saz!);
- Expect.equals(null, anonymousJSClass.zoo);
+ Expect.equals('baz', anonymousJSClass.bar);
+ Expect.equals(null, anonymousJSClass.bleep);
+ Expect.equals(null, anonymousJSClass.goo);
+ Expect.equals(1, anonymousJSClass.ooo);
+ Expect.equals(null, anonymousJSClass.saz);
+ Expect.listEquals(const [1.0, 2.0], anonymousJSClass.zoo);
}
@JS()