Version 2.17.0-111.0.dev
Merge commit '3a3738c6fbeef1500191a4858d61185a4eb6c016' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart b/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart
index f9296fc..c24cd91 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart
@@ -82,6 +82,9 @@
abstract class ClassMemberDeclaration implements Declaration {
/// The class that defines this method.
Identifier get definingClass;
+
+ /// Whether or not this is a static member.
+ bool get isStatic;
}
/// A declaration that defines a new type in the program.
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
index f423fcf..99c2ae5 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
@@ -2,14 +2,24 @@
// 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 'executor_shared/serialization.dart'
+ show SerializationMode, SerializationModeHelpers;
+
/// Generates a Dart program for a given set of macros, which can be compiled
/// and then passed as a precompiled kernel file to `MacroExecutor.loadMacro`.
///
/// The [macroDeclarations] is a map from library URIs to macro classes for the
/// macros supported. The macro classes are provided as a map from macro class
/// names to the names of the macro class constructors.
+///
+/// The [serializationMode] must be a client variant.
String bootstrapMacroIsolate(
- Map<String, Map<String, List<String>>> macroDeclarations) {
+ Map<String, Map<String, List<String>>> macroDeclarations,
+ SerializationMode serializationMode) {
+ if (!serializationMode.isClient) {
+ throw new ArgumentError(
+ 'Got $serializationMode but expected a client version.');
+ }
StringBuffer imports = new StringBuffer();
StringBuffer constructorEntries = new StringBuffer();
macroDeclarations
@@ -26,16 +36,21 @@
constructorEntries.writeln('},');
});
});
- return template.replaceFirst(_importMarker, imports.toString()).replaceFirst(
- _macroConstructorEntriesMarker, constructorEntries.toString());
+ return template
+ .replaceFirst(_importMarker, imports.toString())
+ .replaceFirst(
+ _macroConstructorEntriesMarker, constructorEntries.toString())
+ .replaceFirst(_modeMarker, serializationMode.asCode);
}
const String _importMarker = '{{IMPORT}}';
const String _macroConstructorEntriesMarker = '{{MACRO_CONSTRUCTOR_ENTRIES}}';
+const String _modeMarker = '{{SERIALIZATION_MODE}}';
const String template = '''
import 'dart:async';
import 'dart:isolate';
+import 'dart:typed_data';
import 'package:_fe_analyzer_shared/src/macros/executor_shared/execute_macro.dart';
import 'package:_fe_analyzer_shared/src/macros/executor_shared/introspection_impls.dart';
@@ -56,11 +71,15 @@
Future<Response> sendRequest(Request request) => _sendRequest(request, sendPort);
/// TODO: More directly support customizable serialization types.
- withSerializationMode(SerializationMode.jsonClient, () {
+ withSerializationMode($_modeMarker, () {
ReceivePort receivePort = new ReceivePort();
sendPort.send(receivePort.sendPort);
receivePort.listen((message) async {
+ if (serializationMode == SerializationMode.byteDataClient
+ && message is TransferableTypedData) {
+ message = message.materialize().asUint8List();
+ }
var deserializer = deserializerFactory(message)
..moveNext();
int zoneId = deserializer.expectInt();
@@ -91,7 +110,7 @@
default:
throw new StateError('Unhandled event type \$type');
}
- sendPort.send(serializer.result);
+ _sendResult(serializer, sendPort);
});
});
}
@@ -252,7 +271,18 @@
Serializer serializer = serializerFactory();
serializer.addInt(request.serializationZoneId);
request.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer, sendPort);
return completer.future;
}
+
+/// Sends [serializer.result] to [sendPort], possibly wrapping it in a
+/// [TransferableTypedData] object.
+void _sendResult(Serializer serializer, SendPort sendPort) {
+ if (serializationMode == SerializationMode.byteDataClient) {
+ sendPort.send(
+ TransferableTypedData.fromList([serializer.result as Uint8List]));
+ } else {
+ sendPort.send(serializer.result);
+ }
+}
''';
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
index 67190b0..ade1e6d 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
@@ -6,15 +6,6 @@
import 'bootstrap.dart'; // For doc comments only.
import 'executor_shared/serialization.dart';
-/// Exposes a platform specific [MacroExecutor], through a top level
-/// `Future<MacroExecutor> start()` function.
-///
-/// TODO: conditionally load isolate_mirrors_executor.dart once conditional
-/// imports of mirrors are supported in AOT (issue #48057).
-import 'fake_executor/fake_executor.dart'
- if (dart.library.isolate) 'isolated_executor/isolated_executor.dart'
- as executor_impl show start;
-
/// The interface used by Dart language implementations, in order to load
/// and execute macros, as well as produce library augmentations from those
/// macro applications.
@@ -23,14 +14,6 @@
/// during macro discovery and expansion, and unifies how augmentation libraries
/// are produced.
abstract class MacroExecutor {
- /// Returns a platform specific [MacroExecutor]. On unsupported platforms this
- /// will be a fake executor object, which will throw an [UnsupportedError] if
- /// used.
- ///
- /// Note that some implementations will also require calls to [loadMacro]
- /// to pass a `precompiledKernelUri`.
- static Future<MacroExecutor> start() => executor_impl.start();
-
/// Invoked when an implementation discovers a new macro definition in a
/// [library] with [name], and prepares this executor to run the macro.
///
@@ -261,6 +244,7 @@
/// The types of identifiers.
enum IdentifierKind {
instanceMember,
+ local, // Parameters, local variables, etc.
staticInstanceMember,
topLevelMember,
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/builder_impls.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/builder_impls.dart
index 9f14be98..6f70c92 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/builder_impls.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/builder_impls.dart
@@ -269,18 +269,21 @@
if (getter != null) {
augmentations.add(new DeclarationCode.fromParts([
'augment ',
+ if (declaration is FieldDeclaration && declaration.isStatic) 'static ',
getter,
]));
}
if (setter != null) {
augmentations.add(new DeclarationCode.fromParts([
'augment ',
+ if (declaration is FieldDeclaration && declaration.isStatic) 'static ',
setter,
]));
}
if (initializer != null) {
augmentations.add(new DeclarationCode.fromParts([
'augment ',
+ if (declaration is FieldDeclaration && declaration.isStatic) 'static ',
if (declaration.isFinal) 'final ',
declaration.type.code,
' ',
@@ -310,6 +313,7 @@
declaration.definingClass.name,
if (declaration.identifier.name.isNotEmpty) '.',
] else ...[
+ if (declaration is MethodDeclaration && declaration.isStatic) 'static ',
declaration.returnType.code,
' ',
if (declaration.isOperator) 'operator ',
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart
index ebf86e2..857674e 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/introspection_impls.dart
@@ -330,6 +330,9 @@
@override
RemoteInstanceKind get kind => RemoteInstanceKind.methodDeclaration;
+ @override
+ final bool isStatic;
+
MethodDeclarationImpl({
// Declaration fields
required int id,
@@ -346,6 +349,7 @@
required List<TypeParameterDeclarationImpl> typeParameters,
// Method fields
required this.definingClass,
+ required this.isStatic,
}) : super(
id: id,
identifier: identifier,
@@ -367,6 +371,7 @@
if (serializationMode.isClient) return;
definingClass.serialize(serializer);
+ serializer.addBool(isStatic);
}
}
@@ -409,6 +414,7 @@
returnType: returnType,
typeParameters: typeParameters,
definingClass: definingClass,
+ isStatic: true,
);
@override
@@ -466,6 +472,9 @@
@override
final IdentifierImpl definingClass;
+ @override
+ final bool isStatic;
+
FieldDeclarationImpl({
// Declaration fields
required int id,
@@ -477,6 +486,7 @@
required TypeAnnotationImpl type,
// Field fields
required this.definingClass,
+ required this.isStatic,
}) : super(
id: id,
identifier: identifier,
@@ -494,6 +504,7 @@
if (serializationMode.isClient) return;
definingClass.serialize(serializer);
+ serializer.addBool(isStatic);
}
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization.dart
index 8adf1a1..267a46f 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization.dart
@@ -601,7 +601,7 @@
jsonClient,
}
-extension IsClient on SerializationMode {
+extension SerializationModeHelpers on SerializationMode {
bool get isClient {
switch (this) {
case SerializationMode.byteDataClient:
@@ -612,4 +612,18 @@
return false;
}
}
+
+ /// A stable string to write in code.
+ String get asCode {
+ switch (this) {
+ case SerializationMode.byteDataClient:
+ return 'SerializationMode.byteDataClient';
+ case SerializationMode.byteDataServer:
+ return 'SerializationMode.byteDataServer';
+ case SerializationMode.jsonClient:
+ return 'SerializationMode.jsonClient';
+ case SerializationMode.jsonServer:
+ return 'SerializationMode.jsonServer';
+ }
+ }
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization_extensions.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization_extensions.dart
index 5a6df71..cc7e8cb 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization_extensions.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor_shared/serialization_extensions.dart
@@ -139,6 +139,7 @@
returnType: RemoteInstance.deserialize(this),
typeParameters: (this..moveNext())._expectRemoteInstanceList(),
definingClass: RemoteInstance.deserialize(this),
+ isStatic: (this..moveNext()).expectBool(),
);
ConstructorDeclaration _expectConstructorDeclaration(int id) =>
@@ -155,7 +156,13 @@
returnType: RemoteInstance.deserialize(this),
typeParameters: (this..moveNext())._expectRemoteInstanceList(),
definingClass: RemoteInstance.deserialize(this),
- isFactory: (this..moveNext()).expectBool(),
+ // There is an extra boolean here representing the `isStatic` field
+ // which we just skip past.
+ isFactory: (this
+ ..moveNext()
+ ..expectBool()
+ ..moveNext())
+ .expectBool(),
);
VariableDeclaration _expectVariableDeclaration(int id) =>
@@ -176,6 +183,7 @@
isLate: (this..moveNext()).expectBool(),
type: RemoteInstance.deserialize(this),
definingClass: RemoteInstance.deserialize(this),
+ isStatic: (this..moveNext()).expectBool(),
);
ClassDeclaration _expectClassDeclaration(int id) => new ClassDeclarationImpl(
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/fake_executor/fake_executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/fake_executor/fake_executor.dart
deleted file mode 100644
index 9bfd0a7..0000000
--- a/pkg/_fe_analyzer_shared/lib/src/macros/fake_executor/fake_executor.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2021, 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.
-
-import '../executor.dart';
-
-/// The only public api exposed by this library, returns a [_FakeMacroExecutor].
-Future<MacroExecutor> start() async => new _FakeMacroExecutor();
-
-/// A [MacroExecutor] implementation which throws an [UnsupportedError] in all
-/// methods.
-class _FakeMacroExecutor implements MacroExecutor {
- @override
- dynamic noSuchMethod(Invocation invocation) {
- throw new UnsupportedError(
- 'Macro expansion is not supported on this platform.');
- }
-}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
index dcd267c..1efa621 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/isolated_executor/isolated_executor.dart
@@ -4,6 +4,7 @@
import 'dart:async';
import 'dart:isolate';
+import 'dart:typed_data';
import 'package:_fe_analyzer_shared/src/macros/executor_shared/remote_instance.dart';
@@ -15,10 +16,13 @@
import '../executor_shared/serialization.dart';
import '../executor.dart';
-/// Returns an instance of [_IsolatedMacroExecutor].
+/// Returns an instance of [_IsolatedMacroExecutor] using [serializationMode].
+///
+/// The [serializationMode] must be a `server` variant;
///
/// This is the only public api exposed by this library.
-Future<MacroExecutor> start() async => new _IsolatedMacroExecutor();
+Future<MacroExecutor> start(SerializationMode serializationMode) async =>
+ new _IsolatedMacroExecutor(serializationMode);
/// A [MacroExecutor] implementation which spawns a separate isolate for each
/// macro that is loaded. Each of these is wrapped in its own
@@ -35,6 +39,16 @@
/// [MacroInstanceIdentifier].
final _executors = <Object, _SingleIsolatedMacroExecutor>{};
+ /// The mode to use for serialization - must be a `server` variant.
+ final SerializationMode _serializationMode;
+
+ _IsolatedMacroExecutor(this._serializationMode) {
+ if (_serializationMode.isClient) {
+ throw new ArgumentError(
+ 'Got $serializationMode but expected a server version.');
+ }
+ }
+
@override
void close() {
for (_SingleIsolatedMacroExecutor executor in _executors.values) {
@@ -92,7 +106,7 @@
_SingleIsolatedMacroExecutor executor =
await _SingleIsolatedMacroExecutor.start(
- library, name, precompiledKernelUri);
+ library, name, precompiledKernelUri, _serializationMode);
_executors[identifier] = executor;
return identifier;
}
@@ -112,6 +126,9 @@
/// A map of response completers by request id.
final responseCompleters = <int, Completer<Response>>{};
+ /// The mode to use for serialization - must be a `server` variant.
+ final SerializationMode serializationMode;
+
/// We need to know which serialization zone to deserialize objects in, so
/// that we read them from the correct cache. Each request creates its own
/// zone which it stores here by ID and then responses are deserialized in
@@ -124,11 +141,15 @@
_SingleIsolatedMacroExecutor(
{required this.onClose,
required this.messageStream,
- required this.sendPort}) {
+ required this.sendPort,
+ required this.serializationMode}) {
messageStream.listen((message) {
- withSerializationMode(SerializationMode.jsonServer, () {
- Deserializer deserializer =
- deserializerFactory(message as List<Object?>);
+ if (serializationMode == SerializationMode.byteDataServer &&
+ message is TransferableTypedData) {
+ message = message.materialize().asUint8List();
+ }
+ withSerializationMode(serializationMode, () {
+ Deserializer deserializer = deserializerFactory(message);
// Every object starts with a zone ID which dictates the zone in which
// we should deserialize the message.
deserializer.moveNext();
@@ -171,7 +192,7 @@
serializationZoneId: zoneId);
Serializer serializer = serializerFactory();
response.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer);
break;
case MessageType.isExactlyTypeRequest:
IsExactlyTypeRequest request =
@@ -186,7 +207,7 @@
serializationZoneId: zoneId);
Serializer serializer = serializerFactory();
response.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer);
break;
case MessageType.isSubtypeOfRequest:
IsSubtypeOfRequest request =
@@ -201,7 +222,7 @@
serializationZoneId: zoneId);
Serializer serializer = serializerFactory();
response.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer);
break;
case MessageType.declarationOfRequest:
DeclarationOfRequest request =
@@ -217,7 +238,7 @@
serializationZoneId: zoneId);
Serializer serializer = serializerFactory();
response.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer);
break;
case MessageType.constructorsOfRequest:
ClassIntrospectionRequest request =
@@ -235,7 +256,7 @@
serializationZoneId: zoneId);
Serializer serializer = serializerFactory();
response.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer);
break;
case MessageType.fieldsOfRequest:
ClassIntrospectionRequest request =
@@ -253,7 +274,7 @@
serializationZoneId: zoneId);
Serializer serializer = serializerFactory();
response.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer);
break;
case MessageType.interfacesOfRequest:
ClassIntrospectionRequest request =
@@ -271,7 +292,7 @@
serializationZoneId: zoneId);
Serializer serializer = serializerFactory();
response.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer);
break;
case MessageType.methodsOfRequest:
ClassIntrospectionRequest request =
@@ -289,7 +310,7 @@
serializationZoneId: zoneId);
Serializer serializer = serializerFactory();
response.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer);
break;
case MessageType.mixinsOfRequest:
ClassIntrospectionRequest request =
@@ -307,7 +328,7 @@
serializationZoneId: zoneId);
Serializer serializer = serializerFactory();
response.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer);
break;
case MessageType.superclassOfRequest:
ClassIntrospectionRequest request =
@@ -325,7 +346,7 @@
serializationZoneId: zoneId);
Serializer serializer = serializerFactory();
response.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer);
break;
default:
throw new StateError('Unexpected message type $messageType');
@@ -335,8 +356,8 @@
});
}
- static Future<_SingleIsolatedMacroExecutor> start(
- Uri library, String name, Uri precompiledKernelUri) async {
+ static Future<_SingleIsolatedMacroExecutor> start(Uri library, String name,
+ Uri precompiledKernelUri, SerializationMode serializationMode) async {
ReceivePort receivePort = new ReceivePort();
Isolate isolate =
await Isolate.spawnUri(precompiledKernelUri, [], receivePort.sendPort);
@@ -357,7 +378,8 @@
isolate.kill();
},
messageStream: messageStreamController.stream,
- sendPort: await sendPortCompleter.future);
+ sendPort: await sendPortCompleter.future,
+ serializationMode: serializationMode);
}
@override
@@ -436,7 +458,7 @@
/// Creates a [Request] with a given serialization zone ID, and handles the
/// response, casting it to the expected type or throwing the error provided.
Future<T> _sendRequest<T>(Request Function(int) requestFactory) =>
- withSerializationMode(SerializationMode.jsonServer, () async {
+ withSerializationMode(serializationMode, () async {
int zoneId = _nextSerializationZoneId++;
serializationZones[zoneId] = Zone.current;
Request request = requestFactory(zoneId);
@@ -444,7 +466,7 @@
// It is our responsibility to add the zone ID header.
serializer.addInt(zoneId);
request.serialize(serializer);
- sendPort.send(serializer.result);
+ _sendResult(serializer);
Completer<Response> completer = new Completer<Response>();
responseCompleters[request.id] = completer;
try {
@@ -458,4 +480,15 @@
serializationZones.remove(zoneId);
}
});
+
+ /// Sends [serializer.result] to [sendPort], possibly wrapping it in a
+ /// [TransferableTypedData] object.
+ void _sendResult(Serializer serializer) {
+ if (serializationMode == SerializationMode.byteDataServer) {
+ sendPort.send(
+ new TransferableTypedData.fromList([serializer.result as Uint8List]));
+ } else {
+ sendPort.send(serializer.result);
+ }
+ }
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index f8572cf..bb5c37e 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -2787,6 +2787,16 @@
problemMessage: r"""Enum constructors can't be torn off.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeEnumContainsValuesDeclaration =
+ messageEnumContainsValuesDeclaration;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageEnumContainsValuesDeclaration = const MessageCode(
+ "EnumContainsValuesDeclaration",
+ problemMessage:
+ r"""Enums can't contain declarations of members with the name 'values'.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeEnumDeclarationEmpty = messageEnumDeclarationEmpty;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart b/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart
index 67cc977..5a9842e 100644
--- a/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/executor_shared/serialization_test.dart
@@ -226,7 +226,8 @@
positionalParameters: [barPositionalParam],
returnType: fooType,
typeParameters: [zapTypeParam],
- definingClass: fooType.identifier);
+ definingClass: fooType.identifier,
+ isStatic: false);
expectSerializationEquality(method, mode);
});
@@ -273,6 +274,7 @@
isLate: false,
type: barType,
definingClass: fooType.identifier,
+ isStatic: false,
);
expectSerializationEquality(bar, mode);
});
diff --git a/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart b/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart
index 5710e81..ec4408f 100644
--- a/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/isolated_executor/isolated_executor_test.dart
@@ -7,6 +7,7 @@
import 'package:_fe_analyzer_shared/src/macros/bootstrap.dart';
import 'package:_fe_analyzer_shared/src/macros/executor.dart';
+import 'package:_fe_analyzer_shared/src/macros/executor_shared/serialization.dart';
import 'package:_fe_analyzer_shared/src/macros/isolated_executor/isolated_executor.dart'
as isolatedExecutor;
@@ -23,235 +24,246 @@
late File simpleMacroFile;
late Directory tmpDir;
- setUpAll(() async {
- // We support running from either the root of the SDK or the package root.
- simpleMacroFile = File(
- 'pkg/_fe_analyzer_shared/test/macros/isolated_executor/simple_macro.dart');
- if (!simpleMacroFile.existsSync()) {
- simpleMacroFile = File('test/macros/isolated_executor/simple_macro.dart');
- }
- executor = await isolatedExecutor.start();
- tmpDir = Directory.systemTemp.createTempSync('isolated_executor_test');
- macroUri = simpleMacroFile.absolute.uri;
+ for (var mode in [
+ SerializationMode.byteDataServer,
+ SerializationMode.jsonServer
+ ]) {
+ final clientMode = mode == SerializationMode.byteDataServer
+ ? SerializationMode.byteDataClient
+ : SerializationMode.jsonClient;
- var bootstrapContent = bootstrapMacroIsolate({
- macroUri.toString(): {
- macroName: ['', 'named']
- }
- });
- var bootstrapFile = File(tmpDir.uri.resolve('main.dart').toFilePath())
- ..writeAsStringSync(bootstrapContent);
- kernelOutputFile = File(tmpDir.uri.resolve('main.dart.dill').toFilePath());
- var buildSnapshotResult = await Process.run(Platform.resolvedExecutable, [
- '--snapshot=${kernelOutputFile.uri.toFilePath()}',
- '--snapshot-kind=kernel',
- '--packages=${(await Isolate.packageConfig)!}',
- bootstrapFile.uri.toFilePath(),
- ]);
- expect(buildSnapshotResult.exitCode, 0,
- reason: 'stdout: ${buildSnapshotResult.stdout}\n'
- 'stderr: ${buildSnapshotResult.stderr}');
+ group('$mode', () {
+ setUpAll(() async {
+ simpleMacroFile =
+ File(Platform.script.resolve('simple_macro.dart').toFilePath());
+ executor = await isolatedExecutor.start(mode);
+ tmpDir = Directory.systemTemp.createTempSync('isolated_executor_test');
+ macroUri = simpleMacroFile.absolute.uri;
- var clazzId = await executor.loadMacro(macroUri, macroName,
- precompiledKernelUri: kernelOutputFile.uri);
- expect(clazzId, isNotNull, reason: 'Can load a macro.');
+ var bootstrapContent = bootstrapMacroIsolate({
+ macroUri.toString(): {
+ macroName: ['', 'named']
+ }
+ }, clientMode);
+ var bootstrapFile = File(tmpDir.uri.resolve('main.dart').toFilePath())
+ ..writeAsStringSync(bootstrapContent);
+ kernelOutputFile =
+ File(tmpDir.uri.resolve('main.dart.dill').toFilePath());
+ var buildSnapshotResult =
+ await Process.run(Platform.resolvedExecutable, [
+ '--snapshot=${kernelOutputFile.uri.toFilePath()}',
+ '--snapshot-kind=kernel',
+ '--packages=${(await Isolate.packageConfig)!}',
+ bootstrapFile.uri.toFilePath(),
+ ]);
+ expect(buildSnapshotResult.exitCode, 0,
+ reason: 'stdout: ${buildSnapshotResult.stdout}\n'
+ 'stderr: ${buildSnapshotResult.stderr}');
- instanceId =
- await executor.instantiateMacro(clazzId, '', Arguments([], {}));
- expect(instanceId, isNotNull,
- reason: 'Can create an instance with no arguments.');
+ var clazzId = await executor.loadMacro(macroUri, macroName,
+ precompiledKernelUri: kernelOutputFile.uri);
+ expect(clazzId, isNotNull, reason: 'Can load a macro.');
- instanceId =
- await executor.instantiateMacro(clazzId, '', Arguments([1, 2], {}));
- expect(instanceId, isNotNull,
- reason: 'Can create an instance with positional arguments.');
+ instanceId =
+ await executor.instantiateMacro(clazzId, '', Arguments([], {}));
+ expect(instanceId, isNotNull,
+ reason: 'Can create an instance with no arguments.');
- instanceId = await executor.instantiateMacro(
- clazzId, 'named', Arguments([], {'x': 1, 'y': 2}));
- expect(instanceId, isNotNull,
- reason: 'Can create an instance with named arguments.');
- });
+ instanceId =
+ await executor.instantiateMacro(clazzId, '', Arguments([1, 2], {}));
+ expect(instanceId, isNotNull,
+ reason: 'Can create an instance with positional arguments.');
- tearDownAll(() {
- if (tmpDir.existsSync()) tmpDir.deleteSync(recursive: true);
- executor.close();
- });
-
- group('run macros', () {
- group('in the types phase', () {
- test('on functions', () async {
- var result =
- await executor.executeTypesPhase(instanceId, Fixtures.myFunction);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('class GeneratedByMyFunction {}'));
+ instanceId = await executor.instantiateMacro(
+ clazzId, 'named', Arguments([], {'x': 1, 'y': 2}));
+ expect(instanceId, isNotNull,
+ reason: 'Can create an instance with named arguments.');
});
- test('on methods', () async {
- var result =
- await executor.executeTypesPhase(instanceId, Fixtures.myMethod);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('class GeneratedByMyMethod {}'));
+ tearDownAll(() {
+ if (tmpDir.existsSync()) tmpDir.deleteSync(recursive: true);
+ executor.close();
});
- test('on getters', () async {
- var result = await executor.executeTypesPhase(
- instanceId,
- Fixtures.myVariableGetter,
- );
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('class GeneratedByMyVariableGetter {}'));
- });
+ group('run macros', () {
+ group('in the types phase', () {
+ test('on functions', () async {
+ var result = await executor.executeTypesPhase(
+ instanceId, Fixtures.myFunction);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('class GeneratedByMyFunction {}'));
+ });
- test('on setters', () async {
- var result = await executor.executeTypesPhase(
- instanceId,
- Fixtures.myVariableSetter,
- );
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('class GeneratedByMyVariableSetter {}'));
- });
+ test('on methods', () async {
+ var result =
+ await executor.executeTypesPhase(instanceId, Fixtures.myMethod);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('class GeneratedByMyMethod {}'));
+ });
- test('on variables', () async {
- var result = await executor.executeTypesPhase(
- instanceId,
- Fixtures.myVariable,
- );
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('class GeneratedBy_myVariable {}'));
- });
+ test('on getters', () async {
+ var result = await executor.executeTypesPhase(
+ instanceId,
+ Fixtures.myVariableGetter,
+ );
+ expect(
+ result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace(
+ 'class GeneratedByMyVariableGetter {}'));
+ });
- test('on constructors', () async {
- var result = await executor.executeTypesPhase(
- instanceId, Fixtures.myConstructor);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('class GeneratedByMyConstructor {}'));
- });
+ test('on setters', () async {
+ var result = await executor.executeTypesPhase(
+ instanceId,
+ Fixtures.myVariableSetter,
+ );
+ expect(
+ result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace(
+ 'class GeneratedByMyVariableSetter {}'));
+ });
- test('on fields', () async {
- var result =
- await executor.executeTypesPhase(instanceId, Fixtures.myField);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('class GeneratedByMyField {}'));
- });
+ test('on variables', () async {
+ var result = await executor.executeTypesPhase(
+ instanceId,
+ Fixtures.myVariable,
+ );
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('class GeneratedBy_myVariable {}'));
+ });
- test('on classes', () async {
- var result =
- await executor.executeTypesPhase(instanceId, Fixtures.myClass);
- expect(
- result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace(
- 'class MyClassBuilder implements Builder<MyClass> {}'));
- });
- });
+ test('on constructors', () async {
+ var result = await executor.executeTypesPhase(
+ instanceId, Fixtures.myConstructor);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('class GeneratedByMyConstructor {}'));
+ });
- group('in the declaration phase', () {
- test('on functions', () async {
- var result = await executor.executeDeclarationsPhase(
- instanceId,
- Fixtures.myFunction,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector);
- expect(
- result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace(
- 'String delegateMyFunction() => myFunction();'));
- });
+ test('on fields', () async {
+ var result =
+ await executor.executeTypesPhase(instanceId, Fixtures.myField);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('class GeneratedByMyField {}'));
+ });
- test('on methods', () async {
- var result = await executor.executeDeclarationsPhase(
- instanceId,
- Fixtures.myMethod,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector);
- expect(
- result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace(
- 'String delegateMemberMyMethod() => myMethod();'));
- });
+ test('on classes', () async {
+ var result =
+ await executor.executeTypesPhase(instanceId, Fixtures.myClass);
+ expect(
+ result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace(
+ 'class MyClassBuilder implements Builder<MyClass> {}'));
+ });
+ });
- test('on constructors', () async {
- var result = await executor.executeDeclarationsPhase(
- instanceId,
- Fixtures.myConstructor,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('''
+ group('in the declaration phase', () {
+ test('on functions', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId,
+ Fixtures.myFunction,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector);
+ expect(
+ result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace(
+ 'String delegateMyFunction() => myFunction();'));
+ });
+
+ test('on methods', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId,
+ Fixtures.myMethod,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector);
+ expect(
+ result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace(
+ 'String delegateMemberMyMethod() => myMethod();'));
+ });
+
+ test('on constructors', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId,
+ Fixtures.myConstructor,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
augment class MyClass {
factory MyClass.myConstructorDelegate() => MyClass.myConstructor();
}'''));
- });
+ });
- test('on getters', () async {
- var result = await executor.executeDeclarationsPhase(
- instanceId,
- Fixtures.myVariableGetter,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('''
+ test('on getters', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId,
+ Fixtures.myVariableGetter,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
String get delegateMyVariable => myVariable;'''));
- });
+ });
- test('on setters', () async {
- var result = await executor.executeDeclarationsPhase(
- instanceId,
- Fixtures.myVariableSetter,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('''
+ test('on setters', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId,
+ Fixtures.myVariableSetter,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
void set delegateMyVariable(String value) => myVariable = value;'''));
- });
+ });
- test('on variables', () async {
- var result = await executor.executeDeclarationsPhase(
- instanceId,
- Fixtures.myVariable,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('''
+ test('on variables', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId,
+ Fixtures.myVariable,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
String get delegate_myVariable => _myVariable;'''));
- });
+ });
- test('on fields', () async {
- var result = await executor.executeDeclarationsPhase(
- instanceId,
- Fixtures.myField,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('''
+ test('on fields', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId,
+ Fixtures.myField,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
augment class MyClass {
String get delegateMyField => myField;
}'''));
- });
+ });
- test('on classes', () async {
- var result = await executor.executeDeclarationsPhase(
- instanceId,
- Fixtures.myClass,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('''
+ test('on classes', () async {
+ var result = await executor.executeDeclarationsPhase(
+ instanceId,
+ Fixtures.myClass,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
augment class MyClass {
static const List<String> fieldNames = ['myField',];
}'''));
- });
- });
+ });
+ });
- group('in the definition phase', () {
- test('on functions', () async {
- var result = await executor.executeDefinitionsPhase(
- instanceId,
- Fixtures.myFunction,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector,
- Fixtures.testTypeDeclarationResolver);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('''
+ group('in the definition phase', () {
+ test('on functions', () async {
+ var result = await executor.executeDefinitionsPhase(
+ instanceId,
+ Fixtures.myFunction,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector,
+ Fixtures.testTypeDeclarationResolver);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
augment String myFunction() {
print('isAbstract: false');
print('isExternal: false');
@@ -260,43 +272,45 @@
print('returnType: String');
return augment super();
}'''));
- });
+ });
- test('on methods', () async {
- var definitionResult = await executor.executeDefinitionsPhase(
- instanceId,
- Fixtures.myMethod,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector,
- Fixtures.testTypeDeclarationResolver);
- expect(definitionResult.augmentations, hasLength(2));
- var augmentationStrings = definitionResult.augmentations
- .map((a) => a.debugString().toString())
- .toList();
- expect(augmentationStrings, unorderedEquals(methodDefinitionMatchers));
- });
+ test('on methods', () async {
+ var definitionResult = await executor.executeDefinitionsPhase(
+ instanceId,
+ Fixtures.myMethod,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector,
+ Fixtures.testTypeDeclarationResolver);
+ expect(definitionResult.augmentations, hasLength(2));
+ var augmentationStrings = definitionResult.augmentations
+ .map((a) => a.debugString().toString())
+ .toList();
+ expect(
+ augmentationStrings, unorderedEquals(methodDefinitionMatchers));
+ });
- test('on constructors', () async {
- var definitionResult = await executor.executeDefinitionsPhase(
- instanceId,
- Fixtures.myConstructor,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector,
- Fixtures.testTypeDeclarationResolver);
- expect(definitionResult.augmentations, hasLength(1));
- expect(definitionResult.augmentations.first.debugString().toString(),
- constructorDefinitionMatcher);
- });
+ test('on constructors', () async {
+ var definitionResult = await executor.executeDefinitionsPhase(
+ instanceId,
+ Fixtures.myConstructor,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector,
+ Fixtures.testTypeDeclarationResolver);
+ expect(definitionResult.augmentations, hasLength(1));
+ expect(
+ definitionResult.augmentations.first.debugString().toString(),
+ constructorDefinitionMatcher);
+ });
- test('on getters', () async {
- var result = await executor.executeDefinitionsPhase(
- instanceId,
- Fixtures.myVariableGetter,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector,
- Fixtures.testTypeDeclarationResolver);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('''
+ test('on getters', () async {
+ var result = await executor.executeDefinitionsPhase(
+ instanceId,
+ Fixtures.myVariableGetter,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector,
+ Fixtures.testTypeDeclarationResolver);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
augment String myVariable() {
print('isAbstract: false');
print('isExternal: false');
@@ -305,17 +319,17 @@
print('returnType: String');
return augment super;
}'''));
- });
+ });
- test('on setters', () async {
- var result = await executor.executeDefinitionsPhase(
- instanceId,
- Fixtures.myVariableSetter,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector,
- Fixtures.testTypeDeclarationResolver);
- expect(result.augmentations.single.debugString().toString(),
- equalsIgnoringWhitespace('''
+ test('on setters', () async {
+ var result = await executor.executeDefinitionsPhase(
+ instanceId,
+ Fixtures.myVariableSetter,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector,
+ Fixtures.testTypeDeclarationResolver);
+ expect(result.augmentations.single.debugString().toString(),
+ equalsIgnoringWhitespace('''
augment void myVariable(String value, ) {
print('isAbstract: false');
print('isExternal: false');
@@ -325,19 +339,19 @@
print('positionalParam: String value');
return augment super = value;
}'''));
- });
+ });
- test('on variables', () async {
- var result = await executor.executeDefinitionsPhase(
- instanceId,
- Fixtures.myVariable,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector,
- Fixtures.testTypeDeclarationResolver);
- expect(
- result.augmentations.map((a) => a.debugString().toString()),
- unorderedEquals([
- equalsIgnoringWhitespace('''
+ test('on variables', () async {
+ var result = await executor.executeDefinitionsPhase(
+ instanceId,
+ Fixtures.myVariable,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector,
+ Fixtures.testTypeDeclarationResolver);
+ expect(
+ result.augmentations.map((a) => a.debugString().toString()),
+ unorderedEquals([
+ equalsIgnoringWhitespace('''
augment String get _myVariable {
print('parentClass: ');
print('isExternal: false');
@@ -345,48 +359,51 @@
print('isLate: false');
return augment super;
}'''),
- equalsIgnoringWhitespace('''
+ equalsIgnoringWhitespace('''
augment set _myVariable(String value) {
augment super = value;
}'''),
- equalsIgnoringWhitespace('''
+ equalsIgnoringWhitespace('''
augment final String _myVariable = 'new initial value' + augment super;
'''),
- ]));
- });
+ ]));
+ });
- test('on fields', () async {
- var definitionResult = await executor.executeDefinitionsPhase(
- instanceId,
- Fixtures.myField,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector,
- Fixtures.testTypeDeclarationResolver);
- expect(definitionResult.augmentations, hasLength(1));
- expect(definitionResult.augmentations.first.debugString().toString(),
- fieldDefinitionMatcher);
- });
+ test('on fields', () async {
+ var definitionResult = await executor.executeDefinitionsPhase(
+ instanceId,
+ Fixtures.myField,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector,
+ Fixtures.testTypeDeclarationResolver);
+ expect(definitionResult.augmentations, hasLength(1));
+ expect(
+ definitionResult.augmentations.first.debugString().toString(),
+ fieldDefinitionMatcher);
+ });
- test('on classes', () async {
- var definitionResult = await executor.executeDefinitionsPhase(
- instanceId,
- Fixtures.myClass,
- Fixtures.testTypeResolver,
- Fixtures.testClassIntrospector,
- Fixtures.testTypeDeclarationResolver);
- var augmentationStrings = definitionResult.augmentations
- .map((a) => a.debugString().toString())
- .toList();
- expect(
- augmentationStrings,
- unorderedEquals([
- ...methodDefinitionMatchers,
- constructorDefinitionMatcher,
- fieldDefinitionMatcher
- ]));
+ test('on classes', () async {
+ var definitionResult = await executor.executeDefinitionsPhase(
+ instanceId,
+ Fixtures.myClass,
+ Fixtures.testTypeResolver,
+ Fixtures.testClassIntrospector,
+ Fixtures.testTypeDeclarationResolver);
+ var augmentationStrings = definitionResult.augmentations
+ .map((a) => a.debugString().toString())
+ .toList();
+ expect(
+ augmentationStrings,
+ unorderedEquals([
+ ...methodDefinitionMatchers,
+ constructorDefinitionMatcher,
+ fieldDefinitionMatcher
+ ]));
+ });
+ });
});
});
- });
+ }
}
final constructorDefinitionMatcher = equalsIgnoringWhitespace('''
diff --git a/pkg/_fe_analyzer_shared/test/macros/util.dart b/pkg/_fe_analyzer_shared/test/macros/util.dart
index 725b3fd..88f02d6 100644
--- a/pkg/_fe_analyzer_shared/test/macros/util.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/util.dart
@@ -359,7 +359,8 @@
isFinal: false,
isLate: false,
type: stringType,
- definingClass: myClassType.identifier);
+ definingClass: myClassType.identifier,
+ isStatic: false);
static final myInterface = ClassDeclarationImpl(
id: RemoteInstance.uniqueId,
identifier: myInterfaceType.identifier,
@@ -381,7 +382,8 @@
positionalParameters: [],
returnType: stringType,
typeParameters: [],
- definingClass: myClassType.identifier);
+ definingClass: myClassType.identifier,
+ isStatic: false);
static final myMixin = ClassDeclarationImpl(
id: RemoteInstance.uniqueId,
identifier: myMixinType.identifier,
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 9491945..ba54779 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -7,8 +7,6 @@
import 'dart:async' show Future;
import 'dart:convert' show jsonEncode;
-import 'package:front_end/src/api_unstable/dart2js.dart'
- show clearStringTokenCanonicalizer;
import 'package:kernel/ast.dart' as ir;
import '../compiler.dart' as api;
@@ -412,7 +410,6 @@
// such caches in the compiler and get access to them through a
// suitably maintained static reference to the current compiler.
void clearState() {
- clearStringTokenCanonicalizer();
Selector.canonicalizedValues.clear();
// The selector objects held in static fields must remain canonical.
diff --git a/pkg/compiler/lib/src/ir/scope_visitor.dart b/pkg/compiler/lib/src/ir/scope_visitor.dart
index a95894c..4e0fc1e 100644
--- a/pkg/compiler/lib/src/ir/scope_visitor.dart
+++ b/pkg/compiler/lib/src/ir/scope_visitor.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 ir;
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/core_types.dart' as ir;
import 'package:kernel/type_environment.dart' as ir;
@@ -115,7 +114,7 @@
}
} else {
assert(node is ir.Procedure || node is ir.Constructor);
- if (!(node is ir.Procedure && ir.isRedirectingFactory(node))) {
+ if (!(node is ir.Procedure && node.isRedirectingFactory)) {
// Skip redirecting factories: they contain invalid expressions only
// used to suppport internal CFE modular compilation.
node.accept(this);
diff --git a/pkg/compiler/lib/src/kernel/env.dart b/pkg/compiler/lib/src/kernel/env.dart
index 55f7892..6943a31 100644
--- a/pkg/compiler/lib/src/kernel/env.dart
+++ b/pkg/compiler/lib/src/kernel/env.dart
@@ -5,7 +5,7 @@
library dart2js.kernel.env;
import 'package:front_end/src/api_unstable/dart2js.dart'
- show isRedirectingFactory, isRedirectingFactoryField;
+ show isRedirectingFactoryField;
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/type_environment.dart' as ir;
@@ -368,7 +368,7 @@
}
var name = member.name.text;
if (member.kind == ir.ProcedureKind.Factory) {
- if (isRedirectingFactory(member)) {
+ if (member.isRedirectingFactory) {
// Don't include redirecting factories.
return;
}
diff --git a/pkg/compiler/test/analyses/analysis_helper.dart b/pkg/compiler/test/analyses/analysis_helper.dart
index 0d427c6..763818b 100644
--- a/pkg/compiler/test/analyses/analysis_helper.dart
+++ b/pkg/compiler/test/analyses/analysis_helper.dart
@@ -19,7 +19,7 @@
import 'package:expect/expect.dart';
import 'package:front_end/src/api_prototype/constant_evaluator.dart' as ir;
import 'package:front_end/src/api_unstable/dart2js.dart'
- show isRedirectingFactory, isRedirectingFactoryField, relativizeUri;
+ show isRedirectingFactoryField, relativizeUri;
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/class_hierarchy.dart' as ir;
import 'package:kernel/core_types.dart' as ir;
@@ -98,7 +98,7 @@
@override
Null visitProcedure(ir.Procedure node) {
- if (node.kind == ir.ProcedureKind.Factory && isRedirectingFactory(node)) {
+ if (node.kind == ir.ProcedureKind.Factory && node.isRedirectingFactory) {
// Don't visit redirecting factories.
return;
}
diff --git a/pkg/front_end/lib/src/api_unstable/dart2js.dart b/pkg/front_end/lib/src/api_unstable/dart2js.dart
index 357b21f..74fd203 100644
--- a/pkg/front_end/lib/src/api_unstable/dart2js.dart
+++ b/pkg/front_end/lib/src/api_unstable/dart2js.dart
@@ -10,12 +10,8 @@
import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
-import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show StringToken;
-
import 'package:kernel/kernel.dart' show Component;
-import 'package:kernel/ast.dart' as ir;
-
import 'package:kernel/target/targets.dart' show Target;
import '../api_prototype/compiler_options.dart'
@@ -126,12 +122,6 @@
export 'compiler_state.dart' show InitializedCompilerState;
-void clearStringTokenCanonicalizer() {
- // TODO(ahe): We should be able to remove this. Fasta should take care of
- // clearing the cache when.
- StringToken.canonicalizer.clear();
-}
-
InitializedCompilerState initializeCompiler(
InitializedCompilerState? oldState,
Target target,
@@ -213,9 +203,3 @@
options.fileSystem = const NullFileSystem();
return compilerResult?.component;
}
-
-/// Desugar API to determine whether [member] is a redirecting factory
-/// constructor.
-// TODO(sigmund): Delete this API once `member.isRedirectingFactory`
-// is implemented correctly for patch files (Issue #33495).
-bool isRedirectingFactory(ir.Procedure member) => member.isRedirectingFactory;
diff --git a/pkg/front_end/lib/src/fasta/kernel/macro.dart b/pkg/front_end/lib/src/fasta/kernel/macro.dart
index 1faf2da..c14a5cd 100644
--- a/pkg/front_end/lib/src/fasta/kernel/macro.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/macro.dart
@@ -205,6 +205,8 @@
macro.ResolvedIdentifier _resolveIdentifier(macro.Identifier identifier) {
if (identifier is _IdentifierImpl) {
MemberBuilder? memberBuilder = identifier.memberBuilder;
+ TypeBuilder? typeBuilder = identifier.typeBuilder;
+ FormalParameterBuilder? parameterBuilder = identifier.parameterBuilder;
if (memberBuilder != null) {
Uri? uri;
String? staticScope;
@@ -225,9 +227,9 @@
name: identifier.name,
staticScope: staticScope,
uri: uri);
- } else {
+ } else if (typeBuilder != null) {
TypeDeclarationBuilder typeDeclarationBuilder =
- identifier.typeBuilder!.declaration!;
+ typeBuilder.declaration!;
Uri? uri;
if (typeDeclarationBuilder is ClassBuilder) {
uri = typeDeclarationBuilder.library.importUri;
@@ -239,6 +241,14 @@
name: identifier.name,
staticScope: null,
uri: uri);
+ } else if (parameterBuilder != null) {
+ return new macro.ResolvedIdentifier(
+ kind: macro.IdentifierKind.local,
+ name: identifier.name,
+ staticScope: null,
+ uri: null);
+ } else {
+ throw new StateError('Unable to resolve identifier $identifier');
}
} else {
// TODO(johnniwinther): Use [_IdentifierImpl] for all identifiers.
@@ -433,11 +443,16 @@
for (FormalParameterBuilder formal in formals) {
macro.TypeAnnotationImpl type =
computeTypeAnnotation(builder.library, formal.type);
+ macro.IdentifierImpl identifier =
+ new _IdentifierImpl.forParameterBuilder(
+ id: macro.RemoteInstance.uniqueId,
+ name: formal.name,
+ parameterBuilder: formal,
+ libraryBuilder: builder.library);
if (formal.isNamed) {
namedParameters.add(new macro.ParameterDeclarationImpl(
id: macro.RemoteInstance.uniqueId,
- identifier: new macro.IdentifierImpl(
- id: macro.RemoteInstance.uniqueId, name: formal.name),
+ identifier: identifier,
isRequired: formal.isNamedRequired,
isNamed: true,
type: type,
@@ -445,8 +460,7 @@
} else {
positionalParameters.add(new macro.ParameterDeclarationImpl(
id: macro.RemoteInstance.uniqueId,
- identifier: new macro.IdentifierImpl(
- id: macro.RemoteInstance.uniqueId, name: formal.name),
+ identifier: identifier,
isRequired: formal.isRequired,
isNamed: false,
type: type,
@@ -544,6 +558,7 @@
isGetter: builder.isGetter,
isOperator: builder.isOperator,
isSetter: builder.isSetter,
+ isStatic: builder.isStatic,
positionalParameters: parameters[0],
namedParameters: parameters[1],
returnType:
@@ -589,6 +604,7 @@
isExternal: builder.isExternal,
isFinal: builder.isFinal,
isLate: builder.isLate,
+ isStatic: builder.isStatic,
type: computeTypeAnnotation(builder.library, builder.type));
} else {
return new macro.VariableDeclarationImpl(
@@ -728,6 +744,7 @@
final MemberBuilder? memberBuilder;
final TypeBuilder? typeBuilder;
final LibraryBuilder libraryBuilder;
+ final FormalParameterBuilder? parameterBuilder;
_IdentifierImpl.forTypeBuilder({
required TypeBuilder this.typeBuilder,
@@ -736,6 +753,7 @@
required String name,
}) : typeDeclarationBuilder = null,
memberBuilder = null,
+ parameterBuilder = null,
super(id: id, name: name);
_IdentifierImpl.forTypeDeclarationBuilder({
@@ -745,6 +763,7 @@
required String name,
}) : typeBuilder = null,
memberBuilder = null,
+ parameterBuilder = null,
super(id: id, name: name);
_IdentifierImpl.forMemberBuilder(
@@ -753,8 +772,19 @@
required String name})
: typeBuilder = null,
typeDeclarationBuilder = null,
+ parameterBuilder = null,
libraryBuilder = memberBuilder.library,
super(id: id, name: name);
+
+ _IdentifierImpl.forParameterBuilder({
+ required FormalParameterBuilder this.parameterBuilder,
+ required this.libraryBuilder,
+ required int id,
+ required String name,
+ }) : typeBuilder = null,
+ typeDeclarationBuilder = null,
+ memberBuilder = null,
+ super(id: id, name: name);
}
class _StaticTypeImpl extends macro.StaticType {
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 143fcb8..fd09e4e 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -722,8 +722,18 @@
builder =
lookupConstructor(beginToken, name!) as SourceFunctionBuilderImpl;
} else {
- builder = lookupBuilder(beginToken, getOrSet, name as String)
- as SourceFunctionBuilderImpl;
+ Builder? memberBuilder =
+ lookupBuilder(beginToken, getOrSet, name as String);
+ if (currentClass?.isEnum == true &&
+ memberBuilder is SourceFieldBuilder &&
+ memberBuilder.name == "values") {
+ // This is the case of a method with the name 'values' declared in an
+ // Enum. In that case the method is replaced with the synthesized field
+ // in the outline building phase, and the error is reported there. At
+ // this point we skip the member.
+ return;
+ }
+ builder = memberBuilder as SourceFunctionBuilderImpl;
}
buildFunctionBody(
createFunctionListener(builder),
diff --git a/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart b/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
index 1eed920..6455359 100644
--- a/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_enum_builder.dart
@@ -27,6 +27,7 @@
import '../fasta_codes.dart'
show
LocatedMessage,
+ messageEnumContainsValuesDeclaration,
messageEnumEntryWithTypeArgumentsWithoutArguments,
messageEnumNonConstConstructor,
messageNoUnnamedConstructorInObject,
@@ -242,6 +243,20 @@
referencesFromIndexed.lookupSetterReference(valuesName);
}
+ Builder? customValuesDeclaration =
+ scope.lookupLocalMember("values", setter: false);
+ if (customValuesDeclaration != null) {
+ // Retrieve the earliest declaration for error reporting.
+ while (customValuesDeclaration?.next != null) {
+ customValuesDeclaration = customValuesDeclaration?.next;
+ }
+ parent.addProblem(
+ messageEnumContainsValuesDeclaration,
+ customValuesDeclaration!.charOffset,
+ customValuesDeclaration.fullNameForErrors.length,
+ fileUri);
+ }
+
SourceFieldBuilder valuesBuilder = new SourceFieldBuilder(
/* metadata = */ null,
listType,
@@ -338,7 +353,9 @@
final int startCharOffsetComputed =
metadata == null ? startCharOffset : metadata.first.charOffset;
scope.forEachLocalMember((name, member) {
- members[name] = member as MemberBuilder;
+ if (name != "values") {
+ members[name] = member as MemberBuilder;
+ }
});
scope.forEachLocalSetter((name, member) {
setters[name] = member;
diff --git a/pkg/front_end/lib/src/kernel_generator_impl.dart b/pkg/front_end/lib/src/kernel_generator_impl.dart
index 990e8ed..a20e586 100644
--- a/pkg/front_end/lib/src/kernel_generator_impl.dart
+++ b/pkg/front_end/lib/src/kernel_generator_impl.dart
@@ -6,6 +6,7 @@
library front_end.kernel_generator_impl;
import 'package:_fe_analyzer_shared/src/macros/bootstrap.dart';
+import 'package:_fe_analyzer_shared/src/macros/executor_shared/serialization.dart';
import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
@@ -296,9 +297,8 @@
Uri uri = _defaultDir.resolve('main.dart');
MemoryFileSystem fs = new MemoryFileSystem(_defaultDir);
- fs
- .entityForUri(uri)
- .writeAsStringSync(bootstrapMacroIsolate(macroDeclarations));
+ fs.entityForUri(uri).writeAsStringSync(bootstrapMacroIsolate(
+ macroDeclarations, SerializationMode.byteDataClient));
precompilationOptions..fileSystem = new HybridFileSystem(fs);
CompilerResult? compilerResult =
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 7be3d9c..644d13b 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -5,6 +5,8 @@
# Note that test/spelling: Status will have no effect. Spelling errors can
# always be fixed by either spelling correctly or updating the dictionary.
+EnumContainsValuesDeclaration/analyzerCode: Fail
+EnumContainsValuesDeclaration/example: Fail
AbstractClassConstructorTearOff/analyzerCode: Fail
AbstractClassInstantiation/example: Fail
AbstractExtensionField/analyzerCode: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 5fdadc6..8607ae0 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -5473,3 +5473,6 @@
EnumFactoryRedirectsToConstructor:
problemMessage: "Enum factory constructors can't redirect to generative constructors."
+
+EnumContainsValuesDeclaration:
+ problemMessage: "Enums can't contain declarations of members with the name 'values'."
diff --git a/pkg/front_end/test/desugar_test.dart b/pkg/front_end/test/desugar_test.dart
index 18342bb..33f3477 100644
--- a/pkg/front_end/test/desugar_test.dart
+++ b/pkg/front_end/test/desugar_test.dart
@@ -14,7 +14,6 @@
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
-import 'package:front_end/src/api_unstable/dart2js.dart' as api;
import 'package:front_end/src/compute_platform_binaries_location.dart';
import 'package:front_end/src/fasta/kernel/utils.dart' show serializeComponent;
import 'package:front_end/src/testing/compiler_common.dart';
@@ -64,7 +63,6 @@
.firstWhere((m) => m.name.text == constructorName) as ir.Procedure;
Expect.isTrue(
member.kind == ir.ProcedureKind.Factory, "$member is not a factory");
- Expect.isTrue(api.isRedirectingFactory(member));
Expect.isTrue(member.isRedirectingFactory);
}
diff --git a/pkg/front_end/test/macro_api_test.dart b/pkg/front_end/test/macro_api_test.dart
index f05b92b..0938f4e 100644
--- a/pkg/front_end/test/macro_api_test.dart
+++ b/pkg/front_end/test/macro_api_test.dart
@@ -4,6 +4,7 @@
import 'dart:io' show Directory, Platform;
+import 'package:_fe_analyzer_shared/src/macros/executor_shared/serialization.dart';
import 'package:_fe_analyzer_shared/src/macros/isolated_executor/isolated_executor.dart'
as isolatedExecutor;
import 'package:expect/expect.dart';
@@ -32,7 +33,7 @@
options.packagesFileUri = Platform.script.resolve(
'../../_fe_analyzer_shared/test/macros/api/package_config.json');
options.macroExecutorProvider = () async {
- return await isolatedExecutor.start();
+ return await isolatedExecutor.start(SerializationMode.byteDataServer);
};
options.precompiledMacroUris = {};
options.target = options.macroTarget = new VmTarget(new TargetFlags());
diff --git a/pkg/front_end/test/macro_application/macro_application_test.dart b/pkg/front_end/test/macro_application/macro_application_test.dart
index a6b4a4f..18e8fdf 100644
--- a/pkg/front_end/test/macro_application/macro_application_test.dart
+++ b/pkg/front_end/test/macro_application/macro_application_test.dart
@@ -6,6 +6,7 @@
import 'package:_fe_analyzer_shared/src/macros/api.dart';
import 'package:_fe_analyzer_shared/src/macros/executor.dart';
+import 'package:_fe_analyzer_shared/src/macros/executor_shared/serialization.dart';
import 'package:_fe_analyzer_shared/src/macros/isolated_executor/isolated_executor.dart'
as isolatedExecutor;
import 'package:_fe_analyzer_shared/src/testing/id.dart'
@@ -59,7 +60,7 @@
@override
void customizeCompilerOptions(CompilerOptions options, TestData testData) {
options.macroExecutorProvider = () async {
- return await isolatedExecutor.start();
+ return await isolatedExecutor.start(SerializationMode.byteDataServer);
};
options.precompiledMacroUris = precompiledMacroUris;
options.macroTarget = new VmTarget(new TargetFlags());
diff --git a/pkg/front_end/testcases/enhanced_enums/declared_values.dart b/pkg/front_end/testcases/enhanced_enums/declared_values.dart
new file mode 100644
index 0000000..a560ba7
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/declared_values.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2022, 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.
+
+enum E1 {
+ element;
+
+ static const List<E1> values = [E1.element]; // Error in E1.
+}
+
+enum E2 {
+ element;
+
+ int values = 42; // Error in E2.
+}
+
+enum E3 {
+ element;
+
+ static const List<E3> values = [E3.element]; // Error in E3.
+ int values = 42; // Duplicate.
+}
+
+enum E4 {
+ element;
+
+ static void set values(List<E4> x) {} // Ok.
+}
+
+enum E5 {
+ element;
+
+ static void set values(dynamic x) {} // Ok.
+}
+
+enum E6 {
+ element;
+
+ static void set values(Never x) {} // Error in E6.
+}
+
+enum E7 {
+ element;
+
+ void values() {} // Error in E7.
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/enhanced_enums/declared_values.dart.strong.expect b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.strong.expect
new file mode 100644
index 0000000..dde0f55
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.strong.expect
@@ -0,0 +1,138 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:8:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E1> values = [E1.element]; // Error in E1.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:14:7: Error: Enums can't contain declarations of members with the name 'values'.
+// int values = 42; // Error in E2.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:21:7: Error: 'values' is already declared in this scope.
+// int values = 42; // Duplicate.
+// ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Context: Previous declaration of 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:45:8: Error: Enums can't contain declarations of members with the name 'values'.
+// void values() {} // Error in E7.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:36:6: Error: The type 'List<E6>' of the getter 'E6.values' is not a subtype of the type 'Never' of the setter 'E6.values'.
+// - 'List' is from 'dart:core'.
+// - 'E6' is from 'pkg/front_end/testcases/enhanced_enums/declared_values.dart'.
+// enum E6 {
+// ^^^^^...
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:39:19: Context: This is the declaration of the setter 'E6.values'.
+// static void set values(Never x) {} // Error in E6.
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E1 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E1> values = #C4;
+ static const field self::E1 element = #C3;
+ const constructor •(core::int index, core::String name) → self::E1
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class E2 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E2> values = #C6;
+ static const field self::E2 element = #C5;
+ const constructor •(core::int index, core::String name) → self::E2
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class E3 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E3> values = #C8;
+ static const field self::E3 element = #C7;
+ const constructor •(core::int index, core::String name) → self::E3
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class E4 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E4> values = #C10;
+ static const field self::E4 element = #C9;
+ const constructor •(core::int index, core::String name) → self::E4
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E4.${this.{core::_Enum::_name}{core::String}}";
+ static set values(core::List<self::E4> x) → void {}
+}
+class E5 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E5> values = #C12;
+ static const field self::E5 element = #C11;
+ const constructor •(core::int index, core::String name) → self::E5
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E5.${this.{core::_Enum::_name}{core::String}}";
+ static set values(dynamic x) → void {}
+}
+class E6 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E6> values = #C14;
+ static const field self::E6 element = #C13;
+ const constructor •(core::int index, core::String name) → self::E6
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E6.${this.{core::_Enum::_name}{core::String}}";
+ static set values(Never x) → void {}
+}
+class E7 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E7> values = #C16;
+ static const field self::E7 element = #C15;
+ const constructor •(core::int index, core::String name) → self::E7
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = 0
+ #C2 = "element"
+ #C3 = self::E1 {index:#C1, _name:#C2}
+ #C4 = <self::E1>[#C3]
+ #C5 = self::E2 {index:#C1, _name:#C2}
+ #C6 = <self::E2>[#C5]
+ #C7 = self::E3 {index:#C1, _name:#C2}
+ #C8 = <self::E3>[#C7]
+ #C9 = self::E4 {index:#C1, _name:#C2}
+ #C10 = <self::E4>[#C9]
+ #C11 = self::E5 {index:#C1, _name:#C2}
+ #C12 = <self::E5>[#C11]
+ #C13 = self::E6 {index:#C1, _name:#C2}
+ #C14 = <self::E6>[#C13]
+ #C15 = self::E7 {index:#C1, _name:#C2}
+ #C16 = <self::E7>[#C15]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///declared_values.dart:
+- E1. (from org-dartlang-testcase:///declared_values.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///declared_values.dart:11:6)
+- E3. (from org-dartlang-testcase:///declared_values.dart:17:6)
+- E4. (from org-dartlang-testcase:///declared_values.dart:24:6)
+- E5. (from org-dartlang-testcase:///declared_values.dart:30:6)
+- E6. (from org-dartlang-testcase:///declared_values.dart:36:6)
+- E7. (from org-dartlang-testcase:///declared_values.dart:42:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/declared_values.dart.strong.transformed.expect b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.strong.transformed.expect
new file mode 100644
index 0000000..dde0f55
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.strong.transformed.expect
@@ -0,0 +1,138 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:8:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E1> values = [E1.element]; // Error in E1.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:14:7: Error: Enums can't contain declarations of members with the name 'values'.
+// int values = 42; // Error in E2.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:21:7: Error: 'values' is already declared in this scope.
+// int values = 42; // Duplicate.
+// ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Context: Previous declaration of 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:45:8: Error: Enums can't contain declarations of members with the name 'values'.
+// void values() {} // Error in E7.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:36:6: Error: The type 'List<E6>' of the getter 'E6.values' is not a subtype of the type 'Never' of the setter 'E6.values'.
+// - 'List' is from 'dart:core'.
+// - 'E6' is from 'pkg/front_end/testcases/enhanced_enums/declared_values.dart'.
+// enum E6 {
+// ^^^^^...
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:39:19: Context: This is the declaration of the setter 'E6.values'.
+// static void set values(Never x) {} // Error in E6.
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E1 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E1> values = #C4;
+ static const field self::E1 element = #C3;
+ const constructor •(core::int index, core::String name) → self::E1
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class E2 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E2> values = #C6;
+ static const field self::E2 element = #C5;
+ const constructor •(core::int index, core::String name) → self::E2
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class E3 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E3> values = #C8;
+ static const field self::E3 element = #C7;
+ const constructor •(core::int index, core::String name) → self::E3
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class E4 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E4> values = #C10;
+ static const field self::E4 element = #C9;
+ const constructor •(core::int index, core::String name) → self::E4
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E4.${this.{core::_Enum::_name}{core::String}}";
+ static set values(core::List<self::E4> x) → void {}
+}
+class E5 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E5> values = #C12;
+ static const field self::E5 element = #C11;
+ const constructor •(core::int index, core::String name) → self::E5
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E5.${this.{core::_Enum::_name}{core::String}}";
+ static set values(dynamic x) → void {}
+}
+class E6 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E6> values = #C14;
+ static const field self::E6 element = #C13;
+ const constructor •(core::int index, core::String name) → self::E6
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E6.${this.{core::_Enum::_name}{core::String}}";
+ static set values(Never x) → void {}
+}
+class E7 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E7> values = #C16;
+ static const field self::E7 element = #C15;
+ const constructor •(core::int index, core::String name) → self::E7
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = 0
+ #C2 = "element"
+ #C3 = self::E1 {index:#C1, _name:#C2}
+ #C4 = <self::E1>[#C3]
+ #C5 = self::E2 {index:#C1, _name:#C2}
+ #C6 = <self::E2>[#C5]
+ #C7 = self::E3 {index:#C1, _name:#C2}
+ #C8 = <self::E3>[#C7]
+ #C9 = self::E4 {index:#C1, _name:#C2}
+ #C10 = <self::E4>[#C9]
+ #C11 = self::E5 {index:#C1, _name:#C2}
+ #C12 = <self::E5>[#C11]
+ #C13 = self::E6 {index:#C1, _name:#C2}
+ #C14 = <self::E6>[#C13]
+ #C15 = self::E7 {index:#C1, _name:#C2}
+ #C16 = <self::E7>[#C15]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///declared_values.dart:
+- E1. (from org-dartlang-testcase:///declared_values.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///declared_values.dart:11:6)
+- E3. (from org-dartlang-testcase:///declared_values.dart:17:6)
+- E4. (from org-dartlang-testcase:///declared_values.dart:24:6)
+- E5. (from org-dartlang-testcase:///declared_values.dart:30:6)
+- E6. (from org-dartlang-testcase:///declared_values.dart:36:6)
+- E7. (from org-dartlang-testcase:///declared_values.dart:42:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/declared_values.dart.textual_outline.expect b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.textual_outline.expect
new file mode 100644
index 0000000..ee99a49
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+enum E1 { element; static const List<E1> values = [E1.element]; }
+enum E2 { element; int values = 42; }
+enum E3 { element; static const List<E3> values = [E3.element]; int values = 42; }
+enum E4 { element; static void set values(List<E4> x) {} }
+enum E5 { element; static void set values(dynamic x) {} }
+enum E6 { element; static void set values(Never x) {} }
+enum E7 { element; void values() {} }
+main() {}
diff --git a/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.expect b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.expect
new file mode 100644
index 0000000..3acc5b0
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.expect
@@ -0,0 +1,138 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:8:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E1> values = [E1.element]; // Error in E1.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:14:7: Error: Enums can't contain declarations of members with the name 'values'.
+// int values = 42; // Error in E2.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:21:7: Error: 'values' is already declared in this scope.
+// int values = 42; // Duplicate.
+// ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Context: Previous declaration of 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:45:8: Error: Enums can't contain declarations of members with the name 'values'.
+// void values() {} // Error in E7.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:36:6: Error: The type 'List<E6>' of the getter 'E6.values' is not a subtype of the type 'Never' of the setter 'E6.values'.
+// - 'List' is from 'dart:core'.
+// - 'E6' is from 'pkg/front_end/testcases/enhanced_enums/declared_values.dart'.
+// enum E6 {
+// ^^^^^...
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:39:19: Context: This is the declaration of the setter 'E6.values'.
+// static void set values(Never x) {} // Error in E6.
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E1 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E1> values = #C4;
+ static const field self::E1 element = #C3;
+ const constructor •(core::int index, core::String name) → self::E1
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class E2 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E2> values = #C6;
+ static const field self::E2 element = #C5;
+ const constructor •(core::int index, core::String name) → self::E2
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class E3 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E3> values = #C8;
+ static const field self::E3 element = #C7;
+ const constructor •(core::int index, core::String name) → self::E3
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class E4 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E4> values = #C10;
+ static const field self::E4 element = #C9;
+ const constructor •(core::int index, core::String name) → self::E4
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E4.${this.{core::_Enum::_name}{core::String}}";
+ static set values(core::List<self::E4> x) → void {}
+}
+class E5 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E5> values = #C12;
+ static const field self::E5 element = #C11;
+ const constructor •(core::int index, core::String name) → self::E5
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E5.${this.{core::_Enum::_name}{core::String}}";
+ static set values(dynamic x) → void {}
+}
+class E6 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E6> values = #C14;
+ static const field self::E6 element = #C13;
+ const constructor •(core::int index, core::String name) → self::E6
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E6.${this.{core::_Enum::_name}{core::String}}";
+ static set values(Never x) → void {}
+}
+class E7 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E7> values = #C16;
+ static const field self::E7 element = #C15;
+ const constructor •(core::int index, core::String name) → self::E7
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = 0
+ #C2 = "element"
+ #C3 = self::E1 {index:#C1, _name:#C2}
+ #C4 = <self::E1*>[#C3]
+ #C5 = self::E2 {index:#C1, _name:#C2}
+ #C6 = <self::E2*>[#C5]
+ #C7 = self::E3 {index:#C1, _name:#C2}
+ #C8 = <self::E3*>[#C7]
+ #C9 = self::E4 {index:#C1, _name:#C2}
+ #C10 = <self::E4*>[#C9]
+ #C11 = self::E5 {index:#C1, _name:#C2}
+ #C12 = <self::E5*>[#C11]
+ #C13 = self::E6 {index:#C1, _name:#C2}
+ #C14 = <self::E6*>[#C13]
+ #C15 = self::E7 {index:#C1, _name:#C2}
+ #C16 = <self::E7*>[#C15]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///declared_values.dart:
+- E1. (from org-dartlang-testcase:///declared_values.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///declared_values.dart:11:6)
+- E3. (from org-dartlang-testcase:///declared_values.dart:17:6)
+- E4. (from org-dartlang-testcase:///declared_values.dart:24:6)
+- E5. (from org-dartlang-testcase:///declared_values.dart:30:6)
+- E6. (from org-dartlang-testcase:///declared_values.dart:36:6)
+- E7. (from org-dartlang-testcase:///declared_values.dart:42:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.modular.expect b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.modular.expect
new file mode 100644
index 0000000..3acc5b0
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.modular.expect
@@ -0,0 +1,138 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:8:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E1> values = [E1.element]; // Error in E1.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:14:7: Error: Enums can't contain declarations of members with the name 'values'.
+// int values = 42; // Error in E2.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:21:7: Error: 'values' is already declared in this scope.
+// int values = 42; // Duplicate.
+// ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Context: Previous declaration of 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:45:8: Error: Enums can't contain declarations of members with the name 'values'.
+// void values() {} // Error in E7.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:36:6: Error: The type 'List<E6>' of the getter 'E6.values' is not a subtype of the type 'Never' of the setter 'E6.values'.
+// - 'List' is from 'dart:core'.
+// - 'E6' is from 'pkg/front_end/testcases/enhanced_enums/declared_values.dart'.
+// enum E6 {
+// ^^^^^...
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:39:19: Context: This is the declaration of the setter 'E6.values'.
+// static void set values(Never x) {} // Error in E6.
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E1 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E1> values = #C4;
+ static const field self::E1 element = #C3;
+ const constructor •(core::int index, core::String name) → self::E1
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class E2 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E2> values = #C6;
+ static const field self::E2 element = #C5;
+ const constructor •(core::int index, core::String name) → self::E2
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class E3 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E3> values = #C8;
+ static const field self::E3 element = #C7;
+ const constructor •(core::int index, core::String name) → self::E3
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class E4 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E4> values = #C10;
+ static const field self::E4 element = #C9;
+ const constructor •(core::int index, core::String name) → self::E4
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E4.${this.{core::_Enum::_name}{core::String}}";
+ static set values(core::List<self::E4> x) → void {}
+}
+class E5 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E5> values = #C12;
+ static const field self::E5 element = #C11;
+ const constructor •(core::int index, core::String name) → self::E5
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E5.${this.{core::_Enum::_name}{core::String}}";
+ static set values(dynamic x) → void {}
+}
+class E6 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E6> values = #C14;
+ static const field self::E6 element = #C13;
+ const constructor •(core::int index, core::String name) → self::E6
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E6.${this.{core::_Enum::_name}{core::String}}";
+ static set values(Never x) → void {}
+}
+class E7 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E7> values = #C16;
+ static const field self::E7 element = #C15;
+ const constructor •(core::int index, core::String name) → self::E7
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = 0
+ #C2 = "element"
+ #C3 = self::E1 {index:#C1, _name:#C2}
+ #C4 = <self::E1*>[#C3]
+ #C5 = self::E2 {index:#C1, _name:#C2}
+ #C6 = <self::E2*>[#C5]
+ #C7 = self::E3 {index:#C1, _name:#C2}
+ #C8 = <self::E3*>[#C7]
+ #C9 = self::E4 {index:#C1, _name:#C2}
+ #C10 = <self::E4*>[#C9]
+ #C11 = self::E5 {index:#C1, _name:#C2}
+ #C12 = <self::E5*>[#C11]
+ #C13 = self::E6 {index:#C1, _name:#C2}
+ #C14 = <self::E6*>[#C13]
+ #C15 = self::E7 {index:#C1, _name:#C2}
+ #C16 = <self::E7*>[#C15]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///declared_values.dart:
+- E1. (from org-dartlang-testcase:///declared_values.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///declared_values.dart:11:6)
+- E3. (from org-dartlang-testcase:///declared_values.dart:17:6)
+- E4. (from org-dartlang-testcase:///declared_values.dart:24:6)
+- E5. (from org-dartlang-testcase:///declared_values.dart:30:6)
+- E6. (from org-dartlang-testcase:///declared_values.dart:36:6)
+- E7. (from org-dartlang-testcase:///declared_values.dart:42:6)
diff --git a/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.outline.expect b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.outline.expect
new file mode 100644
index 0000000..535787e
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.outline.expect
@@ -0,0 +1,128 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:8:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E1> values = [E1.element]; // Error in E1.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:14:7: Error: Enums can't contain declarations of members with the name 'values'.
+// int values = 42; // Error in E2.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:21:7: Error: 'values' is already declared in this scope.
+// int values = 42; // Duplicate.
+// ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Context: Previous declaration of 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:45:8: Error: Enums can't contain declarations of members with the name 'values'.
+// void values() {} // Error in E7.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:36:6: Error: The type 'List<E6>' of the getter 'E6.values' is not a subtype of the type 'Never' of the setter 'E6.values'.
+// - 'List' is from 'dart:core'.
+// - 'E6' is from 'pkg/front_end/testcases/enhanced_enums/declared_values.dart'.
+// enum E6 {
+// ^^^^^...
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:39:19: Context: This is the declaration of the setter 'E6.values'.
+// static void set values(Never x) {} // Error in E6.
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E1 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E1> values = const <self::E1>[self::E1::element];
+ static const field self::E1 element = const self::E1::•(0, "element");
+ const constructor •(core::int index, core::String name) → self::E1
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class E2 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E2> values = const <self::E2>[self::E2::element];
+ static const field self::E2 element = const self::E2::•(0, "element");
+ const constructor •(core::int index, core::String name) → self::E2
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class E3 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E3> values = const <self::E3>[self::E3::element];
+ static const field self::E3 element = const self::E3::•(0, "element");
+ const constructor •(core::int index, core::String name) → self::E3
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class E4 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E4> values = const <self::E4>[self::E4::element];
+ static const field self::E4 element = const self::E4::•(0, "element");
+ const constructor •(core::int index, core::String name) → self::E4
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E4.${this.{core::_Enum::_name}{core::String}}";
+ static set values(core::List<self::E4> x) → void
+ ;
+}
+class E5 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E5> values = const <self::E5>[self::E5::element];
+ static const field self::E5 element = const self::E5::•(0, "element");
+ const constructor •(core::int index, core::String name) → self::E5
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E5.${this.{core::_Enum::_name}{core::String}}";
+ static set values(dynamic x) → void
+ ;
+}
+class E6 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E6> values = const <self::E6>[self::E6::element];
+ static const field self::E6 element = const self::E6::•(0, "element");
+ const constructor •(core::int index, core::String name) → self::E6
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E6.${this.{core::_Enum::_name}{core::String}}";
+ static set values(Never x) → void
+ ;
+}
+class E7 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E7> values = const <self::E7>[self::E7::element];
+ static const field self::E7 element = const self::E7::•(0, "element");
+ const constructor •(core::int index, core::String name) → self::E7
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic
+ ;
+
+
+Extra constant evaluation status:
+Evaluated: ListLiteral @ org-dartlang-testcase:///declared_values.dart:5:6 -> ListConstant(const <E1*>[const E1{_Enum.index: 0, _Enum._name: "element"}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///declared_values.dart:6:3 -> InstanceConstant(const E1{_Enum.index: 0, _Enum._name: "element"})
+Evaluated: ListLiteral @ org-dartlang-testcase:///declared_values.dart:11:6 -> ListConstant(const <E2*>[const E2{_Enum.index: 0, _Enum._name: "element"}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///declared_values.dart:12:3 -> InstanceConstant(const E2{_Enum.index: 0, _Enum._name: "element"})
+Evaluated: ListLiteral @ org-dartlang-testcase:///declared_values.dart:17:6 -> ListConstant(const <E3*>[const E3{_Enum.index: 0, _Enum._name: "element"}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///declared_values.dart:18:3 -> InstanceConstant(const E3{_Enum.index: 0, _Enum._name: "element"})
+Evaluated: ListLiteral @ org-dartlang-testcase:///declared_values.dart:24:6 -> ListConstant(const <E4*>[const E4{_Enum.index: 0, _Enum._name: "element"}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///declared_values.dart:25:3 -> InstanceConstant(const E4{_Enum.index: 0, _Enum._name: "element"})
+Evaluated: ListLiteral @ org-dartlang-testcase:///declared_values.dart:30:6 -> ListConstant(const <E5*>[const E5{_Enum.index: 0, _Enum._name: "element"}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///declared_values.dart:31:3 -> InstanceConstant(const E5{_Enum.index: 0, _Enum._name: "element"})
+Evaluated: ListLiteral @ org-dartlang-testcase:///declared_values.dart:36:6 -> ListConstant(const <E6*>[const E6{_Enum.index: 0, _Enum._name: "element"}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///declared_values.dart:37:3 -> InstanceConstant(const E6{_Enum.index: 0, _Enum._name: "element"})
+Evaluated: ListLiteral @ org-dartlang-testcase:///declared_values.dart:42:6 -> ListConstant(const <E7*>[const E7{_Enum.index: 0, _Enum._name: "element"}])
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///declared_values.dart:43:3 -> InstanceConstant(const E7{_Enum.index: 0, _Enum._name: "element"})
+Extra constant evaluation: evaluated: 49, effectively constant: 14
diff --git a/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.transformed.expect b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.transformed.expect
new file mode 100644
index 0000000..3acc5b0
--- /dev/null
+++ b/pkg/front_end/testcases/enhanced_enums/declared_values.dart.weak.transformed.expect
@@ -0,0 +1,138 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:8:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E1> values = [E1.element]; // Error in E1.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:14:7: Error: Enums can't contain declarations of members with the name 'values'.
+// int values = 42; // Error in E2.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:21:7: Error: 'values' is already declared in this scope.
+// int values = 42; // Duplicate.
+// ^^^^^^
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Context: Previous declaration of 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:20:25: Error: Enums can't contain declarations of members with the name 'values'.
+// static const List<E3> values = [E3.element]; // Error in E3.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:45:8: Error: Enums can't contain declarations of members with the name 'values'.
+// void values() {} // Error in E7.
+// ^^^^^^
+//
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:36:6: Error: The type 'List<E6>' of the getter 'E6.values' is not a subtype of the type 'Never' of the setter 'E6.values'.
+// - 'List' is from 'dart:core'.
+// - 'E6' is from 'pkg/front_end/testcases/enhanced_enums/declared_values.dart'.
+// enum E6 {
+// ^^^^^...
+// pkg/front_end/testcases/enhanced_enums/declared_values.dart:39:19: Context: This is the declaration of the setter 'E6.values'.
+// static void set values(Never x) {} // Error in E6.
+// ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class E1 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E1> values = #C4;
+ static const field self::E1 element = #C3;
+ const constructor •(core::int index, core::String name) → self::E1
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E1.${this.{core::_Enum::_name}{core::String}}";
+}
+class E2 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E2> values = #C6;
+ static const field self::E2 element = #C5;
+ const constructor •(core::int index, core::String name) → self::E2
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E2.${this.{core::_Enum::_name}{core::String}}";
+}
+class E3 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E3> values = #C8;
+ static const field self::E3 element = #C7;
+ const constructor •(core::int index, core::String name) → self::E3
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E3.${this.{core::_Enum::_name}{core::String}}";
+}
+class E4 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E4> values = #C10;
+ static const field self::E4 element = #C9;
+ const constructor •(core::int index, core::String name) → self::E4
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E4.${this.{core::_Enum::_name}{core::String}}";
+ static set values(core::List<self::E4> x) → void {}
+}
+class E5 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E5> values = #C12;
+ static const field self::E5 element = #C11;
+ const constructor •(core::int index, core::String name) → self::E5
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E5.${this.{core::_Enum::_name}{core::String}}";
+ static set values(dynamic x) → void {}
+}
+class E6 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E6> values = #C14;
+ static const field self::E6 element = #C13;
+ const constructor •(core::int index, core::String name) → self::E6
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E6.${this.{core::_Enum::_name}{core::String}}";
+ static set values(Never x) → void {}
+}
+class E7 extends core::_Enum /*isEnum*/ {
+ static const field core::List<self::E7> values = #C16;
+ static const field self::E7 element = #C15;
+ const constructor •(core::int index, core::String name) → self::E7
+ : super core::_Enum::•(index, name)
+ ;
+ method toString() → core::String
+ return "E7.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → dynamic {}
+
+constants {
+ #C1 = 0
+ #C2 = "element"
+ #C3 = self::E1 {index:#C1, _name:#C2}
+ #C4 = <self::E1*>[#C3]
+ #C5 = self::E2 {index:#C1, _name:#C2}
+ #C6 = <self::E2*>[#C5]
+ #C7 = self::E3 {index:#C1, _name:#C2}
+ #C8 = <self::E3*>[#C7]
+ #C9 = self::E4 {index:#C1, _name:#C2}
+ #C10 = <self::E4*>[#C9]
+ #C11 = self::E5 {index:#C1, _name:#C2}
+ #C12 = <self::E5*>[#C11]
+ #C13 = self::E6 {index:#C1, _name:#C2}
+ #C14 = <self::E6*>[#C13]
+ #C15 = self::E7 {index:#C1, _name:#C2}
+ #C16 = <self::E7*>[#C15]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///declared_values.dart:
+- E1. (from org-dartlang-testcase:///declared_values.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- E2. (from org-dartlang-testcase:///declared_values.dart:11:6)
+- E3. (from org-dartlang-testcase:///declared_values.dart:17:6)
+- E4. (from org-dartlang-testcase:///declared_values.dart:24:6)
+- E5. (from org-dartlang-testcase:///declared_values.dart:30:6)
+- E6. (from org-dartlang-testcase:///declared_values.dart:36:6)
+- E7. (from org-dartlang-testcase:///declared_values.dart:42:6)
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index 3788a0f..9bd8949 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -30,6 +30,7 @@
dart2js/late_statics: FormatterCrash
enhanced_enums/conflicting_elements: FormatterCrash
enhanced_enums/constructor_calls: FormatterCrash
+enhanced_enums/declared_values: FormatterCrash
enhanced_enums/entries_with_type_arguments: FormatterCrash
enhanced_enums/enum_as_supertype: FormatterCrash
enhanced_enums/inference_in_constructor_parameters: FormatterCrash
diff --git a/tests/language/call/implicit_tearoff_exceptions_test.dart b/tests/language/call/implicit_tearoff_exceptions_test.dart
new file mode 100644
index 0000000..82336a1
--- /dev/null
+++ b/tests/language/call/implicit_tearoff_exceptions_test.dart
@@ -0,0 +1,123 @@
+// Copyright (c) 2022, 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.
+
+// There are a few circumstances where implicit tear-off of `call` methods does
+// not occur; this test exercises the user-visible static analysis behaviors
+// arising from those circumstances.
+
+// NOTICE: This test checks the currently implemented behavior, even though the
+// implemented behavior does not match the language specification. Until an
+// official decision has been made about whether to change the implementation to
+// match the specification, or vice versa, this regression test is intended to
+// protect against inadvertent implementation changes.
+
+// A note on how the tests work: in several places we use the pattern
+// `context<C>(b ? d : (E..expectStaticType<Exactly<T>>()))` (where `b` has type
+// `bool` and `d` has type `dynamic`). This pattern ensures that `E` will be
+// type analyzed with a context of `C`, and tests that the resulting expression
+// has a type of `T`. However, the presence of `b ? d :` at the beginning
+// ensures that the overall expression has type `dynamic`, so no assignability
+// error will occur if types `C` and `T` are different.
+
+import "package:expect/expect.dart";
+
+import '../static_type_helper.dart';
+
+class A {}
+
+class C extends A {
+ void call() {}
+ void m() {}
+}
+
+// These are top level getters rather than local variables to avoid triggering
+// flow analysis.
+bool get bTrue => true;
+bool get bFalse => false;
+
+void testCascadeTarget() {
+ C c = C();
+ // Even though the subexpression `c` has type `C` and context `void
+ // Function()`, we don't tear off `.call` for subexpressions that are the
+ // target of a cascade; instead, we tear-off `.call` on the full cascade
+ // expression. So `c..m()` is equivalent to `(c..m()).call` (which is valid)
+ // rather than `(c.call)..m()` (which is not).
+ context<void Function()>(c..m());
+
+ // Same as above, but confirm that extra parens around `c` don't change the
+ // behavior.
+ context<void Function()>((c)..m());
+ context<void Function()>(((c))..m());
+}
+
+void testConditional() {
+ A a = A();
+ C c = C();
+ dynamic d = null;
+ // Even though the subexpression `c` has type `C` and context `void
+ // Function()`, we don't tear off `.call` for the `then` or `else`
+ // subexpressions of a conditional expression; instead, we tear off `.call`
+ // for the conditional expression as a whole (if appropriate). So, in
+ // `(bTrue ? c : a)..expectStaticType<...>()`, no implicit tearoff of `c`
+ // occurs, and the subexpression `bTrue ? c : a` gets assigned a static type
+ // of `A`.
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bTrue ? c : a)..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bFalse ? a : c)..expectStaticType<Exactly<A>>())));
+
+ // Same as above, but confirm that extra parens around `c` don't change the
+ // behavior.
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bTrue ? (c) : a)..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bFalse ? a : (c))..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bTrue ? ((c)) : a)..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bFalse ? a : ((c)))..expectStaticType<Exactly<A>>())));
+}
+
+void testIfNull() {
+ A a = A();
+ A? aq = null;
+ C c = C();
+ dynamic d = null;
+ // Even though the subexpression `c` has type `C` and context `void
+ // Function()?`, we don't tear off `.call` for the LHS of a `??` expression;
+ // instead, we tear off `.call` for the `??` expression as a whole (if
+ // appropriate). So, in
+ // `(c ?? a)..expectStaticType<...>()`, no implicit tearoff of `c` occurs, and
+ // the subexpression `c ?? a` gets assigned a static type of `A`.
+ Expect.throws(() => context<void Function()>(bFalse
+ ? d
+ : ((c ?? a) // ignore: dead_null_aware_expression
+ ..expectStaticType<Exactly<A>>())));
+
+ // In `(aq ?? c)..expectStaticType<...>()`, the situation is similar, but the
+ // context for `c` is (non-nullable) `void Function()`.
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((aq ?? c)..expectStaticType<Exactly<A>>())));
+
+ // Same as above, but confirm that extra parens around `c` don't change the
+ // behavior.
+ Expect.throws(() => context<void Function()>(bFalse
+ ? d
+ : (((c) ?? a) // ignore: dead_null_aware_expression
+ ..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((aq ?? (c))..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(bFalse
+ ? d
+ : ((((c)) ?? a) // ignore: dead_null_aware_expression
+ ..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((aq ?? ((c)))..expectStaticType<Exactly<A>>())));
+}
+
+main() {
+ testCascadeTarget();
+ testConditional();
+ testIfNull();
+}
diff --git a/tests/language/call/implicit_tearoff_test.dart b/tests/language/call/implicit_tearoff_test.dart
new file mode 100644
index 0000000..361f7e1
--- /dev/null
+++ b/tests/language/call/implicit_tearoff_test.dart
@@ -0,0 +1,177 @@
+// Copyright (c) 2022, 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.
+
+// This test exercises all the grammar constructs for which implicit tear-off of
+// `call` methods should occur.
+
+// NOTICE: This test checks the currently implemented behavior, even though the
+// implemented behavior does not match the language specification. Until an
+// official decision has been made about whether to change the implementation to
+// match the specification, or vice versa, this regression test is intended to
+// protect against inadvertent implementation changes.
+
+import '../static_type_helper.dart';
+
+class B {}
+
+class C extends B {
+ void call() {}
+ void m() {}
+ void testThisExpression() {
+ context<void Function()>(this);
+ }
+}
+
+class D {
+ C operator +(other) => C();
+ C operator -() => C();
+ C instanceMethod() => C();
+ static C staticMethod() => C();
+ C get instanceGetter => C();
+}
+
+C topLevelMethod() => C();
+
+// These are top level getters rather than local variables to avoid triggering
+// flow analysis.
+bool get bTrue => true;
+bool get bFalse => false;
+
+void testAsExpression() {
+ dynamic d = C();
+ context<void Function()>(d as C);
+}
+
+void testAssignmentExpression() {
+ B b = B(); // ignore: unused_local_variable
+ context<void Function()>(b = C());
+}
+
+Future<void> testAwaitExpression() async {
+ Future<C> fc = Future.value(C());
+ context<void Function()>(await fc);
+}
+
+void testBinaryExpression() {
+ D d = D();
+ context<void Function()>(d + d);
+}
+
+void testCascadeExpression() {
+ // Note: we don't apply implicit `.call` tear-offs to the *target* of a
+ // cascade, but we do apply them to the cascade expression as a whole, so
+ // `c..m()` is equivalent to `(c..m()).call`.
+ C c = C();
+ context<void Function()>(c..m());
+}
+
+void testConditionalExpression() {
+ // Note: we know from `implicit_tearoff_exceptions_test.dart` that the two
+ // branches of the conditional expression are *not* subject to implicit
+ // `.call` tearoff, so the `.call` tearoff in this case is applied to the
+ // whole conditional expression. In other words, `b ? c : c` desugars to
+ // `(b ? c : c).call` rather than `(b ? c.call : c.call)`.
+ C c = C();
+ context<void Function()>(bFalse ? c : c);
+ context<void Function()>(bTrue ? c : c);
+}
+
+void testFunctionExpressionInvocation() {
+ C c = C();
+ context<void Function()>((() => c)());
+}
+
+void testFunctionInvocationLocal() {
+ C localFunction() => C();
+ context<void Function()>(localFunction());
+}
+
+void testFunctionInvocationStatic() {
+ context<void Function()>(D.staticMethod());
+}
+
+void testFunctionInvocationTopLevel() {
+ context<void Function()>(topLevelMethod());
+}
+
+void testIfNullExpression() {
+ C? c1 = bTrue ? C() : null;
+ C c2 = C();
+ context<void Function()>(c1 ?? c2);
+ c1 = null;
+ context<void Function()>(c1 ?? c2);
+}
+
+void testIndexExpression() {
+ List<C> l = [C()];
+ context<void Function()>(l[0]);
+}
+
+void testInstanceCreationExpressionExplicit() {
+ context<void Function()>(new C());
+}
+
+void testInstanceCreationExpressionImplicit() {
+ context<void Function()>(C());
+}
+
+void testInstanceGetGeneral() {
+ D Function() dFunction = () => D();
+ context<void Function()>(dFunction().instanceGetter);
+}
+
+void testInstanceGetViaPrefixedIdentifier() {
+ D d = D();
+ context<void Function()>(d.instanceGetter);
+}
+
+void testMethodInvocation() {
+ context<void Function()>(D().instanceMethod());
+}
+
+void testNullCheckExpression() {
+ C? c = bTrue ? C() : null;
+ context<void Function()>(c!);
+}
+
+void testParenthesizedExpression() {
+ C c = C();
+ context<void Function()>((c));
+}
+
+void testUnaryMinusExpression() {
+ D d = D();
+ context<void Function()>(-d);
+}
+
+extension on C {
+ void testThisExpressionExtension() {
+ context<void Function()>(this);
+ }
+}
+
+main() async {
+ testAsExpression();
+ testAssignmentExpression();
+ await testAwaitExpression();
+ testBinaryExpression();
+ testCascadeExpression();
+ testConditionalExpression();
+ testFunctionExpressionInvocation();
+ testFunctionInvocationLocal();
+ testFunctionInvocationStatic();
+ testFunctionInvocationTopLevel();
+ testIfNullExpression();
+ testIndexExpression();
+ testInstanceCreationExpressionExplicit();
+ testInstanceCreationExpressionImplicit();
+ testInstanceGetGeneral();
+ testInstanceGetViaPrefixedIdentifier();
+ testMethodInvocation();
+ testNullCheckExpression();
+ testParenthesizedExpression();
+ testUnaryMinusExpression();
+ C().testThisExpression();
+ C().testThisExpressionExtension();
+}
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 7b214ff..1c44dac 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -13,6 +13,7 @@
closure/minify_closure_variable_collision_test: SkipByDesign # Regression test for dart2js
[ $builder_tag == dart2js_production && $compiler == dart2js ]
+call/implicit_tearoff_exceptions_test: SkipByDesign # No argument type checks in production mode, issue 45528
control_flow_collections/for_non_bool_condition_test: Crash # Issue 36442
regress/regress45428_test: SkipByDesign # No argument type checks in production mode, issue 45528
diff --git a/tests/language_2/call/implicit_tearoff_exceptions_test.dart b/tests/language_2/call/implicit_tearoff_exceptions_test.dart
new file mode 100644
index 0000000..5ff09e9
--- /dev/null
+++ b/tests/language_2/call/implicit_tearoff_exceptions_test.dart
@@ -0,0 +1,116 @@
+// Copyright (c) 2022, 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.
+
+// There are a few circumstances where implicit tear-off of `call` methods does
+// not occur; this test exercises the user-visible static analysis behaviors
+// arising from those circumstances.
+
+// NOTICE: This test checks the currently implemented behavior, even though the
+// implemented behavior does not match the language specification. Until an
+// official decision has been made about whether to change the implementation to
+// match the specification, or vice versa, this regression test is intended to
+// protect against inadvertent implementation changes.
+
+// A note on how the tests work: in several places we use the pattern
+// `context<C>(b ? d : (E..expectStaticType<Exactly<T>>()))` (where `b` has type
+// `bool` and `d` has type `dynamic`). This pattern ensures that `E` will be
+// type analyzed with a context of `C`, and tests that the resulting expression
+// has a type of `T`. However, the presence of `b ? d :` at the beginning
+// ensures that the overall expression has type `dynamic`, so no assignability
+// error will occur if types `C` and `T` are different.
+
+// @dart = 2.9
+
+import "package:expect/expect.dart";
+
+import '../static_type_helper.dart';
+
+class A {}
+
+class C extends A {
+ void call() {}
+ void m() {}
+}
+
+// These are top level getters rather than local variables to avoid triggering
+// flow analysis.
+bool get bTrue => true;
+bool get bFalse => false;
+
+void testCascadeTarget() {
+ C c = C();
+ // Even though the subexpression `c` has type `C` and context `void
+ // Function()`, we don't tear off `.call` for subexpressions that are the
+ // target of a cascade; instead, we tear-off `.call` on the full cascade
+ // expression. So `c..m()` is equivalent to `(c..m()).call` (which is valid)
+ // rather than `(c.call)..m()` (which is not).
+ context<void Function()>(c..m());
+
+ // Same as above, but confirm that extra parens around `c` don't change the
+ // behavior.
+ context<void Function()>((c)..m());
+ context<void Function()>(((c))..m());
+}
+
+void testConditional() {
+ A a = A();
+ C c = C();
+ dynamic d = null;
+ // Even though the subexpression `c` has type `C` and context `void
+ // Function()`, we don't tear off `.call` for the `then` or `else`
+ // subexpressions of a conditional expression; instead, we tear off `.call`
+ // for the conditional expression as a whole (if appropriate). So, in
+ // `(bTrue ? c : a)..expectStaticType<...>()`, no implicit tearoff of `c`
+ // occurs, and the subexpression `bTrue ? c : a` gets assigned a static type
+ // of `A`.
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bTrue ? c : a)..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bFalse ? a : c)..expectStaticType<Exactly<A>>())));
+
+ // Same as above, but confirm that extra parens around `c` don't change the
+ // behavior.
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bTrue ? (c) : a)..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bFalse ? a : (c))..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bTrue ? ((c)) : a)..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((bFalse ? a : ((c)))..expectStaticType<Exactly<A>>())));
+}
+
+void testIfNull() {
+ A a = A();
+ A aq = null;
+ C c = C();
+ dynamic d = null;
+ // Even though the subexpression `c` has type `C` and context `void
+ // Function()`, we don't tear off `.call` for the LHS of a `??` expression;
+ // instead, we tear off `.call` for the `??` expression as a whole (if
+ // appropriate). So, in
+ // `(c ?? a)..expectStaticType<...>()`, no implicit tearoff of `c` occurs, and
+ // the subexpression `c ?? a` gets assigned a static type of `A`.
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((c ?? a)..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((aq ?? c)..expectStaticType<Exactly<A>>())));
+
+ // Same as above, but confirm that extra parens around `c` don't change the
+ // behavior.
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : (((c) ?? a)..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((aq ?? (c))..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((((c)) ?? a)..expectStaticType<Exactly<A>>())));
+ Expect.throws(() => context<void Function()>(
+ bFalse ? d : ((aq ?? ((c)))..expectStaticType<Exactly<A>>())));
+}
+
+main() {
+ testCascadeTarget();
+ testConditional();
+ testIfNull();
+}
diff --git a/tests/language_2/call/implicit_tearoff_test.dart b/tests/language_2/call/implicit_tearoff_test.dart
new file mode 100644
index 0000000..ec30ced
--- /dev/null
+++ b/tests/language_2/call/implicit_tearoff_test.dart
@@ -0,0 +1,173 @@
+// Copyright (c) 2022, 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.
+
+// This test exercises all the grammar constructs for which implicit tear-off of
+// `call` methods should occur.
+
+// NOTICE: This test checks the currently implemented behavior, even though the
+// implemented behavior does not match the language specification. Until an
+// official decision has been made about whether to change the implementation to
+// match the specification, or vice versa, this regression test is intended to
+// protect against inadvertent implementation changes.
+
+// @dart = 2.9
+
+import '../static_type_helper.dart';
+
+class B {}
+
+class C extends B {
+ void call() {}
+ void m() {}
+ void testThisExpression() {
+ context<void Function()>(this);
+ }
+}
+
+class D {
+ C operator +(other) => C();
+ C operator -() => C();
+ C instanceMethod() => C();
+ static C staticMethod() => C();
+ C get instanceGetter => C();
+}
+
+C topLevelMethod() => C();
+
+// These are top level getters rather than local variables to avoid triggering
+// flow analysis.
+bool get bTrue => true;
+bool get bFalse => false;
+
+void testAsExpression() {
+ dynamic d = C();
+ context<void Function()>(d as C);
+}
+
+void testAssignmentExpression() {
+ B b = B(); // ignore: unused_local_variable
+ context<void Function()>(b = C());
+}
+
+Future<void> testAwaitExpression() async {
+ Future<C> fc = Future.value(C());
+ context<void Function()>(await fc);
+}
+
+void testBinaryExpression() {
+ D d = D();
+ context<void Function()>(d + d);
+}
+
+void testCascadeExpression() {
+ // Note: we don't apply implicit `.call` tear-offs to the *target* of a
+ // cascade, but we do apply them to the cascade expression as a whole, so
+ // `c..m()` is equivalent to `(c..m()).call`.
+ C c = C();
+ context<void Function()>(c..m());
+}
+
+void testConditionalExpression() {
+ // Note: we know from `implicit_tearoff_exceptions_test.dart` that the two
+ // branches of the conditional expression are *not* subject to implicit
+ // `.call` tearoff, so the `.call` tearoff in this case is applied to the
+ // whole conditional expression. In other words, `b ? c : c` desugars to
+ // `(b ? c : c).call` rather than `(b ? c.call : c.call)`.
+ C c = C();
+ context<void Function()>(bFalse ? c : c);
+ context<void Function()>(bTrue ? c : c);
+}
+
+void testFunctionExpressionInvocation() {
+ C c = C();
+ context<void Function()>((() => c)());
+}
+
+void testFunctionInvocationLocal() {
+ C localFunction() => C();
+ context<void Function()>(localFunction());
+}
+
+void testFunctionInvocationStatic() {
+ context<void Function()>(D.staticMethod());
+}
+
+void testFunctionInvocationTopLevel() {
+ context<void Function()>(topLevelMethod());
+}
+
+void testIfNullExpression() {
+ C c1 = bTrue ? C() : null;
+ C c2 = C();
+ context<void Function()>(c1 ?? c2);
+ c1 = null;
+ context<void Function()>(c1 ?? c2);
+}
+
+void testIndexExpression() {
+ List<C> l = [C()];
+ context<void Function()>(l[0]);
+}
+
+void testInstanceCreationExpressionExplicit() {
+ context<void Function()>(new C());
+}
+
+void testInstanceCreationExpressionImplicit() {
+ context<void Function()>(C());
+}
+
+void testInstanceGetGeneral() {
+ D Function() dFunction = () => D();
+ context<void Function()>(dFunction().instanceGetter);
+}
+
+void testInstanceGetViaPrefixedIdentifier() {
+ D d = D();
+ context<void Function()>(d.instanceGetter);
+}
+
+void testMethodInvocation() {
+ context<void Function()>(D().instanceMethod());
+}
+
+void testParenthesizedExpression() {
+ C c = C();
+ context<void Function()>((c));
+}
+
+void testUnaryMinusExpression() {
+ D d = D();
+ context<void Function()>(-d);
+}
+
+extension on C {
+ void testThisExpressionExtension() {
+ context<void Function()>(this);
+ }
+}
+
+main() async {
+ testAsExpression();
+ testAssignmentExpression();
+ await testAwaitExpression();
+ testBinaryExpression();
+ testCascadeExpression();
+ testConditionalExpression();
+ testFunctionExpressionInvocation();
+ testFunctionInvocationLocal();
+ testFunctionInvocationStatic();
+ testFunctionInvocationTopLevel();
+ testIfNullExpression();
+ testIndexExpression();
+ testInstanceCreationExpressionExplicit();
+ testInstanceCreationExpressionImplicit();
+ testInstanceGetGeneral();
+ testInstanceGetViaPrefixedIdentifier();
+ testMethodInvocation();
+ testParenthesizedExpression();
+ testUnaryMinusExpression();
+ C().testThisExpression();
+ C().testThisExpressionExtension();
+}
diff --git a/tests/language_2/language_2_dart2js.status b/tests/language_2/language_2_dart2js.status
index 7b214ff..1c44dac 100644
--- a/tests/language_2/language_2_dart2js.status
+++ b/tests/language_2/language_2_dart2js.status
@@ -13,6 +13,7 @@
closure/minify_closure_variable_collision_test: SkipByDesign # Regression test for dart2js
[ $builder_tag == dart2js_production && $compiler == dart2js ]
+call/implicit_tearoff_exceptions_test: SkipByDesign # No argument type checks in production mode, issue 45528
control_flow_collections/for_non_bool_condition_test: Crash # Issue 36442
regress/regress45428_test: SkipByDesign # No argument type checks in production mode, issue 45528
diff --git a/tools/VERSION b/tools/VERSION
index f931023..25c6a12 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 17
PATCH 0
-PRERELEASE 110
+PRERELEASE 111
PRERELEASE_PATCH 0
\ No newline at end of file