Version 3.6.0-106.0.dev
Merge 7eef09cd6eccd60d66fc75a0435d2979385614d0 into dev
diff --git a/pkg/dart2wasm/lib/async.dart b/pkg/dart2wasm/lib/async.dart
index deeca32..55e4020 100644
--- a/pkg/dart2wasm/lib/async.dart
+++ b/pkg/dart2wasm/lib/async.dart
@@ -10,19 +10,78 @@
import 'code_generator.dart';
import 'state_machine.dart';
-class AsyncCodeGenerator extends StateMachineCodeGenerator {
+class AsyncCodeGenerator extends StateMachineEntryCodeGenerator {
AsyncCodeGenerator(super.translator, super.function, super.reference);
late final ClassInfo asyncSuspendStateInfo =
translator.classInfo[translator.asyncSuspendStateClass]!;
- // Note: These locals are only available in "inner" functions.
- w.Local get _suspendStateLocal => function.locals[0];
- w.Local get _awaitValueLocal => function.locals[1];
- w.Local get _pendingExceptionLocal => function.locals[2];
- w.Local get _pendingStackTraceLocal => function.locals[3];
+ @override
+ void generateOuter(
+ FunctionNode functionNode, Context? context, Source functionSource) {
+ final resumeFun = _defineInnerBodyFunction(functionNode);
- w.FunctionBuilder _defineBodyFunction(FunctionNode functionNode) =>
+ // Outer (wrapper) function creates async state, calls the inner function
+ // (which runs until first suspension point, i.e. `await`), and returns the
+ // completer's future.
+
+ // (1) Create async state.
+
+ final asyncStateLocal =
+ b.addLocal(w.RefType(asyncSuspendStateInfo.struct, nullable: false));
+
+ // AsyncResumeFun _resume
+ b.global_get(translator.makeFunctionRef(resumeFun));
+
+ // WasmStructRef? _context
+ if (context != null) {
+ assert(!context.isEmpty);
+ b.local_get(context.currentLocal);
+ } else {
+ b.ref_null(w.HeapType.struct);
+ }
+
+ // _AsyncCompleter _completer
+ types.makeType(this, functionNode.emittedValueType!);
+ call(translator.makeAsyncCompleter.reference);
+
+ // Allocate `_AsyncSuspendState`
+ call(translator.newAsyncSuspendState.reference);
+ b.local_set(asyncStateLocal);
+
+ // (2) Call inner function.
+ //
+ // Note: the inner function does not throw, so we don't need a `try` block
+ // here.
+
+ b.local_get(asyncStateLocal);
+ b.ref_null(translator.topInfo.struct); // await value
+ b.ref_null(translator.topInfo.struct); // error value
+ b.ref_null(translator.stackTraceInfo.repr.struct); // stack trace
+ b.call(resumeFun);
+ b.drop(); // drop null
+
+ // (3) Return the completer's future.
+
+ b.local_get(asyncStateLocal);
+ final completerFutureGetterType = translator
+ .signatureForDirectCall(translator.completerFuture.getterReference);
+ b.struct_get(
+ asyncSuspendStateInfo.struct, FieldIndex.asyncSuspendStateCompleter);
+ translator.convertType(
+ b,
+ asyncSuspendStateInfo.struct.fields[5].type.unpacked,
+ completerFutureGetterType.inputs[0]);
+ call(translator.completerFuture.getterReference);
+ b.return_();
+ b.end();
+
+ AsyncStateMachineCodeGenerator(translator, resumeFun, reference,
+ functionNode, functionSource, closures)
+ .generate();
+ }
+
+ w.FunctionBuilder _defineInnerBodyFunction(FunctionNode functionNode) =>
m.functions.define(
m.types.defineFunction([
asyncSuspendStateInfo.nonNullableType, // _AsyncSuspendState
@@ -37,6 +96,24 @@
translator.topInfo.nullableType
]),
"${function.functionName} inner");
+}
+
+class AsyncStateMachineCodeGenerator extends StateMachineCodeGenerator {
+ AsyncStateMachineCodeGenerator(
+ super.translator,
+ super.function,
+ super.reference,
+ super.functionNode,
+ super.functionSource,
+ super.closures);
+
+ late final ClassInfo asyncSuspendStateInfo =
+ translator.classInfo[translator.asyncSuspendStateClass]!;
+
+ w.Local get _suspendStateLocal => function.locals[0];
+ w.Local get _awaitValueLocal => function.locals[1];
+ w.Local get _pendingExceptionLocal => function.locals[2];
+ w.Local get _pendingStackTraceLocal => function.locals[3];
@override
void setSuspendStateCurrentException(void Function() emitValue) {
@@ -94,86 +171,9 @@
}
@override
- void generateFunctions(FunctionNode functionNode, Context? context) {
- final resumeFun = _defineBodyFunction(functionNode);
-
- _generateOuter(functionNode, context, resumeFun);
-
- // Forget about the outer function locals containing the type arguments,
- // so accesses to the type arguments in the inner function will fetch them
- // from the context.
- typeLocals.clear();
-
- _generateInner(functionNode, context, resumeFun);
- }
-
- void _generateOuter(
- FunctionNode functionNode, Context? context, w.BaseFunction resumeFun) {
- // Outer (wrapper) function creates async state, calls the inner function
- // (which runs until first suspension point, i.e. `await`), and returns the
- // completer's future.
-
- // (1) Create async state.
-
- final asyncStateLocal =
- b.addLocal(w.RefType(asyncSuspendStateInfo.struct, nullable: false));
-
- // AsyncResumeFun _resume
- b.global_get(translator.makeFunctionRef(resumeFun));
-
- // WasmStructRef? _context
- if (context != null) {
- assert(!context.isEmpty);
- b.local_get(context.currentLocal);
- } else {
- b.ref_null(w.HeapType.struct);
- }
-
- // _AsyncCompleter _completer
- types.makeType(this, functionNode.emittedValueType!);
- call(translator.makeAsyncCompleter.reference);
-
- // Allocate `_AsyncSuspendState`
- call(translator.newAsyncSuspendState.reference);
- b.local_set(asyncStateLocal);
-
- // (2) Call inner function.
- //
- // Note: the inner function does not throw, so we don't need a `try` block
- // here.
-
- b.local_get(asyncStateLocal);
- b.ref_null(translator.topInfo.struct); // await value
- b.ref_null(translator.topInfo.struct); // error value
- b.ref_null(translator.stackTraceInfo.repr.struct); // stack trace
- b.call(resumeFun);
- b.drop(); // drop null
-
- // (3) Return the completer's future.
-
- b.local_get(asyncStateLocal);
- final completerFutureGetterType = translator
- .signatureForDirectCall(translator.completerFuture.getterReference);
- b.struct_get(
- asyncSuspendStateInfo.struct, FieldIndex.asyncSuspendStateCompleter);
- translator.convertType(
- b,
- asyncSuspendStateInfo.struct.fields[5].type.unpacked,
- completerFutureGetterType.inputs[0]);
- call(translator.completerFuture.getterReference);
- b.end();
- }
-
- void _generateInner(FunctionNode functionNode, Context? context,
- w.FunctionBuilder resumeFun) {
+ void generateInner(FunctionNode functionNode, Context? context) {
// void Function(_AsyncSuspendState, Object?, Object?, StackTrace?)
- // Set the current Wasm function for the code generator to the inner
- // function of the `async`, which is to contain the body.
- function = resumeFun;
- b = resumeFun.body;
- functionType = resumeFun.type;
-
// Set up locals for contexts and `this`.
thisLocal = null;
Context? localContext = context;
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 6d96df2..aa3bf24 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -40,8 +40,8 @@
with ExpressionVisitor1DefaultMixin<w.ValueType, w.ValueType>
implements InitializerVisitor<void>, StatementVisitor<void> {
final Translator translator;
- w.FunctionType functionType;
- w.InstructionsBuilder b;
+ final w.FunctionType functionType;
+ final w.InstructionsBuilder b;
final Reference reference;
late final List<w.Local> paramLocals;
final w.Label? returnLabel;
diff --git a/pkg/dart2wasm/lib/state_machine.dart b/pkg/dart2wasm/lib/state_machine.dart
index cc0d292..84b43af 100644
--- a/pkg/dart2wasm/lib/state_machine.dart
+++ b/pkg/dart2wasm/lib/state_machine.dart
@@ -563,18 +563,74 @@
CatchVariables._(this.exception, this.stackTrace);
}
+abstract class StateMachineEntryCodeGenerator extends CodeGenerator {
+ final w.FunctionBuilder function;
+
+ StateMachineEntryCodeGenerator(
+ Translator translator, this.function, Reference reference)
+ : super(translator, function.type, function.body, reference,
+ paramLocals: function.locals.toList());
+
+ @override
+ void generate() {
+ final source = member.enclosingComponent!.uriToSource[member.fileUri]!;
+ closures = Closures(translator, member);
+ setSourceMapSource(source);
+ setSourceMapFileOffset(member.fileOffset);
+ setupParametersAndContexts(member.reference);
+ _generateBody(member.function!, source);
+ }
+
+ @override
+ void generateLambda(Lambda lambda, Closures closures) {
+ final source = lambda.functionNodeSource;
+ this.closures = closures;
+ setSourceMapSource(source);
+ setSourceMapFileOffset(lambda.functionNode.fileOffset);
+ setupLambdaParametersAndContexts(lambda);
+ _generateBody(lambda.functionNode, source);
+ }
+
+ void _generateBody(FunctionNode functionNode, Source functionSource) {
+ Context? context = closures.contexts[functionNode];
+ if (context != null && context.isEmpty) context = context.parent;
+
+ generateOuter(functionNode, context, functionSource);
+ }
+
+ /// Generate the outer function.
+ ///
+ /// - Outer function: the `async` or `sync*` function.
+ ///
+ /// In case of `async` this function should return a future.
+ ///
+ /// In case of `sync*`, this function should return an iterable.
+ ///
+ void generateOuter(
+ FunctionNode functionNode, Context? context, Source functionSource);
+}
+
/// A [CodeGenerator] that compiles the function to a state machine based on
/// the suspension points in the function (`await` expressions and `yield`
/// statements).
///
/// This is used to compile `async` and `sync*` functions.
abstract class StateMachineCodeGenerator extends CodeGenerator {
- w.FunctionBuilder function;
+ final w.FunctionBuilder function;
+ final FunctionNode functionNode;
+ final Source functionSource;
StateMachineCodeGenerator(
- Translator translator, this.function, Reference reference)
+ Translator translator,
+ this.function,
+ Reference reference,
+ this.functionNode,
+ this.functionSource,
+ Closures closures)
: super(translator, function.type, function.body, reference,
- paramLocals: function.locals.toList());
+ paramLocals: function.locals.toList()) {
+ this.closures = closures;
+ }
/// Targets of the CFG, indexed by target index.
late final List<StateTarget> targets;
@@ -612,23 +668,9 @@
@override
void generate() {
- final source = member.enclosingComponent!.uriToSource[member.fileUri]!;
- setSourceMapSource(source);
- setSourceMapFileOffset(member.fileOffset);
- closures = Closures(translator, member);
- setupParametersAndContexts(member.reference);
- _generateBodies(member.function!);
- }
+ setSourceMapSource(functionSource);
+ setSourceMapFileOffset(functionNode.fileOffset);
- @override
- void generateLambda(Lambda lambda, Closures closures) {
- this.closures = closures;
- setSourceMapSource(lambda.functionNodeSource);
- setupLambdaParametersAndContexts(lambda);
- _generateBodies(lambda.functionNode);
- }
-
- void _generateBodies(FunctionNode functionNode) {
// Number and categorize CFG targets.
targets = _YieldFinder(translator.options.enableAsserts).find(functionNode);
for (final target in targets) {
@@ -647,7 +689,14 @@
Context? context = closures.contexts[functionNode];
if (context != null && context.isEmpty) context = context.parent;
- generateFunctions(functionNode, context);
+ generateInner(functionNode, context);
+ }
+
+ @override
+ void generateLambda(Lambda lambda, Closures closures) {
+ // This is only invoked for the actual async/async*/sync* code generator and
+ // not for the (inner) state machine code generator.
+ throw UnsupportedError('This should not be reachable');
}
/// Store the exception value emitted by [emitValue] in suspension state.
@@ -679,23 +728,10 @@
/// iteration by returning `false`.
void emitReturn(void Function() emitValue);
- /// Generate the outer and inner functions.
- ///
- /// - Outer function: the `async` or `sync*` function.
- ///
- /// In case of `async` this function should return a future.
- ///
- /// In case of `sync*`, this function should return an iterable.
- ///
- /// Note that when generating the outer function we can't use the
- /// [StateMachineCodeGenerator] methods, as the outer functions are not the
- /// state machines used to implement suspension and resumption.
+ /// Generate the inner functions.
///
/// - Inner function: the function that will be called for resumption.
- ///
- /// [StateMachineCodeGenerator] methods (visitors etc.) are for generating
- /// this function.
- void generateFunctions(FunctionNode functionNode, Context? context);
+ void generateInner(FunctionNode functionNode, Context? context);
void emitTargetLabel(StateTarget target) {
currentTargetIndex++;
diff --git a/pkg/dart2wasm/lib/sync_star.dart b/pkg/dart2wasm/lib/sync_star.dart
index 38ff310..9718a48 100644
--- a/pkg/dart2wasm/lib/sync_star.dart
+++ b/pkg/dart2wasm/lib/sync_star.dart
@@ -10,6 +10,57 @@
import 'code_generator.dart';
import 'state_machine.dart';
+class SyncStarCodeGenerator extends StateMachineEntryCodeGenerator {
+ SyncStarCodeGenerator(super.translator, super.function, super.reference);
+
+ late final ClassInfo suspendStateInfo =
+ translator.classInfo[translator.suspendStateClass]!;
+
+ late final ClassInfo syncStarIterableInfo =
+ translator.classInfo[translator.syncStarIterableClass]!;
+
+ @override
+ void generateOuter(
+ FunctionNode functionNode, Context? context, Source functionSource) {
+ final resumeFun = _defineInnerBodyFunction(functionNode);
+
+ // Instantiate a [_SyncStarIterable] containing the context and resume
+ // function for this `sync*` function.
+ DartType elementType = functionNode.emittedValueType!;
+ translator.functions.recordClassAllocation(syncStarIterableInfo.classId);
+ b.i32_const(syncStarIterableInfo.classId);
+ b.i32_const(initialIdentityHash);
+ types.makeType(this, elementType);
+ if (context != null) {
+ assert(!context.isEmpty);
+ b.local_get(context.currentLocal);
+ } else {
+ b.ref_null(w.HeapType.struct);
+ }
+ b.global_get(translator.makeFunctionRef(resumeFun));
+ b.struct_new(syncStarIterableInfo.struct);
+ b.return_();
+ b.end();
+
+ SyncStarStateMachineCodeGenerator(translator, resumeFun, reference,
+ functionNode, functionSource, closures)
+ .generate();
+ }
+
+ w.FunctionBuilder _defineInnerBodyFunction(FunctionNode functionNode) =>
+ m.functions.define(
+ m.types.defineFunction([
+ suspendStateInfo.nonNullableType, // _SuspendState
+ translator.topInfo.nullableType, // Object?, error value
+ translator.stackTraceInfo.repr
+ .nullableType // StackTrace?, error stack trace
+ ], const [
+ // bool for whether the generator has more to do
+ w.NumType.i32
+ ]),
+ "${function.functionName} inner");
+}
+
/// A specialized code generator for generating code for `sync*` functions.
///
/// This will create an "outer" function which is a small function that just
@@ -25,8 +76,14 @@
/// Local state is preserved via the closure contexts, which will implicitly
/// capture all local variables in a `sync*` function even if they are not
/// captured by any lambdas.
-class SyncStarCodeGenerator extends StateMachineCodeGenerator {
- SyncStarCodeGenerator(super.translator, super.function, super.reference);
+class SyncStarStateMachineCodeGenerator extends StateMachineCodeGenerator {
+ SyncStarStateMachineCodeGenerator(
+ super.translator,
+ super.function,
+ super.reference,
+ super.functionNode,
+ super.functionSource,
+ super.closures);
late final ClassInfo suspendStateInfo =
translator.classInfo[translator.suspendStateClass]!;
@@ -42,19 +99,6 @@
w.Local get _pendingExceptionLocal => function.locals[1];
w.Local get _pendingStackTraceLocal => function.locals[2];
- w.FunctionBuilder _defineBodyFunction(FunctionNode functionNode) =>
- m.functions.define(
- m.types.defineFunction([
- suspendStateInfo.nonNullableType, // _SuspendState
- translator.topInfo.nullableType, // Object?, error value
- translator.stackTraceInfo.repr
- .nullableType // StackTrace?, error stack trace
- ], const [
- // bool for whether the generator has more to do
- w.NumType.i32
- ]),
- "${function.functionName} inner");
-
@override
void setSuspendStateCurrentException(void Function() emitValue) {
b.local_get(_suspendStateLocal);
@@ -104,47 +148,7 @@
}
@override
- void generateFunctions(FunctionNode functionNode, Context? context) {
- final resumeFun = _defineBodyFunction(functionNode);
-
- _generateOuter(functionNode, context, resumeFun);
-
- // Forget about the outer function locals containing the type arguments,
- // so accesses to the type arguments in the inner function will fetch them
- // from the context.
- typeLocals.clear();
-
- _generateInner(functionNode, context, resumeFun);
- }
-
- void _generateOuter(
- FunctionNode functionNode, Context? context, w.BaseFunction resumeFun) {
- // Instantiate a [_SyncStarIterable] containing the context and resume
- // function for this `sync*` function.
- DartType elementType = functionNode.emittedValueType!;
- translator.functions.recordClassAllocation(syncStarIterableInfo.classId);
- b.i32_const(syncStarIterableInfo.classId);
- b.i32_const(initialIdentityHash);
- types.makeType(this, elementType);
- if (context != null) {
- assert(!context.isEmpty);
- b.local_get(context.currentLocal);
- } else {
- b.ref_null(w.HeapType.struct);
- }
- b.global_get(translator.makeFunctionRef(resumeFun));
- b.struct_new(syncStarIterableInfo.struct);
- b.end();
- }
-
- void _generateInner(FunctionNode functionNode, Context? context,
- w.FunctionBuilder resumeFun) {
- // Set the current Wasm function for the code generator to the inner
- // function of the `sync*`, which is to contain the body.
- function = resumeFun;
- b = resumeFun.body;
- functionType = resumeFun.type;
-
+ void generateInner(FunctionNode functionNode, Context? context) {
// Set up locals for contexts and `this`.
thisLocal = null;
Context? localContext = context;
@@ -197,6 +201,7 @@
emitReturn(() {});
b.end(); // masterLoop
+ b.return_();
b.end(); // inner function
}
diff --git a/pkg/dds/CHANGELOG.md b/pkg/dds/CHANGELOG.md
index 499429d..cd0d884 100644
--- a/pkg/dds/CHANGELOG.md
+++ b/pkg/dds/CHANGELOG.md
@@ -1,6 +1,7 @@
# 4.2.5
- Fixed DevTools URI not including a trailing '/' before the query parameters, which could prevent DevTools from loading properly.
- [DAP] Fixed an issue where format specifiers and `format.hex` in `variablesRequest` would not apply to values from lists such as `Uint8List` from `dart:typed_data`.
+- Added `package:dds/dds_launcher.dart`, a library which can be used to launch DDS instances using `dart development-service`.
# 4.2.4+1
- Added missing type to `Event` in `postEvent`.
diff --git a/pkg/dds/lib/dds.dart b/pkg/dds/lib/dds.dart
index 8b22313..7a6ed14 100644
--- a/pkg/dds/lib/dds.dart
+++ b/pkg/dds/lib/dds.dart
@@ -169,6 +169,8 @@
static const String protocolVersion = '2.0';
}
+/// Thrown by DDS during initialization failures, unexpected connection issues,
+/// and when attempting to spawn DDS when an existing DDS instance exists.
class DartDevelopmentServiceException implements Exception {
/// Set when `DartDeveloperService.startDartDevelopmentService` is called and
/// the target VM service already has a Dart Developer Service instance
@@ -182,6 +184,33 @@
/// Set when a connection error has occurred after startup.
static const int connectionError = 3;
+ factory DartDevelopmentServiceException.fromJson(Map<String, Object?> json) {
+ if (json
+ case {
+ 'error_code': final int errorCode,
+ 'message': final String message,
+ 'uri': final String? uri
+ }) {
+ return switch (errorCode) {
+ existingDdsInstanceError =>
+ DartDevelopmentServiceException.existingDdsInstance(
+ message,
+ ddsUri: Uri.parse(uri!),
+ ),
+ failedToStartError => DartDevelopmentServiceException.failedToStart(),
+ connectionError =>
+ DartDevelopmentServiceException.connectionIssue(message),
+ _ => throw StateError(
+ 'Invalid DartDevelopmentServiceException error_code: $errorCode',
+ ),
+ };
+ }
+ throw StateError('Invalid DartDevelopmentServiceException JSON: $json');
+ }
+
+ /// Thrown when `DartDeveloperService.startDartDevelopmentService` is called
+ /// and the target VM service already has a Dart Developer Service instance
+ /// connected.
factory DartDevelopmentServiceException.existingDdsInstance(
String message, {
Uri? ddsUri,
@@ -192,11 +221,14 @@
);
}
+ /// Thrown when the connection to the remote VM service terminates unexpectedly
+ /// during Dart Development Service startup.
factory DartDevelopmentServiceException.failedToStart() {
return DartDevelopmentServiceException._(
failedToStartError, 'Failed to start Dart Development Service');
}
+ /// Thrown when a connection error has occurred after startup.
factory DartDevelopmentServiceException.connectionIssue(String message) {
return DartDevelopmentServiceException._(connectionError, message);
}
@@ -215,6 +247,7 @@
final String message;
}
+/// Thrown when attempting to start a new DDS instance when one already exists.
class ExistingDartDevelopmentServiceException
extends DartDevelopmentServiceException {
ExistingDartDevelopmentServiceException._(
diff --git a/pkg/dds/lib/dds_launcher.dart b/pkg/dds/lib/dds_launcher.dart
new file mode 100644
index 0000000..2e8ad80
--- /dev/null
+++ b/pkg/dds/lib/dds_launcher.dart
@@ -0,0 +1,198 @@
+// Copyright (c) 2024, 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 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'dds.dart' hide DartDevelopmentService;
+import 'src/arg_parser.dart';
+import 'src/dds_impl.dart';
+
+/// Spawns a Dart Development Service instance which will communicate with a
+/// VM service. Requires the target VM service to have no other connected
+/// clients.
+///
+/// [remoteVmServiceUri] is the address of the VM service that this
+/// development service will communicate with.
+///
+/// If provided, [serviceUri] will determine the address and port of the
+/// spawned Dart Development Service.
+///
+/// [enableAuthCodes] controls whether or not an authentication code must
+/// be provided by clients when communicating with this instance of
+/// DDS. Authentication codes take the form of a base64
+/// encoded string provided as the first element of the DDS path and is meant
+/// to make it more difficult for unintended clients to connect to this
+/// service. Authentication codes are enabled by default.
+///
+/// If [serveDevTools] is enabled, DDS will serve a DevTools instance and act
+/// as a DevTools Server. If not specified, [devToolsServerAddress] is ignored.
+///
+/// If provided, DDS will redirect DevTools requests to an existing DevTools
+/// server hosted at [devToolsServerAddress]. Ignored if [serveDevTools] is not
+/// true.
+///
+/// If [enableServicePortFallback] is enabled, DDS will attempt to bind to any
+/// available port if the specified port is unavailable.
+///
+/// If set, the set of [cachedUserTags] will be used to determine which CPU
+/// samples should be cached by DDS.
+///
+/// If provided, [dartExecutable] is the path to the 'dart' executable that
+/// should be used to spawn the DDS instance. By default, `Platform.executable`
+/// is used.
+class DartDevelopmentServiceLauncher {
+ static Future<DartDevelopmentServiceLauncher> start({
+ required Uri remoteVmServiceUri,
+ Uri? serviceUri,
+ bool enableAuthCodes = true,
+ bool serveDevTools = false,
+ Uri? devToolsServerAddress,
+ bool enableServicePortFallback = false,
+ List<String> cachedUserTags = const <String>[],
+ String? dartExecutable,
+ }) async {
+ final process = await Process.start(
+ dartExecutable ?? Platform.executable,
+ <String>[
+ 'development-service',
+ '--${DartDevelopmentServiceOptions.vmServiceUriOption}=$remoteVmServiceUri',
+ if (serviceUri != null) ...<String>[
+ '--${DartDevelopmentServiceOptions.bindAddressOption}=${serviceUri.host}',
+ '--${DartDevelopmentServiceOptions.bindPortOption}=${serviceUri.port}',
+ ],
+ if (!enableAuthCodes)
+ '--${DartDevelopmentServiceOptions.disableServiceAuthCodesFlag}',
+ if (serveDevTools)
+ '--${DartDevelopmentServiceOptions.serveDevToolsFlag}',
+ if (devToolsServerAddress != null)
+ '--${DartDevelopmentServiceOptions.devToolsServerAddressOption}=$devToolsServerAddress',
+ if (enableServicePortFallback)
+ '--${DartDevelopmentServiceOptions.enableServicePortFallbackFlag}',
+ for (final String tag in cachedUserTags)
+ '--${DartDevelopmentServiceOptions.cachedUserTagsOption}=$tag',
+ ],
+ );
+ final completer = Completer<DartDevelopmentServiceLauncher>();
+ late StreamSubscription<Object?> stderrSub;
+ stderrSub = process.stderr
+ .transform(utf8.decoder)
+ .transform(json.decoder)
+ .listen((Object? result) {
+ if (result
+ case {
+ 'state': 'started',
+ 'ddsUri': final String ddsUriStr,
+ }) {
+ final ddsUri = Uri.parse(ddsUriStr);
+ final devToolsUriStr = result['devToolsUri'] as String?;
+ final devToolsUri =
+ devToolsUriStr == null ? null : Uri.parse(devToolsUriStr);
+ final dtdUriStr =
+ (result['dtd'] as Map<String, Object?>?)?['uri'] as String?;
+ final dtdUri = dtdUriStr == null ? null : Uri.parse(dtdUriStr);
+
+ completer.complete(
+ DartDevelopmentServiceLauncher._(
+ process: process,
+ uri: ddsUri,
+ devToolsUri: devToolsUri,
+ dtdUri: dtdUri,
+ ),
+ );
+ } else if (result
+ case {
+ 'state': 'error',
+ 'error': final String error,
+ }) {
+ final Map<String, Object?>? exceptionDetails =
+ result['ddsExceptionDetails'] as Map<String, Object?>?;
+ completer.completeError(
+ exceptionDetails != null
+ ? DartDevelopmentServiceException.fromJson(exceptionDetails)
+ : StateError(error),
+ );
+ } else {
+ throw StateError('Unexpected result from DDS: $result');
+ }
+ stderrSub.cancel();
+ });
+ return completer.future;
+ }
+
+ DartDevelopmentServiceLauncher._({
+ required Process process,
+ required this.uri,
+ required this.devToolsUri,
+ required this.dtdUri,
+ }) : _ddsInstance = process;
+
+ final Process _ddsInstance;
+
+ /// The [Uri] VM service clients can use to communicate with this
+ /// DDS instance via HTTP.
+ final Uri uri;
+
+ /// The HTTP [Uri] of the hosted DevTools instance.
+ ///
+ /// Returns `null` if DevTools is not running.
+ final Uri? devToolsUri;
+
+ /// The [Uri] of the Dart Tooling Daemon instance that is hosted by DevTools.
+ ///
+ /// This will be null if DTD was not started by the DevTools server. For
+ /// example, it may have been started by an IDE.
+ final Uri? dtdUri;
+
+ /// The [Uri] VM service clients can use to communicate with this
+ /// DDS instance via server-sent events (SSE).
+ Uri get sseUri => _toSse(uri)!;
+
+ /// The [Uri] VM service clients can use to communicate with this
+ /// DDS instance via a [WebSocket].
+ Uri get wsUri => _toWebSocket(uri)!;
+
+ List<String> _cleanupPathSegments(Uri uri) {
+ final pathSegments = <String>[];
+ if (uri.pathSegments.isNotEmpty) {
+ pathSegments.addAll(
+ uri.pathSegments.where(
+ // Strip out the empty string that appears at the end of path segments.
+ // Empty string elements will result in an extra '/' being added to the
+ // URI.
+ (s) => s.isNotEmpty,
+ ),
+ );
+ }
+ return pathSegments;
+ }
+
+ Uri? _toWebSocket(Uri? uri) {
+ if (uri == null) {
+ return null;
+ }
+ final pathSegments = _cleanupPathSegments(uri);
+ pathSegments.add('ws');
+ return uri.replace(scheme: 'ws', pathSegments: pathSegments);
+ }
+
+ Uri? _toSse(Uri? uri) {
+ if (uri == null) {
+ return null;
+ }
+ final pathSegments = _cleanupPathSegments(uri);
+ pathSegments.add(DartDevelopmentServiceImpl.kSseHandlerPath);
+ return uri.replace(scheme: 'sse', pathSegments: pathSegments);
+ }
+
+ /// Completes when the DDS instance has shutdown.
+ Future<void> get done => _ddsInstance.exitCode;
+
+ /// Shutdown the DDS instance.
+ Future<void> shutdown() {
+ _ddsInstance.kill();
+ return _ddsInstance.exitCode;
+ }
+}
diff --git a/pkg/dds/lib/src/dds_impl.dart b/pkg/dds/lib/src/dds_impl.dart
index 376855e..69dcfd4 100644
--- a/pkg/dds/lib/src/dds_impl.dart
+++ b/pkg/dds/lib/src/dds_impl.dart
@@ -347,8 +347,8 @@
Handler _sseHandler() {
final handler = SseHandler(
authCodesEnabled
- ? Uri.parse('/$authCode/$_kSseHandlerPath')
- : Uri.parse('/$_kSseHandlerPath'),
+ ? Uri.parse('/$authCode/$kSseHandlerPath')
+ : Uri.parse('/$kSseHandlerPath'),
keepAlive: sseKeepAlive,
);
@@ -441,7 +441,7 @@
return null;
}
final pathSegments = _cleanupPathSegments(uri);
- pathSegments.add(_kSseHandlerPath);
+ pathSegments.add(kSseHandlerPath);
return uri.replace(scheme: 'sse', pathSegments: pathSegments);
}
@@ -552,7 +552,7 @@
StreamManager get streamManager => _streamManager;
late StreamManager _streamManager;
- static const _kSseHandlerPath = '\$debugHandler';
+ static const kSseHandlerPath = '\$debugHandler';
late json_rpc.Peer vmServiceClient;
late WebSocketChannel _vmServiceSocket;
diff --git a/pkg/dds/test/launcher_smoke_test.dart b/pkg/dds/test/launcher_smoke_test.dart
new file mode 100644
index 0000000..80fc54b
--- /dev/null
+++ b/pkg/dds/test/launcher_smoke_test.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2024, 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 'dart:convert';
+import 'dart:io';
+
+import 'package:dds/dds_launcher.dart';
+import 'package:test/test.dart';
+import 'package:vm_service/vm_service_io.dart';
+
+import 'common/test_helper.dart';
+
+void main() {
+ group('DDS', () {
+ late Process process;
+ late DartDevelopmentServiceLauncher dds;
+
+ setUp(() async {
+ process = await spawnDartProcess('smoke.dart');
+ });
+
+ tearDown(() async {
+ await dds.shutdown();
+ process.kill();
+ });
+
+ void createSmokeTest(bool useAuthCodes) {
+ test(
+ 'Launcher Smoke Test with ${useAuthCodes ? "" : "no"} authentication codes',
+ () async {
+ dds = await DartDevelopmentServiceLauncher.start(
+ remoteVmServiceUri: remoteVmServiceUri,
+ enableAuthCodes: useAuthCodes,
+ );
+
+ // Ensure basic websocket requests are forwarded correctly to the VM service.
+ final service = await vmServiceConnectUri(dds.wsUri.toString());
+ final version = await service.getVersion();
+ expect(version.major! > 0, true);
+ expect(version.minor! >= 0, true);
+
+ expect(
+ dds.uri.pathSegments,
+ useAuthCodes ? isNotEmpty : isEmpty,
+ );
+
+ // Ensure we can still make requests of the VM service via HTTP.
+ HttpClient client = HttpClient();
+ final request = await client.getUrl(remoteVmServiceUri.replace(
+ pathSegments: [
+ if (remoteVmServiceUri.pathSegments.isNotEmpty)
+ remoteVmServiceUri.pathSegments.first,
+ 'getVersion',
+ ],
+ ));
+ final response = await request.close();
+ final Map<String, dynamic> jsonResponse = (await response
+ .transform(utf8.decoder)
+ .transform(json.decoder)
+ .single) as Map<String, dynamic>;
+ expect(jsonResponse['result']['type'], 'Version');
+ expect(jsonResponse['result']['major'] > 0, true);
+ expect(jsonResponse['result']['minor'] >= 0, true);
+ },
+ );
+ }
+
+ createSmokeTest(true);
+ createSmokeTest(false);
+ });
+}
diff --git a/pkg/front_end/lib/src/base/scope.dart b/pkg/front_end/lib/src/base/scope.dart
index bb726bd..1aabf30 100644
--- a/pkg/front_end/lib/src/base/scope.dart
+++ b/pkg/front_end/lib/src/base/scope.dart
@@ -26,7 +26,6 @@
import '../source/source_function_builder.dart';
import '../source/source_library_builder.dart';
import '../source/source_member_builder.dart';
-import '../util/helpers.dart' show DelayedActionPerformer;
import 'messages.dart';
import 'name_space.dart';
import 'uri_offset.dart';
@@ -773,9 +772,7 @@
ProcedureKind? get kind => null;
@override
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
throw new UnsupportedError('$runtimeType.buildOutlineExpressions');
}
diff --git a/pkg/front_end/lib/src/builder/formal_parameter_builder.dart b/pkg/front_end/lib/src/builder/formal_parameter_builder.dart
index 8128c30..9f7c620 100644
--- a/pkg/front_end/lib/src/builder/formal_parameter_builder.dart
+++ b/pkg/front_end/lib/src/builder/formal_parameter_builder.dart
@@ -23,7 +23,6 @@
import '../source/source_field_builder.dart';
import '../source/source_library_builder.dart';
import '../source/type_parameter_scope_builder.dart';
-import '../util/helpers.dart' show DelayedActionPerformer;
import 'builder.dart';
import 'constructor_builder.dart';
import 'declaration_builders.dart';
@@ -273,8 +272,7 @@
/// Builds the default value from this [initializerToken] if this is a
/// formal parameter on a const constructor or instance method.
- void buildOutlineExpressions(SourceLibraryBuilder libraryBuilder,
- List<DelayedActionPerformer> delayedActionPerformers) {
+ void buildOutlineExpressions(SourceLibraryBuilder libraryBuilder) {
if (needsDefaultValuesBuiltAsOutlineExpressions) {
if (initializerToken != null) {
final DeclarationBuilder declarationBuilder =
@@ -296,9 +294,7 @@
bodyBuilder, initializer, variable!.type, hasDeclaredInitializer);
variable!.initializer = initializer..parent = variable;
initializerWasInferred = true;
- bodyBuilder.performBacklogComputations(
- delayedActionPerformers: delayedActionPerformers,
- allowFurtherDelays: false);
+ bodyBuilder.performBacklogComputations();
} else if (kind.isOptional) {
// As done by BodyBuilder.endFormalParameter.
variable!.initializer = new NullLiteral()..parent = variable;
diff --git a/pkg/front_end/lib/src/builder/metadata_builder.dart b/pkg/front_end/lib/src/builder/metadata_builder.dart
index 2e7c2da..315e768 100644
--- a/pkg/front_end/lib/src/builder/metadata_builder.dart
+++ b/pkg/front_end/lib/src/builder/metadata_builder.dart
@@ -107,7 +107,7 @@
// TODO(johnniwinther): Avoid potentially inferring annotations multiple
// times.
bodyBuilder.inferAnnotations(parent, parent.annotations);
- bodyBuilder.performBacklogComputations(allowFurtherDelays: false);
+ bodyBuilder.performBacklogComputations();
for (MapEntry<MetadataBuilder, int> entry
in parsedAnnotationBuilders.entries) {
MetadataBuilder annotationBuilder = entry.key;
diff --git a/pkg/front_end/lib/src/builder/type_variable_builder.dart b/pkg/front_end/lib/src/builder/type_variable_builder.dart
index 6c56ff7..65dc82c 100644
--- a/pkg/front_end/lib/src/builder/type_variable_builder.dart
+++ b/pkg/front_end/lib/src/builder/type_variable_builder.dart
@@ -401,7 +401,6 @@
SourceLibraryBuilder libraryBuilder,
BodyBuilderContext bodyBuilderContext,
ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
LookupScope scope) {
MetadataBuilder.buildAnnotations(parameter, metadata, bodyBuilderContext,
libraryBuilder, fileUri!, scope);
diff --git a/pkg/front_end/lib/src/kernel/benchmarker.dart b/pkg/front_end/lib/src/kernel/benchmarker.dart
index 8f7af23..c1164de 100644
--- a/pkg/front_end/lib/src/kernel/benchmarker.dart
+++ b/pkg/front_end/lib/src/kernel/benchmarker.dart
@@ -189,6 +189,7 @@
outline_buildClassHierarchyMembers,
outline_computeHierarchy,
outline_installTypedefTearOffs,
+ outline_performRedirectingFactoryInference,
outline_performTopLevelInference,
outline_checkOverrides,
outline_checkAbstractMembers,
@@ -279,7 +280,6 @@
inferRedirectingFactoryTypeArguments,
buildOutlineExpressions,
- delayedActionPerformer,
computeMacroApplications_macroExecutorProvider,
macroApplications_macroExecutorLoadMacro,
diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart
index 81a3d1e..356a7a5 100644
--- a/pkg/front_end/lib/src/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/kernel/body_builder.dart
@@ -100,8 +100,8 @@
import '../type_inference/type_inferrer.dart'
show TypeInferrer, InferredFunctionBody;
import '../type_inference/type_schema.dart' show UnknownType;
-import '../util/local_stack.dart';
import '../util/helpers.dart';
+import '../util/local_stack.dart';
import 'benchmarker.dart' show Benchmarker;
import 'body_builder_context.dart';
import 'collections.dart';
@@ -126,7 +126,7 @@
}
class BodyBuilder extends StackListenerImpl
- implements ExpressionGeneratorHelper, DelayedActionPerformer {
+ implements ExpressionGeneratorHelper {
@override
final Forest forest;
@@ -246,89 +246,6 @@
/// nominal correspondingly.
bool _insideOfFormalParameterType = false;
- /// True if the currently built part of the body is inside of a default value
- /// of a formal parameter.
- ///
- /// Being inside of a default value is treated with regards to possible
- /// nestedness of the default values. See the documentation on
- /// [_defaultValueNestingLevel] for details.
- bool get _insideOfFormalParameterDefaultValue {
- return _defaultValueNestingLevel > 0;
- }
-
- /// True if the parser is between [beginMetadata] and [endMetadata].
- bool _insideMetadataParsing = false;
-
- /// Numeric nestedness of formal parameter default values.
- ///
- /// The value of 0 means that the currently built part is not within a default
- /// value. Consider the following clarifying examples.
- ///
- /// // `const Bar()` isn't within a default value.
- /// foo() => const Bar();
- ///
- /// // `const Bar()` is at [_defaultValueNestingLevel] = 1.
- /// foo([dynamic x = const Bar()]) {}
- ///
- /// // `const Bar()` is at [_defaultValueNestingLevel] = 2.
- /// // `const Baz()` is at [_defaultValueNestingLevel] = 1.
- /// foo([dynamic x = ([dynamic y = const Bar()]) => const Baz()]) {}
- ///
- /// Since function expressions aren't const values, currently it's not
- /// possible to write a program with [_defaultValueNestingLevel] > 1 that
- /// doesn't contain a compile-time error. However, it's still necessary to
- /// track the nestedness level to avoid bad compiler states and compiler
- /// crashes.
- int _defaultValueNestingLevel = 0;
-
- /// Returns true if newly created aliased or redirecting invocations need
- /// post-processing such as resolution or unaliasing.
- ///
- /// The need for the condition computed by the getter is due to some parts of
- /// the AST being built twice. The first time they are built is during
- /// outline expressions building. The second time they are built during the
- /// function body building. However, they are fully processed only the first
- /// time they are built, and the second time around they are discarded.
- /// Additional complication arises due to some nodes, such as annotations,
- /// being built only once. So we only need to add the nodes created for the
- /// first time into the lists of nodes for post-processing.
- ///
- /// The invocations inside default values that need resolution or unaliasing
- /// were already added to the post-processing lists during outline expression
- /// building. Only those invocations that are built outside of the default
- /// values or inside the default values that aren't built as outline
- /// expressions need to be added during the second pass.
- bool get _createdStaticInvocationsNeedPostProcessing {
- return
- // All invocations in outline building phase will be type-inferred, and
- // they all should be added to the post-processing.
- _context.inOutlineBuildingPhase ||
-
- // Here we aren't in the outline mode, but rather in the
- // body-building mode. If the current context has formal parameters
- // and is a constructor context, their default values should be
- // skipped because in the body-building mode they aren't passed
- // through type inference.
- (!_context.hasFormalParameters ||
- !_insideOfFormalParameterDefaultValue ||
- !_context.isConstructor) &&
-
- // The invocations in the metadata should also be skipped in the
- // body-building phase, since they aren't type-inferred. An
- // exception here are the annotations within method bodies,
- // field initializers, and on formal parameters.
- !(_context.inMetadata ||
- _insideMetadataParsing &&
- !_inBody &&
- !inFormals &&
- !inFieldInitializer) &&
-
- // Finally, the const fields in body-building phase aren't
- // inferred and the invocations in them should be skipped during
- // post-processing.
- !_context.inConstFields;
- }
-
bool get inFunctionType =>
_structuralParameterDepthLevel > 0 || _insideOfFormalParameterType;
@@ -346,10 +263,6 @@
int functionNestingLevel = 0;
- int _inBodyCount = 0;
-
- bool get _inBody => _inBodyCount > 0;
-
Statement? problemInLoopOrSwitch;
LocalStack<LabelScope> _labelScopes;
@@ -371,41 +284,6 @@
/// and where that was.
Map<String, int>? initializedFields;
- /// List of built redirecting factory invocations. The targets of the
- /// invocations are to be resolved in a separate step.
- final List<FactoryConstructorInvocation> redirectingFactoryInvocations = [];
-
- /// List of redirecting factory invocations delayed for resolution.
- ///
- /// A resolution of a redirecting factory invocation can be delayed because
- /// the inference in the declaration of the redirecting factory isn't done
- /// yet.
- final List<FactoryConstructorInvocation>
- delayedRedirectingFactoryInvocations = [];
-
- /// List of built type aliased generative constructor invocations that
- /// require unaliasing.
- final List<TypeAliasedConstructorInvocation>
- typeAliasedConstructorInvocations = [];
-
- /// List of built type aliased factory constructor invocations that require
- /// unaliasing.
- final List<TypeAliasedFactoryInvocation> typeAliasedFactoryInvocations = [];
-
- /// List of type aliased factory invocations delayed for resolution.
- ///
- /// A resolution of a type aliased factory invocation can be delayed because
- /// the inference in the declaration of the target isn't done yet.
- final List<TypeAliasedFactoryInvocation>
- delayedTypeAliasedFactoryInvocations = [];
-
- /// List of type aliased constructor invocations delayed for resolution.
- ///
- /// A resolution of a type aliased constructor invocation can be delayed
- /// because the inference in the declaration of the target isn't done yet.
- final List<TypeAliasedConstructorInvocation>
- delayedTypeAliasedConstructorInvocations = [];
-
/// Variables with metadata. Their types need to be inferred late, for
/// example, in [finishFunction].
List<VariableDeclaration>? variablesWithMetadata;
@@ -538,9 +416,6 @@
void enterLocalScope(LocalScope localScope) {
_localScopes.push(localScope);
_labelScopes.push(new LabelScopeImpl(_labelScope));
- if (_localScope.kind == ScopeKind.functionBody) {
- _inBodyCount++;
- }
}
void createAndEnterLocalScope(
@@ -548,9 +423,6 @@
_localScopes
.push(_localScope.createNestedScope(debugName: debugName, kind: kind));
_labelScopes.push(new LabelScopeImpl(_labelScope));
- if (kind == ScopeKind.functionBody) {
- _inBodyCount++;
- }
}
void exitLocalScope({List<ScopeKind>? expectedScopeKinds}) {
@@ -571,9 +443,6 @@
declaredInCurrentGuard = null;
}
}
- if (_localScope.kind == ScopeKind.functionBody) {
- _inBodyCount--;
- }
_labelScopes.pop();
_localScopes.pop();
}
@@ -939,7 +808,6 @@
super.push(constantContext);
constantContext = ConstantContext.inferred;
assert(checkState(token, [ValueKinds.ConstantContext]));
- _insideMetadataParsing = true;
}
@override
@@ -1017,7 +885,6 @@
}
constantContext = savedConstantContext;
}
- _insideMetadataParsing = false;
assert(checkState(beginToken, [ValueKinds.Expression]));
}
@@ -1101,21 +968,7 @@
continue;
}
if (initializer != null) {
- if (fieldBuilder.hasBodyBeenBuilt) {
- // The initializer was already compiled (e.g., if it appear in the
- // outline, like constant field initializers) so we do not need to
- // perform type inference or transformations.
-
- // If the body is already built and it's a type aliased constructor or
- // factory invocation, they shouldn't be checked or resolved the
- // second time, so they are removed from the corresponding lists.
- if (initializer is TypeAliasedConstructorInvocation) {
- typeAliasedConstructorInvocations.remove(initializer);
- }
- if (initializer is TypeAliasedFactoryInvocation) {
- typeAliasedFactoryInvocations.remove(initializer);
- }
- } else {
+ if (!fieldBuilder.hasBodyBeenBuilt) {
initializer = typeInferrer
.inferFieldInitializer(this, fieldBuilder.builtType, initializer)
.expression;
@@ -1143,7 +996,7 @@
}
pop(); // Annotations.
- performBacklogComputations(allowFurtherDelays: false);
+ performBacklogComputations();
assert(stack.length == 0);
}
@@ -1152,40 +1005,13 @@
///
/// Back logged computations include resolution of redirecting factory
/// invocations and checking of typedef types.
- ///
- /// If the parameter [allowFurtherDelays] is set to `true`, the backlog
- /// computations are allowed to be delayed one more time if they can't be
- /// completed in the current invocation of [performBacklogComputations] and
- /// have a chance to be completed during the next invocation. If
- /// [allowFurtherDelays] is set to `false`, the backlog computations are
- /// assumed to be final and the function throws an internal exception in case
- /// if any of the computations can't be completed.
- void performBacklogComputations(
- {List<DelayedActionPerformer>? delayedActionPerformers,
- required bool allowFurtherDelays}) {
+ void performBacklogComputations() {
_finishVariableMetadata();
- _unaliasTypeAliasedConstructorInvocations(
- typeAliasedConstructorInvocations);
- _unaliasTypeAliasedFactoryInvocations(typeAliasedFactoryInvocations);
- _resolveRedirectingFactoryTargets(redirectingFactoryInvocations,
- allowFurtherDelays: allowFurtherDelays);
libraryBuilder.checkPendingBoundsChecks(typeEnvironment);
- if (hasDelayedActions) {
- assert(
- delayedActionPerformers != null,
- // Coverage-ignore(suite): Not run.
- "Body builder has delayed actions that cannot be performed: "
- "${[
- ...delayedRedirectingFactoryInvocations,
- ...delayedTypeAliasedFactoryInvocations,
- ...delayedTypeAliasedConstructorInvocations,
- ]}");
- delayedActionPerformers?.add(this);
- }
}
void finishRedirectingFactoryBody() {
- performBacklogComputations(allowFurtherDelays: false);
+ performBacklogComputations();
}
@override
@@ -1497,7 +1323,7 @@
_context.setBody(body);
}
- performBacklogComputations(allowFurtherDelays: false);
+ performBacklogComputations();
}
void checkAsyncReturnType(AsyncMarker asyncModifier, DartType returnType,
@@ -1615,7 +1441,8 @@
/// [target], `.arguments` is [arguments], `.fileOffset` is [fileOffset],
/// and `.isConst` is [isConst].
/// Returns null if the invocation can't be resolved.
- Expression? _resolveRedirectingFactoryTarget(
+ @override
+ Expression? resolveRedirectingFactoryTarget(
Procedure target, Arguments arguments, int fileOffset, bool isConst) {
Procedure initialTarget = target;
Expression replacementNode;
@@ -1662,195 +1489,49 @@
return replacementNode;
}
- /// If the parameter [allowFurtherDelays] is set to `true`, the resolution of
- /// redirecting factories is allowed to be delayed one more time if it can't
- /// be completed in the current invocation of
- /// [_resolveRedirectingFactoryTargets] and has a chance to be completed
- /// during the next invocation. If [allowFurtherDelays] is set to `false`,
- /// the resolution of redirecting factories is assumed to be final and the
- /// function throws an internal exception in case if any of the resolutions
- /// can't be completed.
- void _resolveRedirectingFactoryTargets(
- List<FactoryConstructorInvocation> redirectingFactoryInvocations,
- {required bool allowFurtherDelays}) {
- List<FactoryConstructorInvocation> invocations =
- redirectingFactoryInvocations.toList();
- redirectingFactoryInvocations.clear();
- for (FactoryConstructorInvocation invocation in invocations) {
- // If the invocation was invalid, it or its parent has already been
- // desugared into an exception throwing expression. There is nothing to
- // resolve anymore. Note that in the case where the invocation's parent
- // was invalid, type inference won't reach the invocation node and won't
- // set its inferredType field. If type inference is disabled, reach to
- // the outermost parent to check if the node is a dead code.
- if (invocation.parent == null) continue;
- if (!invocation.hasBeenInferred) {
- if (allowFurtherDelays) {
- delayedRedirectingFactoryInvocations.add(invocation);
- }
- continue;
- }
- Expression? replacement = _resolveRedirectingFactoryTarget(
- invocation.target,
- invocation.arguments,
- invocation.fileOffset,
- invocation.isConst);
- if (replacement == null) {
- delayedRedirectingFactoryInvocations.add(invocation);
- } else {
- invocation.parent?.replaceChild(invocation, replacement);
- }
- }
- }
-
- void _unaliasTypeAliasedConstructorInvocations(
- List<TypeAliasedConstructorInvocation>
- typeAliasedConstructorInvocations) {
- List<TypeAliasedConstructorInvocation> invocations = [
- ...typeAliasedConstructorInvocations
- ];
- typeAliasedConstructorInvocations.clear();
- for (TypeAliasedConstructorInvocation invocation in invocations) {
- assert(
- invocation.hasBeenInferred || isOrphaned(invocation),
- // Coverage-ignore(suite): Not run.
- "Node $invocation has not been inferred.");
-
- Expression? replacement;
- if (invocation.hasBeenInferred) {
- bool inferred = !hasExplicitTypeArguments(invocation.arguments);
- DartType aliasedType = new TypedefType(
- invocation.typeAliasBuilder.typedef,
- Nullability.nonNullable,
- invocation.arguments.types);
- libraryBuilder.checkBoundsInType(
- aliasedType, typeEnvironment, uri, invocation.fileOffset,
- allowSuperBounded: false, inferred: inferred);
- DartType unaliasedType = aliasedType.unalias;
- List<DartType>? invocationTypeArguments = null;
- if (unaliasedType is InterfaceType) {
- invocationTypeArguments = unaliasedType.typeArguments;
- }
- Arguments invocationArguments = forest.createArguments(
- noLocation, invocation.arguments.positional,
- types: invocationTypeArguments, named: invocation.arguments.named);
- replacement = new ConstructorInvocation(
- invocation.target, invocationArguments,
- isConst: invocation.isConst);
- }
- if (replacement == null) {
- delayedTypeAliasedConstructorInvocations.add(invocation);
- } else {
- invocation.parent?.replaceChild(invocation, replacement);
- }
- }
- typeAliasedConstructorInvocations.clear();
- }
-
- void _unaliasTypeAliasedFactoryInvocations(
- List<TypeAliasedFactoryInvocation> typeAliasedFactoryInvocations) {
- List<TypeAliasedFactoryInvocation> invocations =
- typeAliasedFactoryInvocations.toList();
- typeAliasedFactoryInvocations.clear();
- for (TypeAliasedFactoryInvocation invocation in invocations) {
- assert(
- invocation.hasBeenInferred || isOrphaned(invocation),
- // Coverage-ignore(suite): Not run.
- "Node $invocation has not been inferred.");
-
- Expression? replacement;
- if (invocation.hasBeenInferred) {
- bool inferred = !hasExplicitTypeArguments(invocation.arguments);
- DartType aliasedType = new TypedefType(
- invocation.typeAliasBuilder.typedef,
- Nullability.nonNullable,
- invocation.arguments.types);
- libraryBuilder.checkBoundsInType(
- aliasedType, typeEnvironment, uri, invocation.fileOffset,
- allowSuperBounded: false, inferred: inferred);
- DartType unaliasedType = aliasedType.unalias;
- List<DartType>? invocationTypeArguments = null;
- if (unaliasedType is TypeDeclarationType) {
- invocationTypeArguments = unaliasedType.typeArguments;
- }
- Arguments invocationArguments = forest.createArguments(
- noLocation, invocation.arguments.positional,
- types: invocationTypeArguments,
- named: invocation.arguments.named,
- hasExplicitTypeArguments:
- hasExplicitTypeArguments(invocation.arguments));
- replacement = _resolveRedirectingFactoryTarget(invocation.target,
- invocationArguments, invocation.fileOffset, invocation.isConst);
- }
-
- if (replacement == null) {
- delayedTypeAliasedFactoryInvocations.add(invocation);
- } else {
- invocation.parent?.replaceChild(invocation, replacement);
- }
- }
- typeAliasedFactoryInvocations.clear();
- }
-
- /// Perform actions that were delayed
- ///
- /// An action can be delayed, for instance, because it depends on some
- /// calculations in another library. For example, a resolution of a
- /// redirecting factory invocation depends on the type inference in the
- /// redirecting factory.
@override
- void performDelayedActions({required bool allowFurtherDelays}) {
- if (delayedRedirectingFactoryInvocations.isNotEmpty) {
- _resolveRedirectingFactoryTargets(delayedRedirectingFactoryInvocations,
- allowFurtherDelays: allowFurtherDelays);
- if (delayedRedirectingFactoryInvocations.isNotEmpty) {
- // Coverage-ignore-block(suite): Not run.
- for (StaticInvocation invocation
- in delayedRedirectingFactoryInvocations) {
- internalProblem(
- fasta.templateInternalProblemUnhandled.withArguments(
- invocation.target.name.text, 'performDelayedActions'),
- invocation.fileOffset,
- uri);
- }
- }
+ Expression unaliasSingleTypeAliasedConstructorInvocation(
+ TypeAliasedConstructorInvocation invocation) {
+ bool inferred = !hasExplicitTypeArguments(invocation.arguments);
+ DartType aliasedType = new TypedefType(invocation.typeAliasBuilder.typedef,
+ Nullability.nonNullable, invocation.arguments.types);
+ libraryBuilder.checkBoundsInType(
+ aliasedType, typeEnvironment, uri, invocation.fileOffset,
+ allowSuperBounded: false, inferred: inferred);
+ DartType unaliasedType = aliasedType.unalias;
+ List<DartType>? invocationTypeArguments = null;
+ if (unaliasedType is InterfaceType) {
+ invocationTypeArguments = unaliasedType.typeArguments;
}
- if (delayedTypeAliasedFactoryInvocations.isNotEmpty) {
- _unaliasTypeAliasedFactoryInvocations(
- delayedTypeAliasedFactoryInvocations);
- if (delayedTypeAliasedFactoryInvocations.isNotEmpty) {
- // Coverage-ignore-block(suite): Not run.
- for (StaticInvocation invocation
- in delayedTypeAliasedFactoryInvocations) {
- internalProblem(
- fasta.templateInternalProblemUnhandled.withArguments(
- invocation.target.name.text, 'performDelayedActions'),
- invocation.fileOffset,
- uri);
- }
- }
- }
- if (delayedTypeAliasedConstructorInvocations.isNotEmpty) {
- _unaliasTypeAliasedConstructorInvocations(
- delayedTypeAliasedConstructorInvocations);
- if (delayedTypeAliasedConstructorInvocations.isNotEmpty) {
- // Coverage-ignore-block(suite): Not run.
- for (ConstructorInvocation invocation
- in delayedTypeAliasedConstructorInvocations) {
- internalProblem(
- fasta.templateInternalProblemUnhandled.withArguments(
- invocation.target.name.text, 'performDelayedActions'),
- invocation.fileOffset,
- uri);
- }
- }
- }
+ Arguments invocationArguments = forest.createArguments(
+ noLocation, invocation.arguments.positional,
+ types: invocationTypeArguments, named: invocation.arguments.named);
+ return new ConstructorInvocation(invocation.target, invocationArguments,
+ isConst: invocation.isConst);
}
- bool get hasDelayedActions {
- return delayedRedirectingFactoryInvocations.isNotEmpty ||
- delayedTypeAliasedFactoryInvocations.isNotEmpty ||
- delayedTypeAliasedConstructorInvocations.isNotEmpty;
+ @override
+ Expression? unaliasSingleTypeAliasedFactoryInvocation(
+ TypeAliasedFactoryInvocation invocation) {
+ bool inferred = !hasExplicitTypeArguments(invocation.arguments);
+ DartType aliasedType = new TypedefType(invocation.typeAliasBuilder.typedef,
+ Nullability.nonNullable, invocation.arguments.types);
+ libraryBuilder.checkBoundsInType(
+ aliasedType, typeEnvironment, uri, invocation.fileOffset,
+ allowSuperBounded: false, inferred: inferred);
+ DartType unaliasedType = aliasedType.unalias;
+ List<DartType>? invocationTypeArguments = null;
+ if (unaliasedType is TypeDeclarationType) {
+ invocationTypeArguments = unaliasedType.typeArguments;
+ }
+ Arguments invocationArguments = forest.createArguments(
+ noLocation, invocation.arguments.positional,
+ types: invocationTypeArguments,
+ named: invocation.arguments.named,
+ hasExplicitTypeArguments:
+ hasExplicitTypeArguments(invocation.arguments));
+ return resolveRedirectingFactoryTarget(invocation.target,
+ invocationArguments, invocation.fileOffset, invocation.isConst);
}
void _finishVariableMetadata() {
@@ -1902,15 +1583,14 @@
// Coverage-ignore-block(suite): Not run.
temporaryParent = new ListLiteral(expressions);
}
- performBacklogComputations(allowFurtherDelays: false);
// Coverage-ignore(suite): Not run.
+ performBacklogComputations();
return temporaryParent != null ? temporaryParent.expressions : expressions;
}
// Coverage-ignore(suite): Not run.
Expression parseSingleExpression(
Parser parser, Token token, FunctionNode parameters) {
- assert(redirectingFactoryInvocations.isEmpty);
int fileOffset = offsetForToken(token);
List<NominalVariableBuilder>? typeParameterBuilders;
for (TypeParameter typeParameter in parameters.typeParameters) {
@@ -1988,7 +1668,7 @@
"Previously implicit assumption about inferFunctionBody "
"not returning anything different.");
- performBacklogComputations(allowFurtherDelays: false);
+ performBacklogComputations();
return fakeReturn.expression!;
}
@@ -5764,7 +5444,6 @@
super.push(constantContext);
_insideOfFormalParameterType = false;
constantContext = ConstantContext.required;
- _defaultValueNestingLevel++;
}
@override
@@ -5773,7 +5452,6 @@
Object? defaultValueExpression = pop();
constantContext = pop() as ConstantContext;
push(defaultValueExpression);
- _defaultValueNestingLevel--;
}
@override
@@ -6253,17 +5931,12 @@
libraryBuilder.checkBoundsInConstructorInvocation(
node, typeEnvironment, uri);
} else {
- TypeAliasedConstructorInvocation typeAliasedConstructorInvocation =
- node = new TypeAliasedConstructorInvocation(
- typeAliasBuilder, target, arguments,
- isConst: isConst)
- ..fileOffset = charOffset;
+ node = new TypeAliasedConstructorInvocation(
+ typeAliasBuilder, target, arguments,
+ isConst: isConst)
+ ..fileOffset = charOffset;
// No type arguments were passed, so we need not check bounds.
assert(arguments.types.isEmpty);
- if (_createdStaticInvocationsNeedPostProcessing) {
- typeAliasedConstructorInvocations
- .add(typeAliasedConstructorInvocation);
- }
}
return node;
} else {
@@ -6295,9 +5968,6 @@
libraryBuilder.checkBoundsInFactoryInvocation(
factoryConstructorInvocation, typeEnvironment, uri,
inferred: !hasExplicitTypeArguments(arguments));
- if (_createdStaticInvocationsNeedPostProcessing) {
- redirectingFactoryInvocations.add(factoryConstructorInvocation);
- }
node = factoryConstructorInvocation;
} else {
TypeAliasedFactoryInvocation typeAliasedFactoryInvocation =
@@ -6307,9 +5977,6 @@
..fileOffset = charOffset;
// No type arguments were passed, so we need not check bounds.
assert(arguments.types.isEmpty);
- if (_createdStaticInvocationsNeedPostProcessing) {
- typeAliasedFactoryInvocations.add(typeAliasedFactoryInvocation);
- }
node = typeAliasedFactoryInvocation;
}
return node;
@@ -10525,7 +10192,6 @@
node.target, clone(node.arguments),
isConst: node.isConst)
..hasBeenInferred = node.hasBeenInferred;
- bodyBuilder.redirectingFactoryInvocations.add(result);
return result;
}
// Coverage-ignore(suite): Not run.
@@ -10534,7 +10200,6 @@
node.typeAliasBuilder, node.target, clone(node.arguments),
isConst: node.isConst)
..hasBeenInferred = node.hasBeenInferred;
- bodyBuilder.typeAliasedFactoryInvocations.add(result);
return result;
}
// Coverage-ignore(suite): Not run.
@@ -10550,7 +10215,6 @@
node.typeAliasBuilder, node.target, clone(node.arguments),
isConst: node.isConst)
..hasBeenInferred = node.hasBeenInferred;
- bodyBuilder.typeAliasedConstructorInvocations.add(result);
return result;
}
return super.visitConstructorInvocation(node);
diff --git a/pkg/front_end/lib/src/kernel/kernel_target.dart b/pkg/front_end/lib/src/kernel/kernel_target.dart
index 747d9f1..526a03b 100644
--- a/pkg/front_end/lib/src/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/kernel/kernel_target.dart
@@ -616,6 +616,15 @@
benchmarker
// Coverage-ignore(suite): Not run.
+ ?.enterPhase(
+ BenchmarkPhases.outline_performRedirectingFactoryInference);
+ // TODO(johnniwinther): Add an interface for registering delayed actions.
+ List<DelayedDefaultValueCloner> delayedDefaultValueCloners = [];
+ loader.inferRedirectingFactories(
+ loader.hierarchy, delayedDefaultValueCloners);
+
+ benchmarker
+ // Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_performTopLevelInference);
loader.performTopLevelInference(sortedSourceClassBuilders);
@@ -637,8 +646,6 @@
benchmarker
// Coverage-ignore(suite): Not run.
?.enterPhase(BenchmarkPhases.outline_buildOutlineExpressions);
- // TODO(johnniwinther): Add an interface for registering delayed actions.
- List<DelayedDefaultValueCloner> delayedDefaultValueCloners = [];
loader.buildOutlineExpressions(
loader.hierarchy, delayedDefaultValueCloners);
delayedDefaultValueCloners.forEach(registerDelayedDefaultValueCloner);
diff --git a/pkg/front_end/lib/src/source/source_builder_factory.dart b/pkg/front_end/lib/src/source/source_builder_factory.dart
index d02d5ad..0ca16da 100644
--- a/pkg/front_end/lib/src/source/source_builder_factory.dart
+++ b/pkg/front_end/lib/src/source/source_builder_factory.dart
@@ -1519,6 +1519,8 @@
procedureNameScheme,
nativeMethodName,
redirectionTarget);
+ (_parent.redirectingFactoryBuilders ??= [])
+ .add(procedureBuilder as RedirectingFactoryBuilder);
} else {
procedureBuilder = new SourceFactoryBuilder(
metadata,
diff --git a/pkg/front_end/lib/src/source/source_builder_mixins.dart b/pkg/front_end/lib/src/source/source_builder_mixins.dart
index defa998..8201a79 100644
--- a/pkg/front_end/lib/src/source/source_builder_mixins.dart
+++ b/pkg/front_end/lib/src/source/source_builder_mixins.dart
@@ -20,7 +20,6 @@
import '../builder/type_builder.dart';
import '../kernel/body_builder_context.dart';
import '../kernel/kernel_helper.dart';
-import '../util/helpers.dart';
import 'source_constructor_builder.dart';
import 'source_field_builder.dart';
import 'source_library_builder.dart';
@@ -159,9 +158,7 @@
required bool inMetadata,
required bool inConstFields});
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
MetadataBuilder.buildAnnotations(
annotatable,
@@ -182,7 +179,6 @@
inMetadata: true,
inConstFields: false),
classHierarchy,
- delayedActionPerformers,
typeParameterScope);
}
}
@@ -190,8 +186,8 @@
Iterator<SourceMemberBuilder> iterator = nameSpace.filteredIterator(
parent: this, includeDuplicates: false, includeAugmentations: true);
while (iterator.moveNext()) {
- iterator.current.buildOutlineExpressions(
- classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
+ iterator.current
+ .buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
}
}
diff --git a/pkg/front_end/lib/src/source/source_class_builder.dart b/pkg/front_end/lib/src/source/source_class_builder.dart
index f6598d5..d2b4cf6 100644
--- a/pkg/front_end/lib/src/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/source/source_class_builder.dart
@@ -44,7 +44,6 @@
import '../kernel/kernel_helper.dart';
import '../kernel/type_algorithms.dart' show computeTypeVariableBuilderVariance;
import '../kernel/utils.dart' show compareProcedures;
-import '../util/helpers.dart';
import 'class_declaration.dart';
import 'source_builder_mixins.dart';
import 'source_constructor_builder.dart';
@@ -383,14 +382,12 @@
inConstFields: inConstFields);
}
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
void build(Builder declaration) {
SourceMemberBuilder member = declaration as SourceMemberBuilder;
member.buildOutlineExpressions(
- classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
+ classHierarchy, delayedDefaultValueCloners);
}
MetadataBuilder.buildAnnotations(
@@ -413,7 +410,6 @@
inMetadata: true,
inConstFields: false),
classHierarchy,
- delayedActionPerformers,
typeParameterScope);
}
}
diff --git a/pkg/front_end/lib/src/source/source_constructor_builder.dart b/pkg/front_end/lib/src/source/source_constructor_builder.dart
index 4f5fd9d..2572203 100644
--- a/pkg/front_end/lib/src/source/source_constructor_builder.dart
+++ b/pkg/front_end/lib/src/source/source_constructor_builder.dart
@@ -45,7 +45,6 @@
finishProcedureAugmentation;
import '../type_inference/inference_results.dart';
import '../type_inference/type_schema.dart';
-import '../util/helpers.dart' show DelayedActionPerformer;
import 'constructor_declaration.dart';
import 'name_scheme.dart';
import 'source_class_builder.dart';
@@ -302,9 +301,7 @@
}
void _buildConstructorForOutline(
- Token? beginInitializers,
- List<DelayedActionPerformer> delayedActionPerformers,
- LookupScope declarationScope) {
+ Token? beginInitializers, LookupScope declarationScope) {
if (beginInitializers != null) {
final LocalScope? formalParameterScope;
if (isConst) {
@@ -328,11 +325,10 @@
if (isConst) {
bodyBuilder.constantContext = ConstantContext.required;
}
+ inferFormalTypes(bodyBuilder.hierarchy);
bodyBuilder.parseInitializers(beginInitializers,
doFinishConstructor: isConst);
- bodyBuilder.performBacklogComputations(
- delayedActionPerformers: delayedActionPerformers,
- allowFurtherDelays: false);
+ bodyBuilder.performBacklogComputations();
}
}
@@ -842,24 +838,20 @@
bool _hasBuiltOutlines = false;
@override
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
if (_hasBuiltOutlines) return;
if (isConst && isAugmenting) {
origin.buildOutlineExpressions(
- classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
+ classHierarchy, delayedDefaultValueCloners);
}
- super.buildOutlineExpressions(
- classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
+ super.buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
// For modular compilation purposes we need to include initializers
// for const constructors into the outline. We also need to parse
// initializers to infer types of the super-initializing parameters.
if (isConst || _hasSuperInitializingFormals) {
- _buildConstructorForOutline(
- beginInitializers, delayedActionPerformers, classBuilder.scope);
+ _buildConstructorForOutline(beginInitializers, classBuilder.scope);
}
addSuperParameterDefaultValueCloners(delayedDefaultValueCloners);
if (isConst && isAugmenting) {
@@ -1104,9 +1096,7 @@
}
@override
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
if (_immediatelyDefiningConstructor != null) {
// Ensure that default value expressions have been created for [_origin].
@@ -1114,8 +1104,8 @@
// values and initializers first.
MemberBuilder origin = _immediatelyDefiningConstructor!;
if (origin is SourceConstructorBuilder) {
- origin.buildOutlineExpressions(classHierarchy, delayedActionPerformers,
- delayedDefaultValueCloners);
+ origin.buildOutlineExpressions(
+ classHierarchy, delayedDefaultValueCloners);
}
addSuperParameterDefaultValueCloners(delayedDefaultValueCloners);
_immediatelyDefiningConstructor = null;
@@ -1265,20 +1255,16 @@
}
@override
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
- super.buildOutlineExpressions(
- classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
+ super.buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
if (isConst) {
// For modular compilation purposes we need to include initializers
// for const constructors into the outline.
LookupScope typeParameterScope =
computeTypeParameterScope(extensionTypeDeclarationBuilder.scope);
- _buildConstructorForOutline(
- beginInitializers, delayedActionPerformers, typeParameterScope);
+ _buildConstructorForOutline(beginInitializers, typeParameterScope);
_buildBody();
}
beginInitializers = null;
diff --git a/pkg/front_end/lib/src/source/source_enum_builder.dart b/pkg/front_end/lib/src/source/source_enum_builder.dart
index 4540be2..2abf5d9 100644
--- a/pkg/front_end/lib/src/source/source_enum_builder.dart
+++ b/pkg/front_end/lib/src/source/source_enum_builder.dart
@@ -51,7 +51,6 @@
import '../kernel/kernel_helper.dart';
import '../type_inference/inference_results.dart';
import '../type_inference/type_schema.dart';
-import '../util/helpers.dart';
import 'name_scheme.dart';
import 'source_class_builder.dart' show SourceClassBuilder;
import 'source_constructor_builder.dart';
@@ -83,8 +82,6 @@
final Set<SourceFieldBuilder> _builtElements =
new Set<SourceFieldBuilder>.identity();
- final List<DelayedActionPerformer> _delayedActionPerformers = [];
-
SourceEnumBuilder.internal(
List<MetadataBuilder>? metadata,
String name,
@@ -702,9 +699,7 @@
// redirecting factories can't be completed at this moment and
// therefore should be delayed to another invocation of
// [BodyBuilder.performBacklogComputations].
- bodyBuilder.performBacklogComputations(
- delayedActionPerformers: _delayedActionPerformers,
- allowFurtherDelays: true);
+ bodyBuilder.performBacklogComputations();
arguments.positional.insertAll(0, enumSyntheticArguments);
arguments.argumentsOriginalOrder?.insertAll(0, enumSyntheticArguments);
@@ -778,9 +773,7 @@
}
@override
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
List<Expression> values = <Expression>[];
if (enumConstantInfos != null) {
@@ -807,8 +800,6 @@
elementBuilder.type.registerInferredType(
buildElement(elementBuilder, classHierarchy.coreTypes));
}
- delayedActionPerformers.addAll(_delayedActionPerformers);
- _delayedActionPerformers.clear();
SourceProcedureBuilder toStringBuilder =
firstMemberNamed("_enumToString") as SourceProcedureBuilder;
@@ -846,8 +837,7 @@
]));
}
- super.buildOutlineExpressions(
- classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
+ super.buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
}
}
diff --git a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart
index 29dcd03..d892e59 100644
--- a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart
+++ b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart
@@ -29,7 +29,6 @@
import '../kernel/kernel_helper.dart';
import '../kernel/type_algorithms.dart';
import '../type_inference/type_inference_engine.dart';
-import '../util/helpers.dart';
import 'class_declaration.dart';
import 'source_builder_mixins.dart';
import 'source_constructor_builder.dart';
@@ -594,18 +593,15 @@
}
@override
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
- super.buildOutlineExpressions(
- classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
+ super.buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
Iterator<SourceMemberBuilder> iterator = constructorScope.filteredIterator(
parent: this, includeDuplicates: false, includeAugmentations: true);
while (iterator.moveNext()) {
- iterator.current.buildOutlineExpressions(
- classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
+ iterator.current
+ .buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
}
}
diff --git a/pkg/front_end/lib/src/source/source_factory_builder.dart b/pkg/front_end/lib/src/source/source_factory_builder.dart
index ff84d96..07f7370 100644
--- a/pkg/front_end/lib/src/source/source_factory_builder.dart
+++ b/pkg/front_end/lib/src/source/source_factory_builder.dart
@@ -24,6 +24,7 @@
import '../builder/formal_parameter_builder.dart';
import '../builder/function_builder.dart';
import '../builder/metadata_builder.dart';
+import '../builder/omitted_type_builder.dart';
import '../builder/type_builder.dart';
import '../codes/cfe_codes.dart';
import '../dill/dill_extension_type_member_builder.dart';
@@ -35,7 +36,6 @@
import '../type_inference/inference_helper.dart';
import '../type_inference/type_inferrer.dart';
import '../type_inference/type_schema.dart';
-import '../util/helpers.dart';
import 'name_scheme.dart';
import 'redirecting_factory_body.dart';
import 'source_class_builder.dart';
@@ -202,16 +202,13 @@
bool _hasBuiltOutlines = false;
@override
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
if (_hasBuiltOutlines) return;
if (_delayedDefaultValueCloner != null) {
delayedDefaultValueCloners.add(_delayedDefaultValueCloner!);
}
- super.buildOutlineExpressions(
- classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
+ super.buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
_hasBuiltOutlines = true;
}
@@ -487,20 +484,21 @@
bool _hasBuiltOutlines = false;
@override
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
if (_hasBuiltOutlines) return;
if (isConst && isAugmenting) {
origin.buildOutlineExpressions(
- classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
+ classHierarchy, delayedDefaultValueCloners);
}
- super.buildOutlineExpressions(
- classHierarchy, delayedActionPerformers, delayedDefaultValueCloners);
+ super.buildOutlineExpressions(classHierarchy, delayedDefaultValueCloners);
- RedirectingFactoryTarget redirectingFactoryTarget =
- _procedureInternal.function.redirectingFactoryTarget!;
+ RedirectingFactoryTarget? redirectingFactoryTarget =
+ _procedureInternal.function.redirectingFactoryTarget;
+ if (redirectingFactoryTarget == null) {
+ // The error is reported elsewhere.
+ return;
+ }
List<DartType>? typeArguments = redirectingFactoryTarget.typeArguments;
Member? target = redirectingFactoryTarget.target;
if (typeArguments != null && typeArguments.any((t) => t is UnknownType)) {
@@ -519,8 +517,8 @@
Builder? targetBuilder = redirectionTarget.target;
if (targetBuilder is SourceMemberBuilder) {
// Ensure that target has been built.
- targetBuilder.buildOutlineExpressions(classHierarchy,
- delayedActionPerformers, delayedDefaultValueCloners);
+ targetBuilder.buildOutlineExpressions(
+ classHierarchy, delayedDefaultValueCloners);
}
if (targetBuilder is FunctionBuilder) {
target = targetBuilder.member;
@@ -532,6 +530,23 @@
unhandled("${targetBuilder.runtimeType}", "buildOutlineExpressions",
charOffset, fileUri);
}
+
+ // Type arguments for the targets of redirecting factories can only be
+ // inferred if the formal parameters of the targets are inferred too.
+ // That may not be the case when the target's parameters are initializing
+ // parameters referring to fields with types that are to be inferred.
+ if (targetBuilder is SourceFunctionBuilderImpl) {
+ List<FormalParameterBuilder>? formals = targetBuilder.formals;
+ if (formals != null) {
+ for (FormalParameterBuilder formal in formals) {
+ TypeBuilder formalType = formal.type;
+ if (formalType is InferableTypeBuilder) {
+ formalType.inferType(classHierarchy);
+ }
+ }
+ }
+ }
+
typeArguments = inferrer.inferRedirectingFactoryTypeArguments(
helper,
_procedureInternal.function.returnType,
diff --git a/pkg/front_end/lib/src/source/source_field_builder.dart b/pkg/front_end/lib/src/source/source_field_builder.dart
index 443b41e..d60b640 100644
--- a/pkg/front_end/lib/src/source/source_field_builder.dart
+++ b/pkg/front_end/lib/src/source/source_field_builder.dart
@@ -37,7 +37,6 @@
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
import '../type_inference/type_inference_engine.dart'
show IncludesTypeParametersNonCovariantly;
-import '../util/helpers.dart' show DelayedActionPerformer;
import 'source_class_builder.dart';
import 'source_extension_type_declaration_builder.dart';
import 'source_member_builder.dart';
@@ -452,9 +451,7 @@
Iterable<Annotatable> get annotatables => _fieldEncoding.annotatables;
@override
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
for (Annotatable annotatable in annotatables) {
MetadataBuilder.buildAnnotations(
@@ -495,9 +492,7 @@
bodyBuilder.parseFieldInitializer(_constInitializerToken!))
.expression;
buildBody(classHierarchy.coreTypes, initializer);
- bodyBuilder.performBacklogComputations(
- delayedActionPerformers: delayedActionPerformers,
- allowFurtherDelays: false);
+ bodyBuilder.performBacklogComputations();
}
_constInitializerToken = null;
}
diff --git a/pkg/front_end/lib/src/source/source_function_builder.dart b/pkg/front_end/lib/src/source/source_function_builder.dart
index dac0725..3e5f9de 100644
--- a/pkg/front_end/lib/src/source/source_function_builder.dart
+++ b/pkg/front_end/lib/src/source/source_function_builder.dart
@@ -34,7 +34,6 @@
import 'source_loader.dart' show SourceLoader;
import '../type_inference/type_inference_engine.dart'
show IncludesTypeParametersNonCovariantly;
-import '../util/helpers.dart' show DelayedActionPerformer;
import 'source_builder_mixins.dart';
import 'source_extension_type_declaration_builder.dart';
import 'source_member_builder.dart';
@@ -482,9 +481,7 @@
}
@override
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
if (!hasBuiltOutlineExpressions) {
DeclarationBuilder? classOrExtensionBuilder =
@@ -515,7 +512,6 @@
inMetadata: true,
inConstFields: false),
classHierarchy,
- delayedActionPerformers,
computeTypeParameterScope(parentScope));
}
}
@@ -526,8 +522,7 @@
// buildOutlineExpressions to clear initializerToken to prevent
// consuming too much memory.
for (FormalParameterBuilder formal in formals!) {
- formal.buildOutlineExpressions(
- libraryBuilder, delayedActionPerformers);
+ formal.buildOutlineExpressions(libraryBuilder);
}
}
hasBuiltOutlineExpressions = true;
diff --git a/pkg/front_end/lib/src/source/source_library_builder.dart b/pkg/front_end/lib/src/source/source_library_builder.dart
index 58258b1..068f780 100644
--- a/pkg/front_end/lib/src/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/source/source_library_builder.dart
@@ -71,7 +71,6 @@
exportNeverSentinel,
toKernelCombinators,
unserializableExportName;
-import '../util/helpers.dart';
import 'builder_factory.dart';
import 'class_declaration.dart';
import 'name_scheme.dart';
@@ -189,6 +188,13 @@
/// if [SourceLoader.computeFieldPromotability] hasn't been called.
FieldNonPromotabilityInfo? fieldNonPromotabilityInfo;
+ /// Redirecting factory builders defined in the library. They should be
+ /// collected as they are built, so that we can build the outline expressions
+ /// in the right order.
+ ///
+ /// See [SourceLoader.buildOutlineExpressions] for details.
+ List<RedirectingFactoryBuilder>? redirectingFactoryBuilders;
+
// TODO(johnniwinther): Remove this.
final Map<String, List<Builder>>? augmentations;
@@ -1142,16 +1148,14 @@
inConstFields: inConstFields);
}
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedDefaultValueCloner> delayedDefaultValueCloners,
- List<DelayedActionPerformer> delayedActionPerformers) {
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
+ List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
Iterable<SourceLibraryBuilder>? augmentationLibraries =
this.augmentationLibraries;
if (augmentationLibraries != null) {
for (SourceLibraryBuilder augmentationLibrary in augmentationLibraries) {
- augmentationLibrary.buildOutlineExpressions(classHierarchy,
- delayedDefaultValueCloners, delayedActionPerformers);
+ augmentationLibrary.buildOutlineExpressions(
+ classHierarchy, delayedDefaultValueCloners);
}
}
@@ -1171,20 +1175,20 @@
while (iterator.moveNext()) {
Builder declaration = iterator.current;
if (declaration is SourceClassBuilder) {
- declaration.buildOutlineExpressions(classHierarchy,
- delayedActionPerformers, delayedDefaultValueCloners);
+ declaration.buildOutlineExpressions(
+ classHierarchy, delayedDefaultValueCloners);
} else if (declaration is SourceExtensionBuilder) {
- declaration.buildOutlineExpressions(classHierarchy,
- delayedActionPerformers, delayedDefaultValueCloners);
+ declaration.buildOutlineExpressions(
+ classHierarchy, delayedDefaultValueCloners);
} else if (declaration is SourceExtensionTypeDeclarationBuilder) {
- declaration.buildOutlineExpressions(classHierarchy,
- delayedActionPerformers, delayedDefaultValueCloners);
+ declaration.buildOutlineExpressions(
+ classHierarchy, delayedDefaultValueCloners);
} else if (declaration is SourceMemberBuilder) {
- declaration.buildOutlineExpressions(classHierarchy,
- delayedActionPerformers, delayedDefaultValueCloners);
+ declaration.buildOutlineExpressions(
+ classHierarchy, delayedDefaultValueCloners);
} else if (declaration is SourceTypeAliasBuilder) {
- declaration.buildOutlineExpressions(classHierarchy,
- delayedActionPerformers, delayedDefaultValueCloners);
+ declaration.buildOutlineExpressions(
+ classHierarchy, delayedDefaultValueCloners);
} else {
assert(
declaration is PrefixBuilder ||
diff --git a/pkg/front_end/lib/src/source/source_loader.dart b/pkg/front_end/lib/src/source/source_loader.dart
index 897c3e9..48d8dd8 100644
--- a/pkg/front_end/lib/src/source/source_loader.dart
+++ b/pkg/front_end/lib/src/source/source_loader.dart
@@ -78,7 +78,6 @@
import '../macros/macro_injected_impl.dart' as injected;
import '../type_inference/type_inference_engine.dart';
import '../type_inference/type_inferrer.dart';
-import '../util/helpers.dart';
import 'diet_listener.dart' show DietListener;
import 'diet_parser.dart' show DietParser, useImplicitCreationExpressionInCfe;
import 'name_scheme.dart';
@@ -88,6 +87,7 @@
import 'source_constructor_builder.dart';
import 'source_enum_builder.dart';
import 'source_extension_type_declaration_builder.dart';
+import 'source_factory_builder.dart';
import 'source_library_builder.dart'
show
ImplicitLanguageVersion,
@@ -2898,24 +2898,10 @@
void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
- List<DelayedActionPerformer> delayedActionPerformers =
- <DelayedActionPerformer>[];
for (SourceLibraryBuilder library in sourceLibraryBuilders) {
library.buildOutlineExpressions(
- classHierarchy, delayedDefaultValueCloners, delayedActionPerformers);
+ classHierarchy, delayedDefaultValueCloners);
}
-
- target.benchmarker
- // Coverage-ignore(suite): Not run.
- ?.beginSubdivide(BenchmarkSubdivides.delayedActionPerformer);
- for (DelayedActionPerformer delayedActionPerformer
- in delayedActionPerformers) {
- delayedActionPerformer.performDelayedActions(allowFurtherDelays: false);
- }
- target.benchmarker
- // Coverage-ignore(suite): Not run.
- ?.endSubdivide();
- ticker.logMs("Build outline expressions");
}
void buildClassHierarchy(
@@ -2943,15 +2929,47 @@
new TypeInferenceEngineImpl(instrumentation, target.benchmarker);
}
- void performTopLevelInference(List<SourceClassBuilder> sourceClasses) {
+ void inferRedirectingFactories(ClassHierarchy classHierarchy,
+ List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
+ /// Inferring redirecting factories partially overlaps with top-level
+ /// inference, since the formal parameters of the redirection targets should
+ /// be inferred, and they can be formal initializing parameters requiring
+ /// inference. [RedirectingFactoryBuilder.buildOutlineExpressions] can
+ /// invoke inference on those formal parameters. Therefore, the top-level
+ /// inference should be prepared before we can infer redirecting factories.
+
/// The first phase of top level initializer inference, which consists of
/// creating kernel objects for all fields and top level variables that
/// might be subject to type inference, and records dependencies between
/// them.
typeInferenceEngine.prepareTopLevel(coreTypes, hierarchy);
membersBuilder.computeTypes();
- inferableTypes.inferTypes(typeInferenceEngine.hierarchyBuilder);
+ // TODO(cstefantsova): Put the redirecting factory inference into a separate
+ // step.
+
+ // Redirecting factory invocations can occur in outline expressions and
+ // should be processed before them. The outline expressions within
+ // redirecting factory invocations themselves are minimal, containing only
+ // the target and possibly some type arguments, and don't depend on other
+ // kinds of outline expressions themselves.
+ for (SourceLibraryBuilder library in sourceLibraryBuilders) {
+ List<RedirectingFactoryBuilder>? redirectingFactoryBuilders =
+ library.redirectingFactoryBuilders;
+ if (redirectingFactoryBuilders != null) {
+ for (RedirectingFactoryBuilder redirectingFactoryBuilder
+ in redirectingFactoryBuilders) {
+ redirectingFactoryBuilder.buildOutlineExpressions(
+ classHierarchy, delayedDefaultValueCloners);
+ }
+ }
+ }
+
+ ticker.logMs("Performed redirecting factory inference");
+ }
+
+ void performTopLevelInference(List<SourceClassBuilder> sourceClasses) {
+ inferableTypes.inferTypes(typeInferenceEngine.hierarchyBuilder);
typeInferenceEngine.isTypeInferencePrepared = true;
ticker.logMs("Performed top level inference");
diff --git a/pkg/front_end/lib/src/source/source_member_builder.dart b/pkg/front_end/lib/src/source/source_member_builder.dart
index 35ce7d3..136c2fb 100644
--- a/pkg/front_end/lib/src/source/source_member_builder.dart
+++ b/pkg/front_end/lib/src/source/source_member_builder.dart
@@ -18,7 +18,6 @@
import '../kernel/kernel_helper.dart';
import '../type_inference/type_inference_engine.dart'
show InferenceDataForTesting;
-import '../util/helpers.dart' show DelayedActionPerformer;
import 'source_class_builder.dart';
import 'source_library_builder.dart';
@@ -34,9 +33,7 @@
/// Builds the core AST structures for this member as needed for the outline.
void buildOutlineNodes(BuildNodesCallback f);
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners);
/// Builds the AST nodes for this member as needed for the full compilation.
@@ -171,9 +168,7 @@
@override
// Coverage-ignore(suite): Not run.
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {}
@override
diff --git a/pkg/front_end/lib/src/source/source_type_alias_builder.dart b/pkg/front_end/lib/src/source/source_type_alias_builder.dart
index 8db6d9b..4325d2c 100644
--- a/pkg/front_end/lib/src/source/source_type_alias_builder.dart
+++ b/pkg/front_end/lib/src/source/source_type_alias_builder.dart
@@ -25,7 +25,6 @@
import '../kernel/constructor_tearoff_lowering.dart';
import '../kernel/expression_generator_helper.dart';
import '../kernel/kernel_helper.dart';
-import '../util/helpers.dart';
import 'source_library_builder.dart' show SourceLibraryBuilder;
import 'source_loader.dart';
@@ -335,9 +334,7 @@
inConstFields: inConstFields);
}
- void buildOutlineExpressions(
- ClassHierarchy classHierarchy,
- List<DelayedActionPerformer> delayedActionPerformers,
+ void buildOutlineExpressions(ClassHierarchy classHierarchy,
List<DelayedDefaultValueCloner> delayedDefaultValueCloners) {
MetadataBuilder.buildAnnotations(
typedef,
@@ -358,7 +355,6 @@
inMetadata: true,
inConstFields: false),
classHierarchy,
- delayedActionPerformers,
computeTypeParameterScope(libraryBuilder.scope));
}
}
diff --git a/pkg/front_end/lib/src/type_inference/inference_helper.dart b/pkg/front_end/lib/src/type_inference/inference_helper.dart
index 8899b9f..71089c2 100644
--- a/pkg/front_end/lib/src/type_inference/inference_helper.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_helper.dart
@@ -5,6 +5,7 @@
import 'package:kernel/ast.dart';
import '../codes/cfe_codes.dart' show LocatedMessage, Message;
+import '../kernel/internal_ast.dart';
abstract class InferenceHelper {
Uri get uri;
@@ -28,4 +29,13 @@
String superConstructorNameForDiagnostics(String name);
String constructorNameForDiagnostics(String name, {String? className});
+
+ Expression unaliasSingleTypeAliasedConstructorInvocation(
+ TypeAliasedConstructorInvocation invocation);
+
+ Expression? resolveRedirectingFactoryTarget(
+ Procedure target, Arguments arguments, int fileOffset, bool isConst);
+
+ Expression? unaliasSingleTypeAliasedFactoryInvocation(
+ TypeAliasedFactoryInvocation invocation);
}
diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart
index 20a1c62..1dab4ce 100644
--- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart
@@ -1415,15 +1415,17 @@
isConst: node.isConst,
staticTarget: node.target);
node.hasBeenInferred = true;
- Expression resultNode = node;
SourceLibraryBuilder library = libraryBuilder;
if (!hadExplicitTypeArguments) {
library.checkBoundsInFactoryInvocation(
node, typeSchemaEnvironment, helper.uri,
inferred: true);
}
- return new ExpressionInferenceResult(
- result.inferredType, result.applyResult(resultNode));
+ Expression resolvedExpression = helper.resolveRedirectingFactoryTarget(
+ node.target, node.arguments, node.fileOffset, node.isConst)!;
+ Expression resultExpression = result.applyResult(resolvedExpression);
+
+ return new ExpressionInferenceResult(result.inferredType, resultExpression);
}
/// Returns the function type of [constructor] when called through [typedef].
@@ -1481,10 +1483,13 @@
isConst: node.isConst,
staticTarget: node.target);
node.hasBeenInferred = true;
- Expression resultNode = node;
+
+ Expression resolvedExpression =
+ helper.unaliasSingleTypeAliasedConstructorInvocation(node);
+ Expression resultingExpression = result.applyResult(resolvedExpression);
return new ExpressionInferenceResult(
- result.inferredType, result.applyResult(resultNode));
+ result.inferredType, resultingExpression);
}
/// Returns the function type of [factory] when called through [typedef].
@@ -1547,10 +1552,13 @@
node.arguments as ArgumentsImpl,
isConst: node.isConst,
staticTarget: node.target);
+
+ Expression resolvedExpression =
+ helper.unaliasSingleTypeAliasedFactoryInvocation(node)!;
+ Expression resultExpression = result.applyResult(resolvedExpression);
+
node.hasBeenInferred = true;
- Expression resultNode = node;
- return new ExpressionInferenceResult(
- result.inferredType, result.applyResult(resultNode));
+ return new ExpressionInferenceResult(result.inferredType, resultExpression);
}
@override
diff --git a/pkg/front_end/lib/src/util/helpers.dart b/pkg/front_end/lib/src/util/helpers.dart
index b3eb4d5..07ce19c 100644
--- a/pkg/front_end/lib/src/util/helpers.dart
+++ b/pkg/front_end/lib/src/util/helpers.dart
@@ -7,10 +7,6 @@
import '../api_prototype/experimental_flags.dart';
import '../source/source_library_builder.dart';
-abstract class DelayedActionPerformer {
- void performDelayedActions({required bool allowFurtherDelays});
-}
-
/// Returns `true` if access to `Record` from `dart:core` is allowed.
bool isRecordAccessAllowed(SourceLibraryBuilder library) {
return library
diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart
index f714809..9e7a7a3 100644
--- a/pkg/front_end/test/coverage_suite_expected.dart
+++ b/pkg/front_end/test/coverage_suite_expected.dart
@@ -285,7 +285,7 @@
),
// 100.0%.
"package:front_end/src/builder/formal_parameter_builder.dart": (
- hitCount: 188,
+ hitCount: 186,
missCount: 0,
),
// 100.0%.
@@ -478,15 +478,15 @@
hitCount: 0,
missCount: 0,
),
- // 99.34556835965287%.
+ // 99.14393499709809%.
"package:front_end/src/kernel/body_builder.dart": (
- hitCount: 6983,
- missCount: 46,
+ hitCount: 6833,
+ missCount: 59,
),
- // 100.0%.
+ // 98.26086956521739%.
"package:front_end/src/kernel/body_builder_context.dart": (
- hitCount: 345,
- missCount: 0,
+ hitCount: 339,
+ missCount: 6,
),
// 81.57894736842105%.
"package:front_end/src/kernel/collections.dart": (
@@ -598,10 +598,10 @@
hitCount: 1,
missCount: 0,
),
- // 100.0%.
+ // 99.12126537785588%.
"package:front_end/src/kernel/internal_ast.dart": (
- hitCount: 569,
- missCount: 0,
+ hitCount: 564,
+ missCount: 5,
),
// 100.0%.
"package:front_end/src/kernel/invalid_type.dart": (
@@ -618,9 +618,9 @@
hitCount: 285,
missCount: 0,
),
- // 99.90521327014218%.
+ // 99.90566037735849%.
"package:front_end/src/kernel/kernel_target.dart": (
- hitCount: 1054,
+ hitCount: 1059,
missCount: 1,
),
// 100.0%.
@@ -790,7 +790,7 @@
),
// 100.0%.
"package:front_end/src/source/source_builder_factory.dart": (
- hitCount: 1163,
+ hitCount: 1167,
missCount: 0,
),
// 98.13664596273291%.
@@ -808,14 +808,14 @@
hitCount: 741,
missCount: 4,
),
- // 98.31271091113611%.
+ // 98.31649831649831%.
"package:front_end/src/source/source_constructor_builder.dart": (
- hitCount: 874,
+ hitCount: 876,
missCount: 15,
),
- // 99.81203007518798%.
+ // 99.81024667931689%.
"package:front_end/src/source/source_enum_builder.dart": (
- hitCount: 531,
+ hitCount: 526,
missCount: 1,
),
// 100.0%.
@@ -831,7 +831,7 @@
),
// 100.0%.
"package:front_end/src/source/source_factory_builder.dart": (
- hitCount: 576,
+ hitCount: 583,
missCount: 0,
),
// 100.0%.
@@ -849,9 +849,9 @@
hitCount: 1419,
missCount: 2,
),
- // 99.89258861439313%.
+ // 99.89253089736701%.
"package:front_end/src/source/source_loader.dart": (
- hitCount: 1860,
+ hitCount: 1859,
missCount: 2,
),
// 100.0%.
@@ -874,9 +874,9 @@
hitCount: 20,
missCount: 0,
),
- // 99.09909909909909%.
+ // 99.00497512437812%.
"package:front_end/src/source/type_parameter_scope_builder.dart": (
- hitCount: 220,
+ hitCount: 199,
missCount: 2,
),
// 100.0%.
@@ -909,9 +909,9 @@
hitCount: 166,
missCount: 0,
),
- // 99.51504600845561%.
+ // 99.51564828614009%.
"package:front_end/src/type_inference/inference_visitor.dart": (
- hitCount: 8003,
+ hitCount: 8013,
missCount: 39,
),
// 99.875%.
@@ -961,7 +961,7 @@
),
// 100.0%.
"package:front_end/src/type_inference/type_inferrer.dart": (
- hitCount: 88,
+ hitCount: 96,
missCount: 0,
),
// 100.0%.
diff --git a/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.expect b/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.expect
index 3d66491..f365b95 100644
--- a/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.expect
+++ b/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.expect
@@ -16,6 +16,11 @@
// const newConst1 = new ExtensionType1(0); /* Error */
// ^^^
//
+// pkg/front_end/testcases/extension_types/const_constructor_access.dart:9:23: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// Try using a constructor or factory that is 'const'.
+// const newConst1 = new ExtensionType1(0); /* Error */
+// ^
+//
// pkg/front_end/testcases/extension_types/const_constructor_access.dart:13:31: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
// Try using a constructor or factory that is 'const'.
// const implicitConstAliased1 = Typedef1(0); /* Error */
@@ -30,6 +35,11 @@
// const newConstAliased1 = new Typedef1(0); /* Error */
// ^^^
//
+// pkg/front_end/testcases/extension_types/const_constructor_access.dart:15:30: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// Try using a constructor or factory that is 'const'.
+// const newConstAliased1 = new Typedef1(0); /* Error */
+// ^
+//
// pkg/front_end/testcases/extension_types/const_constructor_access.dart:21:19: Error: New expression is not a constant expression.
// const newConst2 = new ExtensionType2(0); /* Error */
// ^^^
@@ -38,16 +48,6 @@
// const newConstAliased2 = new Typedef2(0); /* Error */
// ^^^
//
-// pkg/front_end/testcases/extension_types/const_constructor_access.dart:9:23: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
-// Try using a constructor or factory that is 'const'.
-// const newConst1 = new ExtensionType1(0); /* Error */
-// ^
-//
-// pkg/front_end/testcases/extension_types/const_constructor_access.dart:15:30: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
-// Try using a constructor or factory that is 'const'.
-// const newConstAliased1 = new Typedef1(0); /* Error */
-// ^
-//
import self as self;
import "dart:core" as core;
diff --git a/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.modular.expect b/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.modular.expect
index 3d66491..f365b95 100644
--- a/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.modular.expect
@@ -16,6 +16,11 @@
// const newConst1 = new ExtensionType1(0); /* Error */
// ^^^
//
+// pkg/front_end/testcases/extension_types/const_constructor_access.dart:9:23: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// Try using a constructor or factory that is 'const'.
+// const newConst1 = new ExtensionType1(0); /* Error */
+// ^
+//
// pkg/front_end/testcases/extension_types/const_constructor_access.dart:13:31: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
// Try using a constructor or factory that is 'const'.
// const implicitConstAliased1 = Typedef1(0); /* Error */
@@ -30,6 +35,11 @@
// const newConstAliased1 = new Typedef1(0); /* Error */
// ^^^
//
+// pkg/front_end/testcases/extension_types/const_constructor_access.dart:15:30: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// Try using a constructor or factory that is 'const'.
+// const newConstAliased1 = new Typedef1(0); /* Error */
+// ^
+//
// pkg/front_end/testcases/extension_types/const_constructor_access.dart:21:19: Error: New expression is not a constant expression.
// const newConst2 = new ExtensionType2(0); /* Error */
// ^^^
@@ -38,16 +48,6 @@
// const newConstAliased2 = new Typedef2(0); /* Error */
// ^^^
//
-// pkg/front_end/testcases/extension_types/const_constructor_access.dart:9:23: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
-// Try using a constructor or factory that is 'const'.
-// const newConst1 = new ExtensionType1(0); /* Error */
-// ^
-//
-// pkg/front_end/testcases/extension_types/const_constructor_access.dart:15:30: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
-// Try using a constructor or factory that is 'const'.
-// const newConstAliased1 = new Typedef1(0); /* Error */
-// ^
-//
import self as self;
import "dart:core" as core;
diff --git a/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.outline.expect b/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.outline.expect
index a0f936d..d17b68f 100644
--- a/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.outline.expect
+++ b/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.outline.expect
@@ -16,6 +16,11 @@
// const newConst1 = new ExtensionType1(0); /* Error */
// ^^^
//
+// pkg/front_end/testcases/extension_types/const_constructor_access.dart:9:23: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// Try using a constructor or factory that is 'const'.
+// const newConst1 = new ExtensionType1(0); /* Error */
+// ^
+//
// pkg/front_end/testcases/extension_types/const_constructor_access.dart:13:31: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
// Try using a constructor or factory that is 'const'.
// const implicitConstAliased1 = Typedef1(0); /* Error */
@@ -30,6 +35,11 @@
// const newConstAliased1 = new Typedef1(0); /* Error */
// ^^^
//
+// pkg/front_end/testcases/extension_types/const_constructor_access.dart:15:30: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// Try using a constructor or factory that is 'const'.
+// const newConstAliased1 = new Typedef1(0); /* Error */
+// ^
+//
// pkg/front_end/testcases/extension_types/const_constructor_access.dart:21:19: Error: New expression is not a constant expression.
// const newConst2 = new ExtensionType2(0); /* Error */
// ^^^
@@ -38,16 +48,6 @@
// const newConstAliased2 = new Typedef2(0); /* Error */
// ^^^
//
-// pkg/front_end/testcases/extension_types/const_constructor_access.dart:9:23: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
-// Try using a constructor or factory that is 'const'.
-// const newConst1 = new ExtensionType1(0); /* Error */
-// ^
-//
-// pkg/front_end/testcases/extension_types/const_constructor_access.dart:15:30: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
-// Try using a constructor or factory that is 'const'.
-// const newConstAliased1 = new Typedef1(0); /* Error */
-// ^
-//
import self as self;
import "dart:core" as core;
diff --git a/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.transformed.expect
index 3d66491..f365b95 100644
--- a/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extension_types/const_constructor_access.dart.strong.transformed.expect
@@ -16,6 +16,11 @@
// const newConst1 = new ExtensionType1(0); /* Error */
// ^^^
//
+// pkg/front_end/testcases/extension_types/const_constructor_access.dart:9:23: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// Try using a constructor or factory that is 'const'.
+// const newConst1 = new ExtensionType1(0); /* Error */
+// ^
+//
// pkg/front_end/testcases/extension_types/const_constructor_access.dart:13:31: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
// Try using a constructor or factory that is 'const'.
// const implicitConstAliased1 = Typedef1(0); /* Error */
@@ -30,6 +35,11 @@
// const newConstAliased1 = new Typedef1(0); /* Error */
// ^^^
//
+// pkg/front_end/testcases/extension_types/const_constructor_access.dart:15:30: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// Try using a constructor or factory that is 'const'.
+// const newConstAliased1 = new Typedef1(0); /* Error */
+// ^
+//
// pkg/front_end/testcases/extension_types/const_constructor_access.dart:21:19: Error: New expression is not a constant expression.
// const newConst2 = new ExtensionType2(0); /* Error */
// ^^^
@@ -38,16 +48,6 @@
// const newConstAliased2 = new Typedef2(0); /* Error */
// ^^^
//
-// pkg/front_end/testcases/extension_types/const_constructor_access.dart:9:23: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
-// Try using a constructor or factory that is 'const'.
-// const newConst1 = new ExtensionType1(0); /* Error */
-// ^
-//
-// pkg/front_end/testcases/extension_types/const_constructor_access.dart:15:30: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
-// Try using a constructor or factory that is 'const'.
-// const newConstAliased1 = new Typedef1(0); /* Error */
-// ^
-//
import self as self;
import "dart:core" as core;
diff --git a/pkg/front_end/testcases/general/bounds_instances.dart.strong.expect b/pkg/front_end/testcases/general/bounds_instances.dart.strong.expect
index 10849bb..0e07d33a 100644
--- a/pkg/front_end/testcases/general/bounds_instances.dart.strong.expect
+++ b/pkg/front_end/testcases/general/bounds_instances.dart.strong.expect
@@ -94,6 +94,16 @@
// class G<X extends Class<X>> {}
// ^
//
+// pkg/front_end/testcases/general/bounds_instances.dart:16:7: Error: Inferred type argument 'Class<Object?>' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'F'.
+// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// new F(); // Error
+// ^
+// pkg/front_end/testcases/general/bounds_instances.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends Class<X>> = Class1;
+// ^
+//
// pkg/front_end/testcases/general/bounds_instances.dart:24:7: Error: Inferred type argument 'Class<Object?>' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'G'.
// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
// - 'Object' is from 'dart:core'.
@@ -140,16 +150,6 @@
// G<int>.new; // Error
// ^
//
-// pkg/front_end/testcases/general/bounds_instances.dart:16:7: Error: Inferred type argument 'Class<Object?>' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'F'.
-// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// new F(); // Error
-// ^
-// pkg/front_end/testcases/general/bounds_instances.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef F<X extends Class<X>> = Class1;
-// ^
-//
// pkg/front_end/testcases/general/bounds_instances.dart:39:3: Error: Type argument 'Object' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'F'.
// - 'Object' is from 'dart:core'.
// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
diff --git a/pkg/front_end/testcases/general/bounds_instances.dart.strong.modular.expect b/pkg/front_end/testcases/general/bounds_instances.dart.strong.modular.expect
index 10849bb..0e07d33a 100644
--- a/pkg/front_end/testcases/general/bounds_instances.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/general/bounds_instances.dart.strong.modular.expect
@@ -94,6 +94,16 @@
// class G<X extends Class<X>> {}
// ^
//
+// pkg/front_end/testcases/general/bounds_instances.dart:16:7: Error: Inferred type argument 'Class<Object?>' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'F'.
+// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// new F(); // Error
+// ^
+// pkg/front_end/testcases/general/bounds_instances.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends Class<X>> = Class1;
+// ^
+//
// pkg/front_end/testcases/general/bounds_instances.dart:24:7: Error: Inferred type argument 'Class<Object?>' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'G'.
// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
// - 'Object' is from 'dart:core'.
@@ -140,16 +150,6 @@
// G<int>.new; // Error
// ^
//
-// pkg/front_end/testcases/general/bounds_instances.dart:16:7: Error: Inferred type argument 'Class<Object?>' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'F'.
-// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// new F(); // Error
-// ^
-// pkg/front_end/testcases/general/bounds_instances.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef F<X extends Class<X>> = Class1;
-// ^
-//
// pkg/front_end/testcases/general/bounds_instances.dart:39:3: Error: Type argument 'Object' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'F'.
// - 'Object' is from 'dart:core'.
// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
diff --git a/pkg/front_end/testcases/general/bounds_instances.dart.strong.transformed.expect b/pkg/front_end/testcases/general/bounds_instances.dart.strong.transformed.expect
index 10849bb..0e07d33a 100644
--- a/pkg/front_end/testcases/general/bounds_instances.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/bounds_instances.dart.strong.transformed.expect
@@ -94,6 +94,16 @@
// class G<X extends Class<X>> {}
// ^
//
+// pkg/front_end/testcases/general/bounds_instances.dart:16:7: Error: Inferred type argument 'Class<Object?>' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'F'.
+// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// new F(); // Error
+// ^
+// pkg/front_end/testcases/general/bounds_instances.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef F<X extends Class<X>> = Class1;
+// ^
+//
// pkg/front_end/testcases/general/bounds_instances.dart:24:7: Error: Inferred type argument 'Class<Object?>' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'G'.
// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
// - 'Object' is from 'dart:core'.
@@ -140,16 +150,6 @@
// G<int>.new; // Error
// ^
//
-// pkg/front_end/testcases/general/bounds_instances.dart:16:7: Error: Inferred type argument 'Class<Object?>' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'F'.
-// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// new F(); // Error
-// ^
-// pkg/front_end/testcases/general/bounds_instances.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef F<X extends Class<X>> = Class1;
-// ^
-//
// pkg/front_end/testcases/general/bounds_instances.dart:39:3: Error: Type argument 'Object' doesn't conform to the bound 'Class<X>' of the type variable 'X' on 'F'.
// - 'Object' is from 'dart:core'.
// - 'Class' is from 'pkg/front_end/testcases/general/bounds_instances.dart'.
diff --git a/pkg/front_end/testcases/general/constructor_inference_interdependence.dart b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart
new file mode 100644
index 0000000..cd9eabd
--- /dev/null
+++ b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2024, 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.
+
+class C {}
+
+sealed class B<X> {
+ final C? Function()? foo;
+ const B({required this.foo});
+
+ const factory B.redir({C? Function()? foo}) = A;
+}
+
+mixin M {}
+
+final class A<X> extends B<X> with M {
+ const A({super.foo = null}) : super();
+}
+
+main() {
+ print(new A());
+}
diff --git a/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.expect b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.expect
new file mode 100644
index 0000000..0db728b
--- /dev/null
+++ b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ synthetic constructor •() → self::C
+ : super core::Object::•()
+ ;
+}
+abstract sealed class B<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
+ final field () →? self::C? foo;
+ const constructor •({required () →? self::C? foo}) → self::B<self::B::X%>
+ : self::B::foo = foo, super core::Object::•()
+ ;
+ static factory redir<X extends core::Object? = dynamic>({() →? self::C? foo = #C1}) → self::B<self::B::redir::X%> /* redirection-target: self::A::•<self::B::redir::X%>*/
+ return new self::A::•<self::B::redir::X%>(foo: foo);
+}
+abstract class M extends core::Object /*isMixinDeclaration*/ {
+}
+abstract sealed class _A&B&M<X extends core::Object? = dynamic> = self::B<self::_A&B&M::X%> with self::M /*isAnonymousMixin,hasConstConstructor*/ {
+ const synthetic constructor •({required () →? self::C? foo}) → self::_A&B&M<self::_A&B&M::X%>
+ : super self::B::•(foo: foo)
+ ;
+}
+final class A<X extends core::Object? = dynamic> extends self::_A&B&M<self::A::X%> /*hasConstConstructor*/ {
+ const constructor •({has-declared-initializer () →? self::C? foo = #C1}) → self::A<self::A::X%>
+ : super self::_A&B&M::•(foo: foo)
+ ;
+}
+static method main() → dynamic {
+ core::print(new self::A::•<dynamic>());
+}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.modular.expect b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.modular.expect
new file mode 100644
index 0000000..0db728b
--- /dev/null
+++ b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.modular.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ synthetic constructor •() → self::C
+ : super core::Object::•()
+ ;
+}
+abstract sealed class B<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
+ final field () →? self::C? foo;
+ const constructor •({required () →? self::C? foo}) → self::B<self::B::X%>
+ : self::B::foo = foo, super core::Object::•()
+ ;
+ static factory redir<X extends core::Object? = dynamic>({() →? self::C? foo = #C1}) → self::B<self::B::redir::X%> /* redirection-target: self::A::•<self::B::redir::X%>*/
+ return new self::A::•<self::B::redir::X%>(foo: foo);
+}
+abstract class M extends core::Object /*isMixinDeclaration*/ {
+}
+abstract sealed class _A&B&M<X extends core::Object? = dynamic> = self::B<self::_A&B&M::X%> with self::M /*isAnonymousMixin,hasConstConstructor*/ {
+ const synthetic constructor •({required () →? self::C? foo}) → self::_A&B&M<self::_A&B&M::X%>
+ : super self::B::•(foo: foo)
+ ;
+}
+final class A<X extends core::Object? = dynamic> extends self::_A&B&M<self::A::X%> /*hasConstConstructor*/ {
+ const constructor •({has-declared-initializer () →? self::C? foo = #C1}) → self::A<self::A::X%>
+ : super self::_A&B&M::•(foo: foo)
+ ;
+}
+static method main() → dynamic {
+ core::print(new self::A::•<dynamic>());
+}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.outline.expect b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.outline.expect
new file mode 100644
index 0000000..af6da57
--- /dev/null
+++ b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.outline.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ synthetic constructor •() → self::C
+ ;
+}
+abstract sealed class B<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
+ final field () →? self::C? foo;
+ const constructor •({required () →? self::C? foo}) → self::B<self::B::X%>
+ : self::B::foo = foo, super core::Object::•()
+ ;
+ static factory redir<X extends core::Object? = dynamic>({() →? self::C? foo = null}) → self::B<self::B::redir::X%> /* redirection-target: self::A::•<self::B::redir::X%>*/
+ return new self::A::•<self::B::redir::X%>(foo: foo);
+}
+abstract class M extends core::Object /*isMixinDeclaration*/ {
+}
+abstract sealed class _A&B&M<X extends core::Object? = dynamic> = self::B<self::_A&B&M::X%> with self::M /*isAnonymousMixin,hasConstConstructor*/ {
+ const synthetic constructor •({required () →? self::C? foo}) → self::_A&B&M<self::_A&B&M::X%>
+ : super self::B::•(foo: foo)
+ ;
+}
+final class A<X extends core::Object? = dynamic> extends self::_A&B&M<self::A::X%> /*hasConstConstructor*/ {
+ const constructor •({has-declared-initializer () →? self::C? foo = null}) → self::A<self::A::X%>
+ : super self::_A&B&M::•(foo: foo)
+ ;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.transformed.expect b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.transformed.expect
new file mode 100644
index 0000000..b0993ad
--- /dev/null
+++ b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.strong.transformed.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ synthetic constructor •() → self::C
+ : super core::Object::•()
+ ;
+}
+abstract sealed class B<X extends core::Object? = dynamic> extends core::Object /*hasConstConstructor*/ {
+ final field () →? self::C? foo;
+ const constructor •({required () →? self::C? foo}) → self::B<self::B::X%>
+ : self::B::foo = foo, super core::Object::•()
+ ;
+ static factory redir<X extends core::Object? = dynamic>({() →? self::C? foo = #C1}) → self::B<self::B::redir::X%> /* redirection-target: self::A::•<self::B::redir::X%>*/
+ return new self::A::•<self::B::redir::X%>(foo: foo);
+}
+abstract class M extends core::Object /*isMixinDeclaration*/ {
+}
+abstract sealed class _A&B&M<X extends core::Object? = dynamic> extends self::B<self::_A&B&M::X%> implements self::M /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/ {
+ const synthetic constructor •({required () →? self::C? foo}) → self::_A&B&M<self::_A&B&M::X%>
+ : super self::B::•(foo: foo)
+ ;
+}
+final class A<X extends core::Object? = dynamic> extends self::_A&B&M<self::A::X%> /*hasConstConstructor*/ {
+ const constructor •({has-declared-initializer () →? self::C? foo = #C1}) → self::A<self::A::X%>
+ : super self::_A&B&M::•(foo: foo)
+ ;
+}
+static method main() → dynamic {
+ core::print(new self::A::•<dynamic>());
+}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.textual_outline.expect b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.textual_outline.expect
new file mode 100644
index 0000000..dc73668
--- /dev/null
+++ b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.textual_outline.expect
@@ -0,0 +1,15 @@
+class C {}
+
+sealed class B<X> {
+ final C? Function()? foo;
+ const B({required this.foo});
+ const factory B.redir({C? Function()? foo}) = A;
+}
+
+mixin M {}
+
+final class A<X> extends B<X> with M {
+ const A({super.foo = null}) : super();
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..8c1259b
--- /dev/null
+++ b/pkg/front_end/testcases/general/constructor_inference_interdependence.dart.textual_outline_modelled.expect
@@ -0,0 +1,15 @@
+class C {}
+
+final class A<X> extends B<X> with M {
+ const A({super.foo = null}) : super();
+}
+
+main() {}
+
+mixin M {}
+
+sealed class B<X> {
+ const B({required this.foo});
+ const factory B.redir({C? Function()? foo}) = A;
+ final C? Function()? foo;
+}
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart
new file mode 100644
index 0000000..cad4e75
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2024, 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.
+
+class C {
+ List<A> field;
+ C({this.field = const [A.redir()]});
+}
+
+abstract class A {
+ const factory A.redir() = B;
+}
+
+class B<X> implements A {
+ const B();
+}
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.expect
new file mode 100644
index 0000000..2d6194a
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A> field;
+ constructor •({core::List<self::A> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+}
+abstract class A extends core::Object {
+ static factory redir() → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>();
+}
+class B<X extends core::Object? = dynamic> extends core::Object implements self::A /*hasConstConstructor*/ {
+ const constructor •() → self::B<self::B::X%>
+ : super core::Object::•()
+ ;
+}
+
+constants {
+ #C1 = self::B<dynamic> {}
+ #C2 = <self::A>[#C1]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///redirecting_constructors_declaration_order.dart:
+- B. (from org-dartlang-testcase:///redirecting_constructors_declaration_order.dart:15:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.modular.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.modular.expect
new file mode 100644
index 0000000..2d6194a
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.modular.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A> field;
+ constructor •({core::List<self::A> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+}
+abstract class A extends core::Object {
+ static factory redir() → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>();
+}
+class B<X extends core::Object? = dynamic> extends core::Object implements self::A /*hasConstConstructor*/ {
+ const constructor •() → self::B<self::B::X%>
+ : super core::Object::•()
+ ;
+}
+
+constants {
+ #C1 = self::B<dynamic> {}
+ #C2 = <self::A>[#C1]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///redirecting_constructors_declaration_order.dart:
+- B. (from org-dartlang-testcase:///redirecting_constructors_declaration_order.dart:15:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.outline.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.outline.expect
new file mode 100644
index 0000000..b288ecc
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.outline.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A> field;
+ constructor •({core::List<self::A> field = const <self::A>[const self::B::•<dynamic>()]}) → self::C
+ ;
+}
+abstract class A extends core::Object {
+ static factory redir() → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>();
+}
+class B<X extends core::Object? = dynamic> extends core::Object implements self::A /*hasConstConstructor*/ {
+ const constructor •() → self::B<self::B::X%>
+ : super core::Object::•()
+ ;
+}
+
+
+Extra constant evaluation status:
+Evaluated: ListLiteral @ org-dartlang-testcase:///redirecting_constructors_declaration_order.dart:7:19 -> ListConstant(const <A>[const B<dynamic>{}])
+Extra constant evaluation: evaluated: 2, effectively constant: 1
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.transformed.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.transformed.expect
new file mode 100644
index 0000000..2d6194a
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.strong.transformed.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A> field;
+ constructor •({core::List<self::A> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+}
+abstract class A extends core::Object {
+ static factory redir() → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>();
+}
+class B<X extends core::Object? = dynamic> extends core::Object implements self::A /*hasConstConstructor*/ {
+ const constructor •() → self::B<self::B::X%>
+ : super core::Object::•()
+ ;
+}
+
+constants {
+ #C1 = self::B<dynamic> {}
+ #C2 = <self::A>[#C1]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///redirecting_constructors_declaration_order.dart:
+- B. (from org-dartlang-testcase:///redirecting_constructors_declaration_order.dart:15:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.textual_outline.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.textual_outline.expect
new file mode 100644
index 0000000..3ce5bdc
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.textual_outline.expect
@@ -0,0 +1,12 @@
+class C {
+ List<A> field;
+ C({this.field = const [A.redir()]});
+}
+
+abstract class A {
+ const factory A.redir() = B;
+}
+
+class B<X> implements A {
+ const B();
+}
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..0d599f9
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order.dart.textual_outline_modelled.expect
@@ -0,0 +1,12 @@
+abstract class A {
+ const factory A.redir() = B;
+}
+
+class B<X> implements A {
+ const B();
+}
+
+class C {
+ C({this.field = const [A.redir()]});
+ List<A> field;
+}
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart
new file mode 100644
index 0000000..4d57560
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2024, 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.
+
+class C {
+ List<A> field;
+ C.named1({this.field = const [A.redir1(0, s: "")]});
+ C.named2({this.field = const [A.redir1(s: "", 0)]});
+}
+
+abstract class A {
+ const factory A.redir1(int x, {required String s}) = B;
+ const factory A.redir2(int x, {required String s}) = B;
+}
+
+class B<X> implements A {
+ const B(int x, {required String s});
+}
+
+test() {
+ new A.redir2(0, s: "");
+ new A.redir2(s: "", 0);
+}
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.expect
new file mode 100644
index 0000000..8db2dcf
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A> field;
+ constructor named1({core::List<self::A> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+ constructor named2({core::List<self::A> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+}
+abstract class A extends core::Object {
+ static factory redir1(core::int x, {required core::String s}) → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>(x, s: s);
+ static factory redir2(core::int x, {required core::String s}) → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>(x, s: s);
+}
+class B<X extends core::Object? = dynamic> extends core::Object implements self::A /*hasConstConstructor*/ {
+ const constructor •(core::int x, {required core::String s}) → self::B<self::B::X%>
+ : super core::Object::•()
+ ;
+}
+static method test() → dynamic {
+ new self::B::•<dynamic>(0, s: "");
+ let final core::String #t1 = "" in new self::B::•<dynamic>(0, s: #t1);
+}
+
+constants {
+ #C1 = self::B<dynamic> {}
+ #C2 = <self::A>[#C1]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///redirecting_constructors_declaration_order_2.dart:
+- B. (from org-dartlang-testcase:///redirecting_constructors_declaration_order_2.dart:17:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.modular.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.modular.expect
new file mode 100644
index 0000000..8db2dcf
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.modular.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A> field;
+ constructor named1({core::List<self::A> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+ constructor named2({core::List<self::A> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+}
+abstract class A extends core::Object {
+ static factory redir1(core::int x, {required core::String s}) → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>(x, s: s);
+ static factory redir2(core::int x, {required core::String s}) → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>(x, s: s);
+}
+class B<X extends core::Object? = dynamic> extends core::Object implements self::A /*hasConstConstructor*/ {
+ const constructor •(core::int x, {required core::String s}) → self::B<self::B::X%>
+ : super core::Object::•()
+ ;
+}
+static method test() → dynamic {
+ new self::B::•<dynamic>(0, s: "");
+ let final core::String #t1 = "" in new self::B::•<dynamic>(0, s: #t1);
+}
+
+constants {
+ #C1 = self::B<dynamic> {}
+ #C2 = <self::A>[#C1]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///redirecting_constructors_declaration_order_2.dart:
+- B. (from org-dartlang-testcase:///redirecting_constructors_declaration_order_2.dart:17:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.outline.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.outline.expect
new file mode 100644
index 0000000..f58b613
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.outline.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A> field;
+ constructor named1({core::List<self::A> field = const <self::A>[const self::B::•<dynamic>(0, s: "")]}) → self::C
+ ;
+ constructor named2({core::List<self::A> field = const <self::A>[const self::B::•<dynamic>(0, s: "")]}) → self::C
+ ;
+}
+abstract class A extends core::Object {
+ static factory redir1(core::int x, {required core::String s}) → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>(x, s: s);
+ static factory redir2(core::int x, {required core::String s}) → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>(x, s: s);
+}
+class B<X extends core::Object? = dynamic> extends core::Object implements self::A /*hasConstConstructor*/ {
+ const constructor •(core::int x, {required core::String s}) → self::B<self::B::X%>
+ : super core::Object::•()
+ ;
+}
+static method test() → dynamic
+ ;
+
+
+Extra constant evaluation status:
+Evaluated: ListLiteral @ org-dartlang-testcase:///redirecting_constructors_declaration_order_2.dart:7:26 -> ListConstant(const <A>[const B<dynamic>{}])
+Evaluated: ListLiteral @ org-dartlang-testcase:///redirecting_constructors_declaration_order_2.dart:8:26 -> ListConstant(const <A>[const B<dynamic>{}])
+Extra constant evaluation: evaluated: 8, effectively constant: 2
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.transformed.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.transformed.expect
new file mode 100644
index 0000000..105c064
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.strong.transformed.expect
@@ -0,0 +1,43 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A> field;
+ constructor named1({core::List<self::A> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+ constructor named2({core::List<self::A> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+}
+abstract class A extends core::Object {
+ static factory redir1(core::int x, {required core::String s}) → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>(x, s: s);
+ static factory redir2(core::int x, {required core::String s}) → self::A /* redirection-target: self::B::•<dynamic>*/
+ return new self::B::•<dynamic>(x, s: s);
+}
+class B<X extends core::Object? = dynamic> extends core::Object implements self::A /*hasConstConstructor*/ {
+ const constructor •(core::int x, {required core::String s}) → self::B<self::B::X%>
+ : super core::Object::•()
+ ;
+}
+static method test() → dynamic {
+ new self::B::•<dynamic>(0, s: "");
+ let final core::String #t1 = "" in new self::B::•<dynamic>(0, s: #t1);
+}
+
+constants {
+ #C1 = self::B<dynamic> {}
+ #C2 = <self::A>[#C1]
+}
+
+Extra constant evaluation status:
+Evaluated: VariableGet @ org-dartlang-testcase:///redirecting_constructors_declaration_order_2.dart:22:19 -> StringConstant("")
+Extra constant evaluation: evaluated: 12, effectively constant: 1
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///redirecting_constructors_declaration_order_2.dart:
+- B. (from org-dartlang-testcase:///redirecting_constructors_declaration_order_2.dart:17:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.textual_outline.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.textual_outline.expect
new file mode 100644
index 0000000..c262d64
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.textual_outline.expect
@@ -0,0 +1,16 @@
+class C {
+ List<A> field;
+ C.named1({this.field = const [A.redir1(0, s: "")]});
+ C.named2({this.field = const [A.redir1(s: "", 0)]});
+}
+
+abstract class A {
+ const factory A.redir1(int x, {required String s}) = B;
+ const factory A.redir2(int x, {required String s}) = B;
+}
+
+class B<X> implements A {
+ const B(int x, {required String s});
+}
+
+test() {}
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..606c5ac
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_2.dart.textual_outline_modelled.expect
@@ -0,0 +1,16 @@
+abstract class A {
+ const factory A.redir1(int x, {required String s}) = B;
+ const factory A.redir2(int x, {required String s}) = B;
+}
+
+class B<X> implements A {
+ const B(int x, {required String s});
+}
+
+class C {
+ C.named1({this.field = const [A.redir1(0, s: "")]});
+ C.named2({this.field = const [A.redir1(s: "", 0)]});
+ List<A> field;
+}
+
+test() {}
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart
new file mode 100644
index 0000000..757e8d6
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2024, 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.
+
+class C {
+ List<A<bool>> field;
+ C.named1({this.field = const [A.redir1(0, s: "")]});
+ C.named2({this.field = const [A.redir1(s: "", 0)]});
+}
+
+abstract class A<X> {
+ const factory A.redir1(int x, {required String s}) = B;
+ const factory A.redir2(int x, {required String s}) = B;
+}
+
+class B<Y> implements A<Y> {
+ const B(int x, {required String s});
+}
+
+test() {
+ A<String> foo1 = new A.redir2(0, s: "");
+ A<num> foo2 = new A.redir2(s: "", 0);
+}
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.expect
new file mode 100644
index 0000000..61b3f85
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A<core::bool>> field;
+ constructor named1({core::List<self::A<core::bool>> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+ constructor named2({core::List<self::A<core::bool>> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+}
+abstract class A<X extends core::Object? = dynamic> extends core::Object {
+ static factory redir1<X extends core::Object? = dynamic>(core::int x, {required core::String s}) → self::A<self::A::redir1::X%> /* redirection-target: self::B::•<self::A::redir1::X%>*/
+ return new self::B::•<self::A::redir1::X%>(x, s: s);
+ static factory redir2<X extends core::Object? = dynamic>(core::int x, {required core::String s}) → self::A<self::A::redir2::X%> /* redirection-target: self::B::•<self::A::redir2::X%>*/
+ return new self::B::•<self::A::redir2::X%>(x, s: s);
+}
+class B<Y extends core::Object? = dynamic> extends core::Object implements self::A<self::B::Y%> /*hasConstConstructor*/ {
+ const constructor •(core::int x, {required core::String s}) → self::B<self::B::Y%>
+ : super core::Object::•()
+ ;
+}
+static method test() → dynamic {
+ self::A<core::String> foo1 = new self::B::•<core::String>(0, s: "");
+ self::A<core::num> foo2 = let final core::String #t1 = "" in new self::B::•<core::num>(0, s: #t1);
+}
+
+constants {
+ #C1 = self::B<core::bool> {}
+ #C2 = <self::A<core::bool>>[#C1]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///redirecting_constructors_declaration_order_3.dart:
+- B. (from org-dartlang-testcase:///redirecting_constructors_declaration_order_3.dart:17:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.modular.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.modular.expect
new file mode 100644
index 0000000..61b3f85
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.modular.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A<core::bool>> field;
+ constructor named1({core::List<self::A<core::bool>> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+ constructor named2({core::List<self::A<core::bool>> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+}
+abstract class A<X extends core::Object? = dynamic> extends core::Object {
+ static factory redir1<X extends core::Object? = dynamic>(core::int x, {required core::String s}) → self::A<self::A::redir1::X%> /* redirection-target: self::B::•<self::A::redir1::X%>*/
+ return new self::B::•<self::A::redir1::X%>(x, s: s);
+ static factory redir2<X extends core::Object? = dynamic>(core::int x, {required core::String s}) → self::A<self::A::redir2::X%> /* redirection-target: self::B::•<self::A::redir2::X%>*/
+ return new self::B::•<self::A::redir2::X%>(x, s: s);
+}
+class B<Y extends core::Object? = dynamic> extends core::Object implements self::A<self::B::Y%> /*hasConstConstructor*/ {
+ const constructor •(core::int x, {required core::String s}) → self::B<self::B::Y%>
+ : super core::Object::•()
+ ;
+}
+static method test() → dynamic {
+ self::A<core::String> foo1 = new self::B::•<core::String>(0, s: "");
+ self::A<core::num> foo2 = let final core::String #t1 = "" in new self::B::•<core::num>(0, s: #t1);
+}
+
+constants {
+ #C1 = self::B<core::bool> {}
+ #C2 = <self::A<core::bool>>[#C1]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///redirecting_constructors_declaration_order_3.dart:
+- B. (from org-dartlang-testcase:///redirecting_constructors_declaration_order_3.dart:17:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.outline.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.outline.expect
new file mode 100644
index 0000000..51200e0
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.outline.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A<core::bool>> field;
+ constructor named1({core::List<self::A<core::bool>> field = const <self::A<core::bool>>[const self::B::•<core::bool>(0, s: "")]}) → self::C
+ ;
+ constructor named2({core::List<self::A<core::bool>> field = const <self::A<core::bool>>[const self::B::•<core::bool>(0, s: "")]}) → self::C
+ ;
+}
+abstract class A<X extends core::Object? = dynamic> extends core::Object {
+ static factory redir1<X extends core::Object? = dynamic>(core::int x, {required core::String s}) → self::A<self::A::redir1::X%> /* redirection-target: self::B::•<self::A::redir1::X%>*/
+ return new self::B::•<self::A::redir1::X%>(x, s: s);
+ static factory redir2<X extends core::Object? = dynamic>(core::int x, {required core::String s}) → self::A<self::A::redir2::X%> /* redirection-target: self::B::•<self::A::redir2::X%>*/
+ return new self::B::•<self::A::redir2::X%>(x, s: s);
+}
+class B<Y extends core::Object? = dynamic> extends core::Object implements self::A<self::B::Y%> /*hasConstConstructor*/ {
+ const constructor •(core::int x, {required core::String s}) → self::B<self::B::Y%>
+ : super core::Object::•()
+ ;
+}
+static method test() → dynamic
+ ;
+
+
+Extra constant evaluation status:
+Evaluated: ListLiteral @ org-dartlang-testcase:///redirecting_constructors_declaration_order_3.dart:7:26 -> ListConstant(const <A<bool>>[const B<bool>{}])
+Evaluated: ListLiteral @ org-dartlang-testcase:///redirecting_constructors_declaration_order_3.dart:8:26 -> ListConstant(const <A<bool>>[const B<bool>{}])
+Extra constant evaluation: evaluated: 8, effectively constant: 2
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.transformed.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.transformed.expect
new file mode 100644
index 0000000..c1da56f
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.strong.transformed.expect
@@ -0,0 +1,43 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+ field core::List<self::A<core::bool>> field;
+ constructor named1({core::List<self::A<core::bool>> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+ constructor named2({core::List<self::A<core::bool>> field = #C2}) → self::C
+ : self::C::field = field, super core::Object::•()
+ ;
+}
+abstract class A<X extends core::Object? = dynamic> extends core::Object {
+ static factory redir1<X extends core::Object? = dynamic>(core::int x, {required core::String s}) → self::A<self::A::redir1::X%> /* redirection-target: self::B::•<self::A::redir1::X%>*/
+ return new self::B::•<self::A::redir1::X%>(x, s: s);
+ static factory redir2<X extends core::Object? = dynamic>(core::int x, {required core::String s}) → self::A<self::A::redir2::X%> /* redirection-target: self::B::•<self::A::redir2::X%>*/
+ return new self::B::•<self::A::redir2::X%>(x, s: s);
+}
+class B<Y extends core::Object? = dynamic> extends core::Object implements self::A<self::B::Y%> /*hasConstConstructor*/ {
+ const constructor •(core::int x, {required core::String s}) → self::B<self::B::Y%>
+ : super core::Object::•()
+ ;
+}
+static method test() → dynamic {
+ self::A<core::String> foo1 = new self::B::•<core::String>(0, s: "");
+ self::A<core::num> foo2 = let final core::String #t1 = "" in new self::B::•<core::num>(0, s: #t1);
+}
+
+constants {
+ #C1 = self::B<core::bool> {}
+ #C2 = <self::A<core::bool>>[#C1]
+}
+
+Extra constant evaluation status:
+Evaluated: VariableGet @ org-dartlang-testcase:///redirecting_constructors_declaration_order_3.dart:22:33 -> StringConstant("")
+Extra constant evaluation: evaluated: 12, effectively constant: 1
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///redirecting_constructors_declaration_order_3.dart:
+- B. (from org-dartlang-testcase:///redirecting_constructors_declaration_order_3.dart:17:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.textual_outline.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.textual_outline.expect
new file mode 100644
index 0000000..61ae9b7
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.textual_outline.expect
@@ -0,0 +1,16 @@
+class C {
+ List<A<bool>> field;
+ C.named1({this.field = const [A.redir1(0, s: "")]});
+ C.named2({this.field = const [A.redir1(s: "", 0)]});
+}
+
+abstract class A<X> {
+ const factory A.redir1(int x, {required String s}) = B;
+ const factory A.redir2(int x, {required String s}) = B;
+}
+
+class B<Y> implements A<Y> {
+ const B(int x, {required String s});
+}
+
+test() {}
diff --git a/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..63f11e2
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_constructors_declaration_order_3.dart.textual_outline_modelled.expect
@@ -0,0 +1,16 @@
+abstract class A<X> {
+ const factory A.redir1(int x, {required String s}) = B;
+ const factory A.redir2(int x, {required String s}) = B;
+}
+
+class B<Y> implements A<Y> {
+ const B(int x, {required String s});
+}
+
+class C {
+ C.named1({this.field = const [A.redir1(0, s: "")]});
+ C.named2({this.field = const [A.redir1(s: "", 0)]});
+ List<A<bool>> field;
+}
+
+test() {}
diff --git a/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.expect b/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.expect
index fb03960..adc5810 100644
--- a/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.expect
+++ b/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.expect
@@ -163,16 +163,16 @@
// new T7(0); // Error
// ^
//
-// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:63:10: Error: The argument type 'int' can't be assigned to the parameter type 'List<void Function<T>(T)>'.
-// - 'List' is from 'dart:core'.
-// new T7(0); // Error
-// ^
-//
// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:59:7: Error: Generic function type 'void Function<T>(T)' inferred as a type argument.
// Try providing a non-generic function type explicitly.
// new T4(); // Error
// ^
//
+// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:63:10: Error: The argument type 'int' can't be assigned to the parameter type 'List<void Function<T>(T)>'.
+// - 'List' is from 'dart:core'.
+// new T7(0); // Error
+// ^
+//
// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:60:4: Error: Generic function type 'void Function<T>(T)' inferred as a type argument.
// Try providing a non-generic function type explicitly.
// <T4>[]; // Error
diff --git a/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.modular.expect b/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.modular.expect
index fb03960..adc5810 100644
--- a/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.modular.expect
@@ -163,16 +163,16 @@
// new T7(0); // Error
// ^
//
-// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:63:10: Error: The argument type 'int' can't be assigned to the parameter type 'List<void Function<T>(T)>'.
-// - 'List' is from 'dart:core'.
-// new T7(0); // Error
-// ^
-//
// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:59:7: Error: Generic function type 'void Function<T>(T)' inferred as a type argument.
// Try providing a non-generic function type explicitly.
// new T4(); // Error
// ^
//
+// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:63:10: Error: The argument type 'int' can't be assigned to the parameter type 'List<void Function<T>(T)>'.
+// - 'List' is from 'dart:core'.
+// new T7(0); // Error
+// ^
+//
// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:60:4: Error: Generic function type 'void Function<T>(T)' inferred as a type argument.
// Try providing a non-generic function type explicitly.
// <T4>[]; // Error
diff --git a/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.transformed.expect b/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.transformed.expect
index 6fe631c..9d18dd9 100644
--- a/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart.strong.transformed.expect
@@ -163,16 +163,16 @@
// new T7(0); // Error
// ^
//
-// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:63:10: Error: The argument type 'int' can't be assigned to the parameter type 'List<void Function<T>(T)>'.
-// - 'List' is from 'dart:core'.
-// new T7(0); // Error
-// ^
-//
// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:59:7: Error: Generic function type 'void Function<T>(T)' inferred as a type argument.
// Try providing a non-generic function type explicitly.
// new T4(); // Error
// ^
//
+// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:63:10: Error: The argument type 'int' can't be assigned to the parameter type 'List<void Function<T>(T)>'.
+// - 'List' is from 'dart:core'.
+// new T7(0); // Error
+// ^
+//
// pkg/front_end/testcases/generic_metadata/alias_from_opt_in.dart:60:4: Error: Generic function type 'void Function<T>(T)' inferred as a type argument.
// Try providing a non-generic function type explicitly.
// <T4>[]; // Error
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.expect
index 5dd8435..417b6fd 100644
--- a/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.expect
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.expect
@@ -2,26 +2,6 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:15:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'A'.
-// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
-// class A<X extends A<X>> {}
-// ^
-//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:17:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'A2'.
-// - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A2(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:8:10: Context: This is the type variable whose bound isn't conformed to.
-// class A2<X extends A2<X>> {
-// ^
-//
// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:14:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
// - 'Object' is from 'dart:core'.
@@ -32,6 +12,16 @@
// typedef B<X extends A<X>> = A<X>;
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:15:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'A'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends A<X>> {}
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:16:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'B2'.
// - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
// - 'Object' is from 'dart:core'.
@@ -52,6 +42,16 @@
// class A2<X extends A2<X>> {
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:17:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'A2'.
+// - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A2(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:8:10: Context: This is the type variable whose bound isn't conformed to.
+// class A2<X extends A2<X>> {
+// ^
+//
import self as self;
import "dart:core" as core;
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.modular.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.modular.expect
index 5dd8435..417b6fd 100644
--- a/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.modular.expect
@@ -2,26 +2,6 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:15:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'A'.
-// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
-// class A<X extends A<X>> {}
-// ^
-//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:17:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'A2'.
-// - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A2(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:8:10: Context: This is the type variable whose bound isn't conformed to.
-// class A2<X extends A2<X>> {
-// ^
-//
// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:14:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
// - 'Object' is from 'dart:core'.
@@ -32,6 +12,16 @@
// typedef B<X extends A<X>> = A<X>;
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:15:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'A'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends A<X>> {}
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:16:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'B2'.
// - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
// - 'Object' is from 'dart:core'.
@@ -52,6 +42,16 @@
// class A2<X extends A2<X>> {
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:17:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'A2'.
+// - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A2(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:8:10: Context: This is the type variable whose bound isn't conformed to.
+// class A2<X extends A2<X>> {
+// ^
+//
import self as self;
import "dart:core" as core;
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.transformed.expect
index 5dd8435..417b6fd 100644
--- a/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart.strong.transformed.expect
@@ -2,26 +2,6 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:15:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'A'.
-// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
-// class A<X extends A<X>> {}
-// ^
-//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:17:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'A2'.
-// - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A2(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:8:10: Context: This is the type variable whose bound isn't conformed to.
-// class A2<X extends A2<X>> {
-// ^
-//
// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:14:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
// - 'Object' is from 'dart:core'.
@@ -32,6 +12,16 @@
// typedef B<X extends A<X>> = A<X>;
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:15:3: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'A'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:5:9: Context: This is the type variable whose bound isn't conformed to.
+// class A<X extends A<X>> {}
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:16:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'B2'.
// - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
// - 'Object' is from 'dart:core'.
@@ -52,6 +42,16 @@
// class A2<X extends A2<X>> {
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:17:3: Error: Inferred type argument 'A2<Object?>' doesn't conform to the bound 'A2<X>' of the type variable 'X' on 'A2'.
+// - 'A2' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A2(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue42446.dart:8:10: Context: This is the type variable whose bound isn't conformed to.
+// class A2<X extends A2<X>> {
+// ^
+//
import self as self;
import "dart:core" as core;
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.expect
index 0f569e6..d001566 100644
--- a/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.expect
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.expect
@@ -12,6 +12,16 @@
// class A<X extends A<X>> {}
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:33:9: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'C'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// new C();
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:14:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef C<X extends A<X>> = A<X>;
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:34:7: Error: Inferred type argument 'Object?' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'call'.
// - 'Object' is from 'dart:core'.
// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
@@ -76,16 +86,6 @@
// instance2(() => captureTypeArgument());
// ^
//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:33:9: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'C'.
-// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// new C();
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:14:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef C<X extends A<X>> = A<X>;
-// ^
-//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:47:11: Error: Inferred type argument 'Object?' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'Subclass.instance1'.
// - 'Object' is from 'dart:core'.
// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.modular.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.modular.expect
index 0f569e6..d001566 100644
--- a/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.modular.expect
@@ -12,6 +12,16 @@
// class A<X extends A<X>> {}
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:33:9: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'C'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// new C();
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:14:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef C<X extends A<X>> = A<X>;
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:34:7: Error: Inferred type argument 'Object?' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'call'.
// - 'Object' is from 'dart:core'.
// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
@@ -76,16 +86,6 @@
// instance2(() => captureTypeArgument());
// ^
//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:33:9: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'C'.
-// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// new C();
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:14:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef C<X extends A<X>> = A<X>;
-// ^
-//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:47:11: Error: Inferred type argument 'Object?' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'Subclass.instance1'.
// - 'Object' is from 'dart:core'.
// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.transformed.expect
index 0f569e6..d001566 100644
--- a/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart.strong.transformed.expect
@@ -12,6 +12,16 @@
// class A<X extends A<X>> {}
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:33:9: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'C'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// new C();
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:14:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef C<X extends A<X>> = A<X>;
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:34:7: Error: Inferred type argument 'Object?' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'call'.
// - 'Object' is from 'dart:core'.
// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
@@ -76,16 +86,6 @@
// instance2(() => captureTypeArgument());
// ^
//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:33:9: Error: Inferred type argument 'A<Object?>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'C'.
-// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// new C();
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:14:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef C<X extends A<X>> = A<X>;
-// ^
-//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart:47:11: Error: Inferred type argument 'Object?' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'Subclass.instance1'.
// - 'Object' is from 'dart:core'.
// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45464.dart'.
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.expect
index 47a40ba..849cda5 100644
--- a/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.expect
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.expect
@@ -2,6 +2,16 @@
//
// Problems in library:
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:20:3: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
+// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends G<C<X>>> = C<X>;
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:21:5: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
// - 'Object' is from 'dart:core'.
@@ -12,6 +22,16 @@
// typedef A<X extends G<C<X>>> = C<X>;
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:22:5: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
+// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A.bar(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends G<C<X>>> = C<X>;
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:23:3: Error: Inferred type argument 'D<Object?> Function(D<Never>)' doesn't conform to the bound 'D<X> Function(D<X>)' of the type variable 'X' on 'B'.
// - 'D' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
// - 'Object' is from 'dart:core'.
@@ -22,26 +42,6 @@
// typedef B<X extends G<D<X>>> = D<X>;
// ^
//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:20:3: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
-// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef A<X extends G<C<X>>> = C<X>;
-// ^
-//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:22:5: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
-// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A.bar(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef A<X extends G<C<X>>> = C<X>;
-// ^
-//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:24:5: Error: Inferred type argument 'D<Object?> Function(D<Never>)' doesn't conform to the bound 'D<X> Function(D<X>)' of the type variable 'X' on 'B'.
// - 'D' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
// - 'Object' is from 'dart:core'.
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.modular.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.modular.expect
index 47a40ba..849cda5 100644
--- a/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.modular.expect
@@ -2,6 +2,16 @@
//
// Problems in library:
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:20:3: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
+// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends G<C<X>>> = C<X>;
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:21:5: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
// - 'Object' is from 'dart:core'.
@@ -12,6 +22,16 @@
// typedef A<X extends G<C<X>>> = C<X>;
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:22:5: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
+// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A.bar(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends G<C<X>>> = C<X>;
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:23:3: Error: Inferred type argument 'D<Object?> Function(D<Never>)' doesn't conform to the bound 'D<X> Function(D<X>)' of the type variable 'X' on 'B'.
// - 'D' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
// - 'Object' is from 'dart:core'.
@@ -22,26 +42,6 @@
// typedef B<X extends G<D<X>>> = D<X>;
// ^
//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:20:3: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
-// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef A<X extends G<C<X>>> = C<X>;
-// ^
-//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:22:5: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
-// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A.bar(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef A<X extends G<C<X>>> = C<X>;
-// ^
-//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:24:5: Error: Inferred type argument 'D<Object?> Function(D<Never>)' doesn't conform to the bound 'D<X> Function(D<X>)' of the type variable 'X' on 'B'.
// - 'D' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
// - 'Object' is from 'dart:core'.
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.transformed.expect
index 47a40ba..849cda5 100644
--- a/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart.strong.transformed.expect
@@ -2,6 +2,16 @@
//
// Problems in library:
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:20:3: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
+// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends G<C<X>>> = C<X>;
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:21:5: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
// - 'Object' is from 'dart:core'.
@@ -12,6 +22,16 @@
// typedef A<X extends G<C<X>>> = C<X>;
// ^
//
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:22:5: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
+// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
+// - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// A.bar(); // Error.
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends G<C<X>>> = C<X>;
+// ^
+//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:23:3: Error: Inferred type argument 'D<Object?> Function(D<Never>)' doesn't conform to the bound 'D<X> Function(D<X>)' of the type variable 'X' on 'B'.
// - 'D' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
// - 'Object' is from 'dart:core'.
@@ -22,26 +42,6 @@
// typedef B<X extends G<D<X>>> = D<X>;
// ^
//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:20:3: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
-// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef A<X extends G<C<X>>> = C<X>;
-// ^
-//
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:22:5: Error: Inferred type argument 'C<Object?> Function(C<Never>)' doesn't conform to the bound 'C<X> Function(C<X>)' of the type variable 'X' on 'A'.
-// - 'C' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
-// - 'Object' is from 'dart:core'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-// A.bar(); // Error.
-// ^
-// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:16:11: Context: This is the type variable whose bound isn't conformed to.
-// typedef A<X extends G<C<X>>> = C<X>;
-// ^
-//
// pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart:24:5: Error: Inferred type argument 'D<Object?> Function(D<Never>)' doesn't conform to the bound 'D<X> Function(D<X>)' of the type variable 'X' on 'B'.
// - 'D' is from 'pkg/front_end/testcases/nonfunction_type_aliases/issue45519_2.dart'.
// - 'Object' is from 'dart:core'.
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index be6a69d..a1234c6 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -79,6 +79,7 @@
regress/issue_39682: semiFuzzFailureOnForceRebuildBodies # has private method
dart2wasm/inference_update_2/issue52452: semiFuzzFailureOnForceRebuildBodies # private fields in class.
records/nullable_access_extension: semiFuzzFailureOnForceRebuildBodies # unnamed extension
+general/constructor_inference_interdependence: semiFuzzFailureOnForceRebuildBodies # sealed class ending up in another library.
# FUZZ FRAMEWORK FAILURES
general/script_tag_in_part_file: SemiFuzzFailure # `#!/usr/bin/env dart` goes away
diff --git a/tools/VERSION b/tools/VERSION
index 4f2a1a3..6f7908c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 3
MINOR 6
PATCH 0
-PRERELEASE 105
+PRERELEASE 106
PRERELEASE_PATCH 0