[cfe] Support patching of extension methods
Change-Id: I453e17e63f97a0ca2477371541c6a9602bee2404 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119322 Reviewed-by: Jens Johansen <jensj@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
bb600e99e2
commit
dd028547ce
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
@@ -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<MetadataBuilder> 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];
|
||||
|
||||
@@ -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())})";
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<MetadataBuilder> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,9 +61,8 @@ abstract class DataExtractor<T> extends Visitor with DataRegistry<T> {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<ExperimentalFlag, bool> 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<T>(
|
||||
DataComputer<T> dataComputer, List<TestConfig> testedConfigs) {
|
||||
retainDataForTesting = true;
|
||||
return (TestData testData,
|
||||
{bool testAfterFailures, bool verbose, bool succinct, bool printCode}) {
|
||||
return runTest(testData, dataComputer, testedConfigs,
|
||||
@@ -242,6 +246,13 @@ Future<bool> runTestForConfig<T>(
|
||||
};
|
||||
options.debugDump = printCode;
|
||||
options.experimentalFlags.addAll(config.experimentalFlags);
|
||||
if (config.librariesSpecificationUri != null) {
|
||||
Set<Uri> 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,
|
||||
|
||||
@@ -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<FormattedMessage> 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 ');
|
||||
}
|
||||
|
||||
@@ -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]*/
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"none": {
|
||||
"libraries": {
|
||||
"test": {
|
||||
"uri": "origin.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();
|
||||
}
|
||||
@@ -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]*/
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"none": {
|
||||
"libraries": {
|
||||
"test": {
|
||||
"patches": [
|
||||
"patch.dart"
|
||||
],
|
||||
"uri": "origin.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<int>(0);
|
||||
"".instanceProperty = "".instanceProperty;
|
||||
Extension.staticMethod();
|
||||
Extension.genericStaticMethod<int>(0);
|
||||
Extension.staticProperty = Extension.staticProperty;
|
||||
true.instanceMethod();
|
||||
true.genericInstanceMethod<int>(0);
|
||||
true.instanceProperty = true.instanceProperty;
|
||||
GenericExtension.staticMethod();
|
||||
GenericExtension.genericStaticMethod<int>(0);
|
||||
GenericExtension.staticProperty = GenericExtension.staticProperty;
|
||||
}
|
||||
@@ -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 t);
|
||||
|
||||
external static int staticMethod();
|
||||
|
||||
external static T genericStaticMethod<T>(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<T> 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 t);
|
||||
|
||||
external static int staticMethod();
|
||||
|
||||
external static T genericStaticMethod<T>(T t);
|
||||
|
||||
external int get instanceProperty;
|
||||
|
||||
external void set instanceProperty(int value);
|
||||
|
||||
external static int get staticProperty;
|
||||
|
||||
external static void set staticProperty(int value);
|
||||
}
|
||||
@@ -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) => 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) => 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<T> 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) => 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) => 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) {}
|
||||
}
|
||||
@@ -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<String> 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<Features> {
|
||||
|
||||
@@ -58,7 +58,7 @@ class IdTestingDataComputer extends DataComputer<String> {
|
||||
Library library, Map<Id, ActualData<String>> actualMap,
|
||||
{bool verbose}) {
|
||||
new IdTestingDataExtractor(compilerResult, actualMap)
|
||||
.computeForLibrary(library, useFileUri: true);
|
||||
.computeForLibrary(library);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -52,7 +52,7 @@ class LanguageVersioningDataComputer extends DataComputer<String> {
|
||||
Library library, Map<Id, ActualData<String>> actualMap,
|
||||
{bool verbose}) {
|
||||
new LanguageVersioningDataExtractor(compilerResult, actualMap)
|
||||
.computeForLibrary(library, useFileUri: true);
|
||||
.computeForLibrary(library);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-14
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@@ -1189,7 +1189,6 @@ class Printer extends Visitor<Null> {
|
||||
++indentation;
|
||||
node.members.forEach((ExtensionMemberDescriptor descriptor) {
|
||||
writeIndentation();
|
||||
writeModifier(descriptor.isExternal, 'external');
|
||||
writeModifier(descriptor.isStatic, 'static');
|
||||
switch (descriptor.kind) {
|
||||
case ExtensionMemberKind.Method:
|
||||
|
||||
@@ -61,7 +61,7 @@ class IdTestingDataComputer extends DataComputer<String> {
|
||||
KernelToElementMapImpl elementMap = frontendStrategy.elementMap;
|
||||
ir.Library node = elementMap.getLibraryNode(library);
|
||||
new IdTestingDataExtractor(compiler.reporter, actualMap, elementMap)
|
||||
.computeForLibrary(node, useFileUri: true);
|
||||
.computeForLibrary(node);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
Reference in New Issue
Block a user