From dd028547ce84aff4bb4404eceaa26928d610cb2c Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Mon, 30 Sep 2019 09:51:31 +0000 Subject: [PATCH] [cfe] Support patching of extension methods Change-Id: I453e17e63f97a0ca2477371541c6a9602bee2404 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119322 Reviewed-by: Jens Johansen Commit-Queue: Johnni Winther --- .../src/api_prototype/memory_file_system.dart | 4 +- pkg/front_end/lib/src/base/common.dart | 6 + .../lib/src/fasta/builder/class_builder.dart | 7 + .../src/fasta/builder/modifier_builder.dart | 3 +- .../src/fasta/builder/procedure_builder.dart | 33 ++-- .../dill/dill_extension_member_builder.dart | 2 +- .../lib/src/fasta/parser/parser.dart | 2 +- .../source/source_extension_builder.dart | 67 ++++++- .../lib/src/testing/id_extractor.dart | 5 +- pkg/front_end/lib/src/testing/id_testing.dart | 2 + .../lib/src/testing/id_testing_helper.dart | 13 +- .../lib/src/testing/id_testing_utils.dart | 7 +- .../test/extensions/data/as_show/lib.dart | 30 ++++ .../extensions/data/as_show/libraries.json | 9 + .../test/extensions/data/as_show/main.dart | 20 +++ .../test/extensions/data/as_show/origin.dart | 30 ++++ .../extensions/data/patching/libraries.json | 12 ++ .../test/extensions/data/patching/main.dart | 23 +++ .../test/extensions/data/patching/origin.dart | 108 ++++++++++++ .../test/extensions/data/patching/patch.dart | 163 ++++++++++++++++++ .../test/extensions/extensions_test.dart | 9 +- .../test/id_testing/id_testing_test.dart | 2 +- .../language_versioning_test.dart | 2 +- pkg/kernel/binary.md | 2 +- pkg/kernel/lib/ast.dart | 15 +- pkg/kernel/lib/text/ast_to_text.dart | 1 - .../dart2js/equivalence/id_testing_test.dart | 2 +- 27 files changed, 525 insertions(+), 54 deletions(-) create mode 100644 pkg/front_end/lib/src/base/common.dart create mode 100644 pkg/front_end/test/extensions/data/as_show/lib.dart create mode 100644 pkg/front_end/test/extensions/data/as_show/libraries.json create mode 100644 pkg/front_end/test/extensions/data/as_show/main.dart create mode 100644 pkg/front_end/test/extensions/data/as_show/origin.dart create mode 100644 pkg/front_end/test/extensions/data/patching/libraries.json create mode 100644 pkg/front_end/test/extensions/data/patching/main.dart create mode 100644 pkg/front_end/test/extensions/data/patching/origin.dart create mode 100644 pkg/front_end/test/extensions/data/patching/patch.dart diff --git a/pkg/front_end/lib/src/api_prototype/memory_file_system.dart b/pkg/front_end/lib/src/api_prototype/memory_file_system.dart index fd091bb169c..3618c93bb21 100644 --- a/pkg/front_end/lib/src/api_prototype/memory_file_system.dart +++ b/pkg/front_end/lib/src/api_prototype/memory_file_system.dart @@ -26,7 +26,9 @@ class MemoryFileSystem implements FileSystem { Uri currentDirectory; MemoryFileSystem(Uri currentDirectory) - : currentDirectory = _addTrailingSlash(currentDirectory); + : currentDirectory = _addTrailingSlash(currentDirectory) { + _directories.add(currentDirectory); + } @override MemoryFileSystemEntity entityForUri(Uri uri) { diff --git a/pkg/front_end/lib/src/base/common.dart b/pkg/front_end/lib/src/base/common.dart new file mode 100644 index 00000000000..e511a044488 --- /dev/null +++ b/pkg/front_end/lib/src/base/common.dart @@ -0,0 +1,6 @@ +// Copyright (c) 2019, 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. + +/// If `true`, data that would not otherwise be kept is stored for testing. +bool retainDataForTesting = false; diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart index c4a16327caf..1ccb68b1bb5 100644 --- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart @@ -53,6 +53,8 @@ import 'package:kernel/type_algebra.dart' as type_algebra import 'package:kernel/type_environment.dart' show TypeEnvironment; +import '../../base/common.dart'; + import '../dill/dill_member_builder.dart' show DillMemberBuilder; import 'builder.dart' @@ -166,6 +168,8 @@ abstract class ClassBuilder extends DeclarationBuilder { ClassBuilder actualOrigin; + ClassBuilder patchForTesting; + ClassBuilder( List metadata, int modifiers, @@ -1523,6 +1527,9 @@ abstract class ClassBuilder extends DeclarationBuilder { void applyPatch(Builder patch) { if (patch is ClassBuilder) { patch.actualOrigin = this; + if (retainDataForTesting) { + patchForTesting = patch; + } // TODO(ahe): Complain if `patch.supertype` isn't null. scope.local.forEach((String name, Builder member) { Builder memberPatch = patch.scope.local[name]; diff --git a/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart b/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart index 63579754404..592ecf2d3ae 100644 --- a/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart @@ -74,5 +74,6 @@ abstract class ModifierBuilder extends Builder { return buffer..write(name ?? fullNameForErrors); } - String toString() => "$debugName(${printOn(new StringBuffer())})"; + String toString() => + "${isPatch ? 'patch ' : ''}$debugName(${printOn(new StringBuffer())})"; } diff --git a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart index d818e4d07a2..0335f232f5d 100644 --- a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart @@ -11,6 +11,8 @@ import 'package:kernel/ast.dart' hide Variance; import 'package:kernel/type_algebra.dart'; +import '../../base/common.dart'; + import 'builder.dart' show Builder, @@ -459,6 +461,7 @@ class ProcedureBuilder extends FunctionBuilder { final Procedure _procedure; final int charOpenParenOffset; final ProcedureKind kind; + ProcedureBuilder patchForTesting; AsyncMarker actualAsyncModifier = AsyncMarker.Sync; @@ -553,8 +556,8 @@ class ProcedureBuilder extends FunctionBuilder { _procedure.isConst = isConst; if (isExtensionMethod) { ExtensionBuilder extensionBuilder = parent; - procedure.isExtensionMember = true; - procedure.isStatic = true; + _procedure.isExtensionMember = true; + _procedure.isStatic = true; String kindInfix = ''; if (isExtensionInstanceMember) { // Instance getter and setter are converted to methods so we use an @@ -574,18 +577,18 @@ class ProcedureBuilder extends FunctionBuilder { throw new UnsupportedError( 'Unexpected extension method kind ${kind}'); } - procedure.kind = ProcedureKind.Method; + _procedure.kind = ProcedureKind.Method; } - procedure.name = new Name( + _procedure.name = new Name( '${extensionBuilder.name}|${kindInfix}${name}', libraryBuilder.library); } else { _procedure.isStatic = isStatic; _procedure.name = new Name(name, libraryBuilder.library); } - } - if (extensionTearOff != null) { - _buildExtensionTearOff(libraryBuilder, parent); + if (extensionTearOff != null) { + _buildExtensionTearOff(libraryBuilder, parent); + } } return _procedure; } @@ -698,7 +701,7 @@ class ProcedureBuilder extends FunctionBuilder { Statement closureBody = new ReturnStatement( new StaticInvocation( - procedure, + _procedure, new Arguments(closurePositionalArguments, types: typeArguments, named: closureNamedArguments)) ..fileOffset = fileOffset) @@ -709,10 +712,10 @@ class ProcedureBuilder extends FunctionBuilder { typeParameters: closureTypeParameters, positionalParameters: closurePositionalParameters, namedParameters: closureNamedParameters, - requiredParameterCount: procedure.function.requiredParameterCount - 1, + requiredParameterCount: _procedure.function.requiredParameterCount - 1, returnType: closureReturnType, - asyncMarker: procedure.function.asyncMarker, - dartAsyncMarker: procedure.function.dartAsyncMarker)) + asyncMarker: _procedure.function.asyncMarker, + dartAsyncMarker: _procedure.function.dartAsyncMarker)) ..fileOffset = fileOffset; _extensionTearOff @@ -783,6 +786,9 @@ class ProcedureBuilder extends FunctionBuilder { if (patch is ProcedureBuilder) { if (checkPatch(patch)) { patch.actualOrigin = this; + if (retainDataForTesting) { + patchForTesting = patch; + } } } else { reportPatchMismatch(patch); @@ -807,6 +813,8 @@ class ConstructorBuilder extends FunctionBuilder { @override ConstructorBuilder actualOrigin; + ConstructorBuilder patchForTesting; + Constructor get actualConstructor => _constructor; ConstructorBuilder( @@ -998,6 +1006,9 @@ class ConstructorBuilder extends FunctionBuilder { if (patch is ConstructorBuilder) { if (checkPatch(patch)) { patch.actualOrigin = this; + if (retainDataForTesting) { + patchForTesting = patch; + } } } else { reportPatchMismatch(patch); diff --git a/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart index b46cd362977..d45a8c7b67e 100644 --- a/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart +++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart @@ -26,7 +26,7 @@ class DillExtensionMemberBuilder extends DillMemberBuilder { bool get isStatic => _descriptor.isStatic; @override - bool get isExternal => _descriptor.isExternal; + bool get isExternal => member.isExternal; @override Procedure get procedure { diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart index f2753bded77..9e548fb2bdb 100644 --- a/pkg/front_end/lib/src/fasta/parser/parser.dart +++ b/pkg/front_end/lib/src/fasta/parser/parser.dart @@ -3444,7 +3444,7 @@ class Parser { beforeInitializers?.next, token); break; case DeclarationKind.Extension: - if (optional(';', bodyStart)) { + if (optional(';', bodyStart) && externalToken == null) { reportRecoverableError(isOperator ? name.next : name, fasta.messageExtensionDeclaresAbstractMember); } diff --git a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart index fd7df17f25b..ea3c8398eaa 100644 --- a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart @@ -4,6 +4,7 @@ import 'dart:core' hide MapEntry; import 'package:kernel/ast.dart'; +import '../../base/common.dart'; import '../builder/declaration.dart'; import '../builder/extension_builder.dart'; import '../builder/library_builder.dart'; @@ -12,22 +13,25 @@ import '../builder/procedure_builder.dart'; import '../builder/type_builder.dart'; import '../builder/type_variable_builder.dart'; import '../scope.dart'; -import 'source_library_builder.dart'; import '../kernel/kernel_builder.dart'; - import '../problems.dart'; - import '../fasta_codes.dart' show + messagePatchDeclarationMismatch, + messagePatchDeclarationOrigin, noLength, templateConflictsWithMember, templateConflictsWithMemberWarning, templateConflictsWithSetter, templateConflictsWithSetterWarning; +import 'source_library_builder.dart'; class SourceExtensionBuilder extends ExtensionBuilder { final Extension _extension; + SourceExtensionBuilder _origin; + SourceExtensionBuilder patchForTesting; + SourceExtensionBuilder( List metadata, int modifiers, @@ -48,7 +52,10 @@ class SourceExtensionBuilder extends ExtensionBuilder { super(metadata, modifiers, name, parent, nameOffset, scope, typeParameters, onType); - Extension get extension => _extension; + @override + SourceExtensionBuilder get origin => _origin ?? this; + + Extension get extension => isPatch ? origin._extension : _extension; /// Builds the [Extension] for this extension build and inserts the members /// into the [Library] of [libraryBuilder]. @@ -75,7 +82,7 @@ class SourceExtensionBuilder extends ExtensionBuilder { Field field = declaration.build(libraryBuilder); if (addMembersToLibrary && declaration.next == null) { libraryBuilder.library.addMember(field); - _extension.members.add(new ExtensionMemberDescriptor( + extension.members.add(new ExtensionMemberDescriptor( name: new Name(declaration.name, libraryBuilder.library), member: field.reference, isStatic: declaration.isStatic, @@ -83,7 +90,9 @@ class SourceExtensionBuilder extends ExtensionBuilder { } } else if (declaration is ProcedureBuilder) { Member function = declaration.build(libraryBuilder); - if (addMembersToLibrary && declaration.next == null) { + if (addMembersToLibrary && + !declaration.isPatch && + declaration.next == null) { libraryBuilder.library.addMember(function); ExtensionMemberKind kind; switch (declaration.kind) { @@ -103,11 +112,10 @@ class SourceExtensionBuilder extends ExtensionBuilder { unsupported("Extension method kind: ${declaration.kind}", declaration.charOffset, declaration.fileUri); } - _extension.members.add(new ExtensionMemberDescriptor( + extension.members.add(new ExtensionMemberDescriptor( name: new Name(declaration.name, libraryBuilder.library), member: function.reference, isStatic: declaration.isStatic, - isExternal: declaration.isExternal, kind: kind)); Procedure tearOff = declaration.extensionTearOff; if (tearOff != null) { @@ -116,7 +124,6 @@ class SourceExtensionBuilder extends ExtensionBuilder { name: new Name(declaration.name, libraryBuilder.library), member: tearOff.reference, isStatic: false, - isExternal: false, kind: ExtensionMemberKind.TearOff)); } } @@ -157,4 +164,46 @@ class SourceExtensionBuilder extends ExtensionBuilder { return _extension; } + + @override + void applyPatch(Builder patch) { + if (patch is SourceExtensionBuilder) { + patch._origin = this; + if (retainDataForTesting) { + patchForTesting = patch; + } + scope.local.forEach((String name, Builder member) { + Builder memberPatch = patch.scope.local[name]; + if (memberPatch != null) { + member.applyPatch(memberPatch); + } + }); + scope.setters.forEach((String name, Builder member) { + Builder memberPatch = patch.scope.setters[name]; + if (memberPatch != null) { + member.applyPatch(memberPatch); + } + }); + + // TODO(johnniwinther): Check that type parameters and on-type match + // with origin declaration. + } else { + library.addProblem(messagePatchDeclarationMismatch, patch.charOffset, + noLength, patch.fileUri, context: [ + messagePatchDeclarationOrigin.withLocation( + fileUri, charOffset, noLength) + ]); + } + } + + @override + int finishPatch() { + if (!isPatch) return 0; + + int count = 0; + scope.forEach((String name, Builder declaration) { + count += declaration.finishPatch(); + }); + return count; + } } diff --git a/pkg/front_end/lib/src/testing/id_extractor.dart b/pkg/front_end/lib/src/testing/id_extractor.dart index 0afbb82ea8a..a7be6045841 100644 --- a/pkg/front_end/lib/src/testing/id_extractor.dart +++ b/pkg/front_end/lib/src/testing/id_extractor.dart @@ -61,9 +61,8 @@ abstract class DataExtractor extends Visitor with DataRegistry { DataExtractor(this.actualMap); - void computeForLibrary(Library library, {bool useFileUri: false}) { - LibraryId id = - new LibraryId(useFileUri ? library.fileUri : library.importUri); + void computeForLibrary(Library library) { + LibraryId id = new LibraryId(library.fileUri); T value = computeLibraryValue(id, library); registerValue(library.fileUri, null, id, value, library); } diff --git a/pkg/front_end/lib/src/testing/id_testing.dart b/pkg/front_end/lib/src/testing/id_testing.dart index 6aba9fbce38..3c49ea0fec2 100644 --- a/pkg/front_end/lib/src/testing/id_testing.dart +++ b/pkg/front_end/lib/src/testing/id_testing.dart @@ -214,6 +214,8 @@ TestData computeTestData(FileSystemEntity testFile, entry; } } + assert( + mainTestFile != null, "No 'main.dart' test file found for $testFile."); } String annotatedCode = new File.fromUri(mainTestFile.uri).readAsStringSync(); diff --git a/pkg/front_end/lib/src/testing/id_testing_helper.dart b/pkg/front_end/lib/src/testing/id_testing_helper.dart index ec923754463..68aa64d60fa 100644 --- a/pkg/front_end/lib/src/testing/id_testing_helper.dart +++ b/pkg/front_end/lib/src/testing/id_testing_helper.dart @@ -8,6 +8,7 @@ import '../api_prototype/compiler_options.dart' import '../api_prototype/experimental_flags.dart' show ExperimentalFlag; import '../api_prototype/terminal_color_support.dart' show printDiagnosticMessage; +import '../base/common.dart'; import '../fasta/messages.dart' show FormattedMessage; import '../fasta/severity.dart' show Severity; import '../kernel_generator_impl.dart' show InternalCompilerResult; @@ -42,8 +43,10 @@ class TestConfig { final String marker; final String name; final Map experimentalFlags; + final Uri librariesSpecificationUri; - const TestConfig(this.marker, this.name, {this.experimentalFlags = const {}}); + const TestConfig(this.marker, this.name, + {this.experimentalFlags = const {}, this.librariesSpecificationUri}); void customizeCompilerOptions(CompilerOptions options) {} } @@ -180,6 +183,7 @@ void onFailure(String message) => throw new StateError(message); /// Creates a test runner for [dataComputer] on [testedConfigs]. RunTestFunction runTestFor( DataComputer dataComputer, List testedConfigs) { + retainDataForTesting = true; return (TestData testData, {bool testAfterFailures, bool verbose, bool succinct, bool printCode}) { return runTest(testData, dataComputer, testedConfigs, @@ -242,6 +246,13 @@ Future runTestForConfig( }; options.debugDump = printCode; options.experimentalFlags.addAll(config.experimentalFlags); + if (config.librariesSpecificationUri != null) { + Set testFiles = + testData.memorySourceFiles.keys.map(createUriForFileName).toSet(); + if (testFiles.contains(config.librariesSpecificationUri)) { + options.librariesSpecificationUri = config.librariesSpecificationUri; + } + } config.customizeCompilerOptions(options); InternalCompilerResult compilerResult = await compileScript( testData.memorySourceFiles, diff --git a/pkg/front_end/lib/src/testing/id_testing_utils.dart b/pkg/front_end/lib/src/testing/id_testing_utils.dart index d32d8f54c84..0c98653abf8 100644 --- a/pkg/front_end/lib/src/testing/id_testing_utils.dart +++ b/pkg/front_end/lib/src/testing/id_testing_utils.dart @@ -62,7 +62,7 @@ Extension lookupExtension(Library library, String extensionName, (Extension extension) => extension.name == extensionName, orElse: () { if (required) { throw new ArgumentError( - "Extension '$extensionName' not found in '$library'."); + "Extension '$extensionName' not found in '${library.importUri}'."); } return null; }); @@ -151,7 +151,7 @@ MemberBuilder lookupClassMemberBuilder(InternalCompilerResult compilerResult, lookupClassBuilder(compilerResult, cls, required: required); MemberBuilder memberBuilder; if (classBuilder != null) { - if (member is Constructor) { + if (member is Constructor || member is Procedure && member.isFactory) { memberBuilder = classBuilder.constructors.local[memberName]; } else if (member is Procedure && member.isSetter) { memberBuilder = classBuilder.scope.setters[memberName]; @@ -527,9 +527,6 @@ String errorsToText(List errors) { /// Returns a textual representation of [descriptor] to be used in testing. String extensionMethodDescriptorToText(ExtensionMemberDescriptor descriptor) { StringBuffer sb = new StringBuffer(); - if (descriptor.isExternal) { - sb.write('external '); - } if (descriptor.isStatic) { sb.write('static '); } diff --git a/pkg/front_end/test/extensions/data/as_show/lib.dart b/pkg/front_end/test/extensions/data/as_show/lib.dart new file mode 100644 index 00000000000..e89ef0cb9ed --- /dev/null +++ b/pkg/front_end/test/extensions/data/as_show/lib.dart @@ -0,0 +1,30 @@ +// Copyright (c) 2019, 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. + +/*library: scope=[Extension1]*/ + +/*class: Extension1: + builder-name=Extension1, + builder-onType=String, + extension-members=[ + method1=Extension1|method1, + tearoff method1=Extension1|get#method1], + extension-name=Extension1, + extension-onType=String +*/ +extension Extension1 on String { + /*member: Extension1|method1: + builder-name=method1, + builder-params=[#this], + member-name=Extension1|method1, + member-params=[#this] + */ + method1() {} + + /*member: Extension1|get#method1: + builder-name=method1, + builder-params=[#this], + member-name=Extension1|get#method1, + member-params=[#this]*/ +} \ No newline at end of file diff --git a/pkg/front_end/test/extensions/data/as_show/libraries.json b/pkg/front_end/test/extensions/data/as_show/libraries.json new file mode 100644 index 00000000000..7a584cb5ffd --- /dev/null +++ b/pkg/front_end/test/extensions/data/as_show/libraries.json @@ -0,0 +1,9 @@ +{ + "none": { + "libraries": { + "test": { + "uri": "origin.dart" + } + } + } +} diff --git a/pkg/front_end/test/extensions/data/as_show/main.dart b/pkg/front_end/test/extensions/data/as_show/main.dart new file mode 100644 index 00000000000..2a7d2d1d84c --- /dev/null +++ b/pkg/front_end/test/extensions/data/as_show/main.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2019, 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. + +/*library: scope=[lib.dart.Extension1,origin.dart.Extension2]*/ + +import 'lib.dart' as lib1; +import 'lib.dart' show Extension1; + +// ignore: uri_does_not_exist +import 'dart:test' as lib2; +// ignore: uri_does_not_exist +import 'dart:test' show Extension2; + +main() { + "".method1(); + Extension1("").method1(); + "".method2(); + Extension2("").method2(); +} diff --git a/pkg/front_end/test/extensions/data/as_show/origin.dart b/pkg/front_end/test/extensions/data/as_show/origin.dart new file mode 100644 index 00000000000..1b36bb9eee6 --- /dev/null +++ b/pkg/front_end/test/extensions/data/as_show/origin.dart @@ -0,0 +1,30 @@ +// Copyright (c) 2019, 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. + +/*library: scope=[Extension2]*/ + +/*class: Extension2: + builder-name=Extension2, + builder-onType=String, + extension-members=[ + method2=Extension2|method2, + tearoff method2=Extension2|get#method2], + extension-name=Extension2, + extension-onType=String +*/ +extension Extension2 on String { +/*member: Extension2|method2: + builder-name=method2, + builder-params=[#this], + member-name=Extension2|method2, + member-params=[#this] + */ +method2() {} + +/*member: Extension2|get#method2: + builder-name=method2, + builder-params=[#this], + member-name=Extension2|get#method2, + member-params=[#this]*/ +} \ No newline at end of file diff --git a/pkg/front_end/test/extensions/data/patching/libraries.json b/pkg/front_end/test/extensions/data/patching/libraries.json new file mode 100644 index 00000000000..a6975084c8b --- /dev/null +++ b/pkg/front_end/test/extensions/data/patching/libraries.json @@ -0,0 +1,12 @@ +{ + "none": { + "libraries": { + "test": { + "patches": [ + "patch.dart" + ], + "uri": "origin.dart" + } + } + } +} diff --git a/pkg/front_end/test/extensions/data/patching/main.dart b/pkg/front_end/test/extensions/data/patching/main.dart new file mode 100644 index 00000000000..9599059bab5 --- /dev/null +++ b/pkg/front_end/test/extensions/data/patching/main.dart @@ -0,0 +1,23 @@ +// Copyright (c) 2019, 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. + +/*library: scope=[origin.dart.Extension,origin.dart.GenericExtension]*/ + +// ignore: uri_does_not_exist +import 'dart:test'; + +main() { + "".instanceMethod(); + "".genericInstanceMethod(0); + "".instanceProperty = "".instanceProperty; + Extension.staticMethod(); + Extension.genericStaticMethod(0); + Extension.staticProperty = Extension.staticProperty; + true.instanceMethod(); + true.genericInstanceMethod(0); + true.instanceProperty = true.instanceProperty; + GenericExtension.staticMethod(); + GenericExtension.genericStaticMethod(0); + GenericExtension.staticProperty = GenericExtension.staticProperty; +} diff --git a/pkg/front_end/test/extensions/data/patching/origin.dart b/pkg/front_end/test/extensions/data/patching/origin.dart new file mode 100644 index 00000000000..1a5b69e87e7 --- /dev/null +++ b/pkg/front_end/test/extensions/data/patching/origin.dart @@ -0,0 +1,108 @@ +// Copyright (c) 2019, 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. + +/*library: scope=[Extension,GenericExtension]*/ + +/*class: Extension: + builder-name=Extension, + builder-onType=String, + extension-members=[ + genericInstanceMethod=Extension|genericInstanceMethod, + getter instanceProperty=Extension|get#instanceProperty, + instanceMethod=Extension|instanceMethod, + setter instanceProperty=Extension|set#instanceProperty, + static genericStaticMethod=Extension|genericStaticMethod, + static getter staticProperty=Extension|staticProperty, + static setter staticProperty=Extension|staticProperty=, + static staticMethod=Extension|staticMethod, + tearoff genericInstanceMethod=Extension|get#genericInstanceMethod, + tearoff instanceMethod=Extension|get#instanceMethod, + ], + extension-name=Extension, + extension-onType=String +*/ +extension Extension on String { + /*member: Extension|get#instanceMethod: + builder-name=instanceMethod, + builder-params=[#this], + member-name=Extension|get#instanceMethod, + member-params=[#this] + */ + external int instanceMethod(); + + /*member: Extension|get#genericInstanceMethod: + builder-name=genericInstanceMethod, + builder-params=[#this,t], + builder-type-params=[T], + member-name=Extension|get#genericInstanceMethod, + member-params=[#this] + */ + external T genericInstanceMethod(T t); + + external static int staticMethod(); + + external static T genericStaticMethod(T t); + + external int get instanceProperty; + + external void set instanceProperty(int value); + + external static int get staticProperty; + + external static void set staticProperty(int value); +} + +/*class: GenericExtension: + builder-name=GenericExtension, + builder-onType=T, + builder-type-params=[T], + extension-members=[ + genericInstanceMethod=GenericExtension|genericInstanceMethod, + getter instanceProperty=GenericExtension|get#instanceProperty, + instanceMethod=GenericExtension|instanceMethod, + setter instanceProperty=GenericExtension|set#instanceProperty, + static genericStaticMethod=GenericExtension|genericStaticMethod, + static getter staticProperty=GenericExtension|staticProperty, + static setter staticProperty=GenericExtension|staticProperty=, + static staticMethod=GenericExtension|staticMethod, + tearoff genericInstanceMethod=GenericExtension|get#genericInstanceMethod, + tearoff instanceMethod=GenericExtension|get#instanceMethod + ], + extension-name=GenericExtension, + extension-onType=T, + extension-type-params=[T] +*/ +extension GenericExtension on T { + /*member: GenericExtension|get#instanceMethod: + builder-name=instanceMethod, + builder-params=[#this], + builder-type-params=[T], + member-name=GenericExtension|get#instanceMethod, + member-params=[#this], + member-type-params=[T] + */ + external int instanceMethod(); + + /*member: GenericExtension|get#genericInstanceMethod: + builder-name=genericInstanceMethod, + builder-params=[#this,t], + builder-type-params=[T,T], + member-name=GenericExtension|get#genericInstanceMethod, + member-params=[#this], + member-type-params=[#T] + */ + external T genericInstanceMethod(T t); + + external static int staticMethod(); + + external static T genericStaticMethod(T t); + + external int get instanceProperty; + + external void set instanceProperty(int value); + + external static int get staticProperty; + + external static void set staticProperty(int value); +} \ No newline at end of file diff --git a/pkg/front_end/test/extensions/data/patching/patch.dart b/pkg/front_end/test/extensions/data/patching/patch.dart new file mode 100644 index 00000000000..32edfc42df3 --- /dev/null +++ b/pkg/front_end/test/extensions/data/patching/patch.dart @@ -0,0 +1,163 @@ +// Copyright (c) 2019, 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. + +// ignore: import_internal_library +import 'dart:_internal'; + +@patch +extension Extension on String { + /*member: Extension|instanceMethod: + builder-name=instanceMethod, + builder-params=[#this], + member-name=Extension|instanceMethod, + member-params=[#this] + */ + @patch + int instanceMethod() => 42; + + /*member: Extension|genericInstanceMethod: + builder-name=genericInstanceMethod, + builder-params=[#this,t], + builder-type-params=[T], + member-name=Extension|genericInstanceMethod, + member-params=[#this,t], + member-type-params=[T] + */ + @patch + T genericInstanceMethod(T t) => t; + + /*member: Extension|staticMethod: + builder-name=staticMethod, + member-name=Extension|staticMethod + */ + @patch + static int staticMethod() => 87; + + /*member: Extension|genericStaticMethod: + builder-name=genericStaticMethod, + builder-params=[t], + builder-type-params=[T], + member-name=Extension|genericStaticMethod, + member-params=[t], + member-type-params=[T] + */ + @patch + static T genericStaticMethod(T t) => t; + + /*member: Extension|get#instanceProperty: + builder-name=instanceProperty, + builder-params=[#this], + member-name=Extension|get#instanceProperty, + member-params=[#this] + */ + @patch + int get instanceProperty => 123; + + /*member: Extension|set#instanceProperty: + builder-name=instanceProperty, + builder-params=[#this,value], + member-name=Extension|set#instanceProperty, + member-params=[#this,value] + */ + @patch + void set instanceProperty(int value) {} + + /*member: Extension|staticProperty: + builder-name=staticProperty, + member-name=Extension|staticProperty + */ + @patch + static int get staticProperty => 237; + + /*member: Extension|staticProperty=: + builder-name=staticProperty, + builder-params=[value], + member-name=Extension|staticProperty=, + member-params=[value] + */ + @patch + static void set staticProperty(int value) {} +} + + +@patch +extension GenericExtension on T { + /*member: GenericExtension|instanceMethod: + builder-name=instanceMethod, + builder-params=[#this], + builder-type-params=[T], + member-name=GenericExtension|instanceMethod, + member-params=[#this], + member-type-params=[T] + */ + @patch + int instanceMethod() => 42; + + /*member: GenericExtension|genericInstanceMethod: + builder-name=genericInstanceMethod, + builder-params=[#this,t], + builder-type-params=[T,T], + member-name=GenericExtension|genericInstanceMethod, + member-params=[#this,t], + member-type-params=[#T,T] + */ + @patch + T genericInstanceMethod(T t) => t; + + /*member: GenericExtension|staticMethod: + builder-name=staticMethod, + member-name=GenericExtension|staticMethod + */ + @patch + static int staticMethod() => 87; + + /*member: GenericExtension|genericStaticMethod: + builder-name=genericStaticMethod, + builder-params=[t], + builder-type-params=[T], + member-name=GenericExtension|genericStaticMethod, + member-params=[t], + member-type-params=[T] + */ + @patch + static T genericStaticMethod(T t) => t; + + /*member: GenericExtension|get#instanceProperty: + builder-name=instanceProperty, + builder-params=[#this], + builder-type-params=[T], + member-name=GenericExtension|get#instanceProperty, + member-params=[#this], + member-type-params=[T] + */ + @patch + int get instanceProperty => 123; + + /*member: GenericExtension|set#instanceProperty: + builder-name=instanceProperty, + builder-params=[#this,value], + builder-type-params=[T], + member-name=GenericExtension|set#instanceProperty, + member-params=[#this,value], + member-type-params=[T] + */ + @patch + void set instanceProperty(int value) {} + + /*member: GenericExtension|staticProperty: + builder-name=staticProperty, + member-name=GenericExtension|staticProperty + */ + @patch + static int get staticProperty => 237; + + /*member: GenericExtension|staticProperty=: + builder-name=staticProperty, + builder-params=[value], + member-name=GenericExtension|staticProperty=, + member-params=[value] + */ + @patch + static void set staticProperty(int value) {} +} \ No newline at end of file diff --git a/pkg/front_end/test/extensions/extensions_test.dart b/pkg/front_end/test/extensions/extensions_test.dart index 33e8fb4238e..880d2490372 100644 --- a/pkg/front_end/test/extensions/extensions_test.dart +++ b/pkg/front_end/test/extensions/extensions_test.dart @@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:io' show Directory, Platform; +import 'package:front_end/src/api_prototype/experimental_flags.dart' + show ExperimentalFlag; import 'package:front_end/src/fasta/builder/builder.dart'; import 'package:front_end/src/fasta/builder/extension_builder.dart'; import 'package:front_end/src/fasta/kernel/kernel_builder.dart'; @@ -22,8 +24,11 @@ main(List args) async { supportedMarkers: sharedMarkers, createUriForFileName: createUriForFileName, onFailure: onFailure, - runTest: runTestFor( - const ExtensionsDataComputer(), [cfeExtensionMethodsConfig])); + runTest: runTestFor(const ExtensionsDataComputer(), [ + new TestConfig(cfeMarker, 'cfe with extension methods', + experimentalFlags: const {ExperimentalFlag.extensionMethods: true}, + librariesSpecificationUri: createUriForFileName('libraries.json')) + ])); } class ExtensionsDataComputer extends DataComputer { diff --git a/pkg/front_end/test/id_testing/id_testing_test.dart b/pkg/front_end/test/id_testing/id_testing_test.dart index 07d99bab1f5..92a4fb553ef 100644 --- a/pkg/front_end/test/id_testing/id_testing_test.dart +++ b/pkg/front_end/test/id_testing/id_testing_test.dart @@ -58,7 +58,7 @@ class IdTestingDataComputer extends DataComputer { Library library, Map> actualMap, {bool verbose}) { new IdTestingDataExtractor(compilerResult, actualMap) - .computeForLibrary(library, useFileUri: true); + .computeForLibrary(library); } @override diff --git a/pkg/front_end/test/language_versioning/language_versioning_test.dart b/pkg/front_end/test/language_versioning/language_versioning_test.dart index 691df945f40..a387f9ab9a2 100644 --- a/pkg/front_end/test/language_versioning/language_versioning_test.dart +++ b/pkg/front_end/test/language_versioning/language_versioning_test.dart @@ -52,7 +52,7 @@ class LanguageVersioningDataComputer extends DataComputer { Library library, Map> actualMap, {bool verbose}) { new LanguageVersioningDataExtractor(compilerResult, actualMap) - .computeForLibrary(library, useFileUri: true); + .computeForLibrary(library); } @override diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md index d8a353e8094..333a741ebde 100644 --- a/pkg/kernel/binary.md +++ b/pkg/kernel/binary.md @@ -353,7 +353,7 @@ enum ExtensionMemberKind { Field = 0, Method = 1, Getter = 2, Setter = 3, Operat type ExtensionMemberDescriptor { StringReference name; ExtensionMemberKind kind; - Byte flags (isStatic, isExternal); + Byte flags (isStatic); MemberReference member; } diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart index cd777e3a370..6fb554df677 100644 --- a/pkg/kernel/lib/ast.dart +++ b/pkg/kernel/lib/ast.dart @@ -1350,7 +1350,6 @@ enum ExtensionMemberKind { /// Information about an member declaration in an extension. class ExtensionMemberDescriptor { static const int FlagStatic = 1 << 0; // Must match serialized bit positions. - static const int FlagExternal = 1 << 1; /// The name of the extension member. /// @@ -1387,28 +1386,16 @@ class ExtensionMemberDescriptor { Reference member; ExtensionMemberDescriptor( - {this.name, - this.kind, - bool isStatic: false, - bool isExternal: false, - this.member}) { + {this.name, this.kind, bool isStatic: false, this.member}) { this.isStatic = isStatic; - this.isExternal = isExternal; } /// Return `true` if the extension method was declared as `static`. bool get isStatic => flags & FlagStatic != 0; - /// Return `true` if the extension method was declared as `external`. - bool get isExternal => flags & FlagExternal != 0; - void set isStatic(bool value) { flags = value ? (flags | FlagStatic) : (flags & ~FlagStatic); } - - void set isExternal(bool value) { - flags = value ? (flags | FlagExternal) : (flags & ~FlagExternal); - } } // ------------------------------------------------------------------------ diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart index 707b3a1df87..d3a9b1a58fc 100644 --- a/pkg/kernel/lib/text/ast_to_text.dart +++ b/pkg/kernel/lib/text/ast_to_text.dart @@ -1189,7 +1189,6 @@ class Printer extends Visitor { ++indentation; node.members.forEach((ExtensionMemberDescriptor descriptor) { writeIndentation(); - writeModifier(descriptor.isExternal, 'external'); writeModifier(descriptor.isStatic, 'static'); switch (descriptor.kind) { case ExtensionMemberKind.Method: diff --git a/tests/compiler/dart2js/equivalence/id_testing_test.dart b/tests/compiler/dart2js/equivalence/id_testing_test.dart index a24168a95e1..c40ff6f9179 100644 --- a/tests/compiler/dart2js/equivalence/id_testing_test.dart +++ b/tests/compiler/dart2js/equivalence/id_testing_test.dart @@ -61,7 +61,7 @@ class IdTestingDataComputer extends DataComputer { KernelToElementMapImpl elementMap = frontendStrategy.elementMap; ir.Library node = elementMap.getLibraryNode(library); new IdTestingDataExtractor(compiler.reporter, actualMap, elementMap) - .computeForLibrary(node, useFileUri: true); + .computeForLibrary(node); } @override