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 cb044562d94..11559052de5 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 @@ -2,7 +2,6 @@ // 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. -import 'package:front_end/src/api_unstable/dart2js.dart' as api; import 'package:kernel/ast.dart'; import 'package:kernel/class_hierarchy.dart'; import 'package:kernel/core_types.dart'; @@ -37,6 +36,7 @@ class JsUtilOptimizer extends Transformer { final CoreTypes _coreTypes; final StatefulStaticTypeContext _staticTypeContext; + Map? _extensionMemberIndex; JsUtilOptimizer(this._coreTypes, ClassHierarchy hierarchy) : _jsTarget = @@ -74,6 +74,7 @@ class JsUtilOptimizer extends Transformer { _staticTypeContext.enterLibrary(lib); lib.transformChildren(this); _staticTypeContext.leaveLibrary(lib); + _extensionMemberIndex = null; return lib; } @@ -88,21 +89,24 @@ class JsUtilOptimizer extends Transformer { @override visitProcedure(Procedure node) { _staticTypeContext.enterMember(node); - if (node.isExternal && node.isExtensionMember && !_isDeclaredStatic(node)) { - var transformedBody; - if (api.getExtensionMemberKind(node) == ProcedureKind.Getter) { - transformedBody = _getExternalGetterBody(node); - } else if (api.getExtensionMemberKind(node) == ProcedureKind.Setter) { - transformedBody = _getExternalSetterBody(node); - } else if (api.getExtensionMemberKind(node) == ProcedureKind.Method) { - transformedBody = _getExternalMethodBody(node); - } - // TODO(rileyporter): Add transformation for static members and any - // operators we decide to support. - if (transformedBody != null) { - node.function.body = transformedBody; - node.isExternal = false; + var transformedBody; + if (node.isExternal && node.isExtensionMember) { + var index = _extensionMemberIndex ??= + _createExtensionMembersIndex(node.enclosingLibrary); + var nodeDescriptor = index[node.reference]!; + if (!nodeDescriptor.isStatic) { + if (nodeDescriptor.kind == ExtensionMemberKind.Getter) { + transformedBody = _getExternalGetterBody(node); + } else if (nodeDescriptor.kind == ExtensionMemberKind.Setter) { + transformedBody = _getExternalSetterBody(node); + } else if (nodeDescriptor.kind == ExtensionMemberKind.Method) { + transformedBody = _getExternalMethodBody(node); + } } + } + if (transformedBody != null) { + node.function.body = transformedBody; + node.isExternal = false; } else { node.transformChildren(this); } @@ -110,6 +114,18 @@ class JsUtilOptimizer extends Transformer { return node; } + /// Returns and initializes `_extensionMemberIndex` to an index of the member + /// reference to the member `ExtensionMemberDescriptor`, for all extension + /// members in the given [library]. + Map _createExtensionMembersIndex( + Library library) { + _extensionMemberIndex = {}; + library.extensions.forEach((extension) => extension.members.forEach( + (descriptor) => + _extensionMemberIndex![descriptor.member] = descriptor)); + return _extensionMemberIndex!; + } + /// Returns a new function body for the given [node] external getter. /// /// The new function body will call the optimized version of @@ -121,7 +137,7 @@ class JsUtilOptimizer extends Transformer { _getPropertyTarget, Arguments([ VariableGet(function.positionalParameters.first), - StringLiteral(_getMemberName(node)) + StringLiteral(_getExtensionMemberName(node)) ])) ..fileOffset = node.fileOffset; return ReturnStatement(AsExpression( @@ -139,7 +155,7 @@ class JsUtilOptimizer extends Transformer { _setPropertyTarget, Arguments([ VariableGet(function.positionalParameters.first), - StringLiteral(_getMemberName(node)), + StringLiteral(_getExtensionMemberName(node)), VariableGet(function.positionalParameters.last) ])) ..fileOffset = node.fileOffset; @@ -157,7 +173,7 @@ class JsUtilOptimizer extends Transformer { _callMethodTarget, Arguments([ VariableGet(function.positionalParameters.first), - StringLiteral(_getMemberName(node)), + StringLiteral(_getExtensionMemberName(node)), ListLiteral(function.positionalParameters .sublist(1) .map((argument) => VariableGet(argument)) @@ -168,29 +184,17 @@ class JsUtilOptimizer extends Transformer { _lowerCallMethod(callMethodInvocation), function.returnType)); } - /// Returns the member name, either from the `@JS` annotation if non-empty, - /// or parsed from CFE generated node name. - String _getMemberName(Procedure node) { + /// Returns the extension member name. + /// + /// Returns either the name from the `@JS` annotation if non-empty, or the + /// declared name of the extension member. Does not return the CFE generated + /// name for the top level member for this extension member. + String _getExtensionMemberName(Procedure node) { var jsAnnotationName = getJSName(node); if (jsAnnotationName.isNotEmpty) { return jsAnnotationName; } - // TODO(rileyporter): Switch to using the ExtensionMemberDescriptor data. - var nodeName = node.name.text; - if (nodeName.contains('#')) { - return nodeName.substring(nodeName.indexOf('#') + 1); - } else { - return nodeName.substring(nodeName.indexOf('|') + 1); - } - } - - /// Returns whether the given extension [node] is declared as `static`. - /// - /// All extension members have `isStatic` true, but the members declared as - /// static will not have a synthesized `this` variable. - bool _isDeclaredStatic(Procedure node) { - return node.function.positionalParameters.isEmpty || - node.function.positionalParameters.first.name != '#this'; + return _extensionMemberIndex![node.reference]!.name.text; } /// Replaces js_util method calls with optimization when possible. diff --git a/pkg/_js_interop_checks/pubspec.yaml b/pkg/_js_interop_checks/pubspec.yaml index 27f50f2fc2a..bae19925409 100644 --- a/pkg/_js_interop_checks/pubspec.yaml +++ b/pkg/_js_interop_checks/pubspec.yaml @@ -8,7 +8,5 @@ environment: dependencies: _fe_analyzer_shared: path: ../_fe_analyzer_shared - front_end: - path: ../front_end kernel: path: ../kernel diff --git a/pkg/front_end/lib/src/api_unstable/dart2js.dart b/pkg/front_end/lib/src/api_unstable/dart2js.dart index b8d1d74123a..e811ba1fe73 100644 --- a/pkg/front_end/lib/src/api_unstable/dart2js.dart +++ b/pkg/front_end/lib/src/api_unstable/dart2js.dart @@ -241,23 +241,3 @@ Iterable getSupportedLibraryNames( // TODO(sigmund): Delete this API once `member.isRedirectingFactory` // is implemented correctly for patch files (Issue #33495). bool isRedirectingFactory(ir.Procedure member) => member.isRedirectingFactory; - -/// Determines what `ProcedureKind` the given extension [member] is based on -/// the member name. -/// -/// Note: classifies operators as `ProcedureKind.Method`. -ir.ProcedureKind getExtensionMemberKind(ir.Procedure member) { - assert(member.isExtensionMember); - String name = member.name.text; - int pipeIndex = name.indexOf('|'); - int poundIndex = name.indexOf('#'); - assert(pipeIndex >= 0); - if (poundIndex >= 0) { - String getOrSet = name.substring(pipeIndex + 1, poundIndex); - return getOrSet == 'get' - ? ir.ProcedureKind.Getter - : ir.ProcedureKind.Setter; - } else { - return member.kind; - } -} diff --git a/pkg/front_end/test/desugar_test.dart b/pkg/front_end/test/desugar_test.dart index 31089edfcf1..82fdd4a4a86 100644 --- a/pkg/front_end/test/desugar_test.dart +++ b/pkg/front_end/test/desugar_test.dart @@ -28,7 +28,6 @@ Future main() async { await testRedirectingFactoryDirect(); await testRedirectingFactorySerialized(); await testRedirectingFactoryPatchFile(); - await testExtensionMemberKind(); }); } @@ -80,97 +79,3 @@ class _B implements A { _B(int x); } '''; - -Future testExtensionMemberKind() async { - var component = await compileUnit(['e.dart'], {'e.dart': extensionSource}); - var library = component.libraries - .firstWhere((l) => l.importUri.path.endsWith('e.dart')); - var descriptors = - library.extensions.expand((extension) => extension.members).toList(); - - // Check generated getters and setters for fields. - var fieldGetter = - findExtensionField(descriptors, 'field', ir.ExtensionMemberKind.Getter); - Expect.equals( - api.getExtensionMemberKind(fieldGetter), ir.ProcedureKind.Getter); - var fieldSetter = - findExtensionField(descriptors, 'field', ir.ExtensionMemberKind.Setter); - Expect.equals( - api.getExtensionMemberKind(fieldSetter), ir.ProcedureKind.Setter); - var staticFieldGetter = findExtensionField( - descriptors, 'staticField', ir.ExtensionMemberKind.Getter); - Expect.equals( - api.getExtensionMemberKind(staticFieldGetter), ir.ProcedureKind.Getter); - var staticFieldSetter = findExtensionField( - descriptors, 'staticField', ir.ExtensionMemberKind.Setter); - Expect.equals( - api.getExtensionMemberKind(staticFieldSetter), ir.ProcedureKind.Setter); - - // Check getters and setters. - var getter = findExtensionMember(descriptors, 'getter'); - Expect.equals(api.getExtensionMemberKind(getter), ir.ProcedureKind.Getter); - var setter = findExtensionMember(descriptors, 'setter'); - Expect.equals(api.getExtensionMemberKind(setter), ir.ProcedureKind.Setter); - var staticGetter = findExtensionMember(descriptors, 'staticGetter'); - Expect.equals( - api.getExtensionMemberKind(staticGetter), ir.ProcedureKind.Getter); - var staticSetter = findExtensionMember(descriptors, 'staticSetter'); - Expect.equals( - api.getExtensionMemberKind(staticSetter), ir.ProcedureKind.Setter); - - // Check methods. - var method = findExtensionMember(descriptors, 'method'); - Expect.equals(api.getExtensionMemberKind(method), ir.ProcedureKind.Method); - var methodTearoff = findExtensionTearoff(descriptors, 'get#method'); - Expect.equals( - api.getExtensionMemberKind(methodTearoff), ir.ProcedureKind.Getter); - var staticMethod = findExtensionMember(descriptors, 'staticMethod'); - Expect.equals( - api.getExtensionMemberKind(staticMethod), ir.ProcedureKind.Method); - - // Check operators. - var operator = findExtensionMember(descriptors, '+'); - Expect.equals(api.getExtensionMemberKind(operator), ir.ProcedureKind.Method); -} - -ir.Member findExtensionMember( - List descriptors, String memberName) { - return descriptors - .firstWhere((d) => d.name.text == memberName) - .member - .asMember; -} - -ir.Member findExtensionField(List descriptors, - String fieldName, ir.ExtensionMemberKind kind) { - return descriptors - .firstWhere((d) => d.name.text == fieldName && d.kind == kind) - .member - .asMember; -} - -ir.Member findExtensionTearoff( - List descriptors, String memberName) { - return descriptors - .map((d) => d.member.asMember) - .firstWhere((m) => m.name.text.contains(memberName)); -} - -const extensionSource = ''' -class Foo {} - -extension Ext on Foo { - external int field; - external static int staticField; - - external get getter; - external set setter(_); - external static get staticGetter; - external static set staticSetter(_); - - external int method(); - external static int staticMethod(); - - external operator +(_); -} -''';