Version 2.14.0-387.0.dev

Merge commit '4200f6d91500360b2ff5dc130810712deb041005' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/replace_with_null_aware.dart b/pkg/analysis_server/lib/src/services/correction/dart/replace_with_null_aware.dart
index c6b7dd1..822442d 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/replace_with_null_aware.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/replace_with_null_aware.dart
@@ -10,11 +10,24 @@
 import 'package:analyzer_plugin/utilities/range_factory.dart';
 
 class ReplaceWithNullAware extends CorrectionProducer {
+  /// The kind of correction to be made.
+  final _CorrectionKind correctionKind;
+
+  ReplaceWithNullAware(this.correctionKind);
+
   @override
   FixKind get fixKind => DartFixKind.REPLACE_WITH_NULL_AWARE;
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
+    if (correctionKind == _CorrectionKind.inChain) {
+      await _computeInChain(builder);
+    } else if (correctionKind == _CorrectionKind.single) {
+      await _computeSingle(builder);
+    }
+  }
+
+  Future<void> _computeInChain(ChangeBuilder builder) async {
     var node = coveredNode;
     if (node is Expression) {
       final node_final = node;
@@ -38,6 +51,37 @@
     }
   }
 
+  Future<void> _computeSingle(ChangeBuilder builder) async {
+    var node = coveredNode?.parent;
+    if (node is MethodInvocation) {
+      var operator = node.operator;
+      if (operator != null) {
+        await builder.addDartFileEdit(file, (builder) {
+          builder.addSimpleReplacement(range.token(operator), '?.');
+        });
+      }
+    } else if (node is PrefixedIdentifier) {
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addSimpleReplacement(range.token(node.period), '?.');
+      });
+    } else if (node is PropertyAccess) {
+      await builder.addDartFileEdit(file, (builder) {
+        builder.addSimpleReplacement(range.token(node.operator), '?.');
+      });
+    }
+  }
+
   /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
-  static ReplaceWithNullAware newInstance() => ReplaceWithNullAware();
+  static ReplaceWithNullAware inChain() =>
+      ReplaceWithNullAware(_CorrectionKind.inChain);
+
+  /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
+  static ReplaceWithNullAware single() =>
+      ReplaceWithNullAware(_CorrectionKind.single);
+}
+
+/// The kinds of corrections supported by [ReplaceWithNullAware].
+enum _CorrectionKind {
+  inChain,
+  single,
 }
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index c04be05..e4e975c 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -930,12 +930,14 @@
     ],
     CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE: [
       AddNullCheck.newInstance,
+      ReplaceWithNullAware.single,
     ],
     CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE: [
       AddNullCheck.newInstance,
     ],
     CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE: [
       AddNullCheck.newInstance,
+      ReplaceWithNullAware.single,
     ],
     CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE: [
       AddNullCheck.newInstance,
@@ -1045,7 +1047,7 @@
     ],
 
     HintCode.CAN_BE_NULL_AFTER_NULL_AWARE: [
-      ReplaceWithNullAware.newInstance,
+      ReplaceWithNullAware.inChain,
     ],
     HintCode.DEAD_CODE: [
       RemoveDeadCode.newInstance,
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_null_aware_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_null_aware_test.dart
index 282e085..84b84d5 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_null_aware_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_null_aware_test.dart
@@ -11,6 +11,8 @@
 void main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ReplaceWithNullAwareTest);
+    defineReflectiveTests(UncheckedMethodInvocationOfNullableValueTest);
+    defineReflectiveTests(UncheckedPropertyAccessOfNullableValueTest);
   });
 }
 
@@ -61,3 +63,90 @@
 ''');
   }
 }
+
+@reflectiveTest
+class UncheckedMethodInvocationOfNullableValueTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.REPLACE_WITH_NULL_AWARE;
+
+  Future<void> test_method() async {
+    await resolveTestCode('''
+class C {
+  List<int>? values;
+
+  void m() {
+    if (values != null) {
+      print(values.toList());
+    }
+  }
+}
+''');
+    await assertHasFix('''
+class C {
+  List<int>? values;
+
+  void m() {
+    if (values != null) {
+      print(values?.toList());
+    }
+  }
+}
+''');
+  }
+}
+
+@reflectiveTest
+class UncheckedPropertyAccessOfNullableValueTest extends FixProcessorTest {
+  @override
+  FixKind get kind => DartFixKind.REPLACE_WITH_NULL_AWARE;
+
+  Future<void> test_prefixedIdentifier() async {
+    await resolveTestCode('''
+class C {
+  List<int>? values;
+
+  void m() {
+    if (values != null) {
+      print(values.length);
+    }
+  }
+}
+''');
+    await assertHasFix('''
+class C {
+  List<int>? values;
+
+  void m() {
+    if (values != null) {
+      print(values?.length);
+    }
+  }
+}
+''');
+  }
+
+  Future<void> test_propertyAccess() async {
+    await resolveTestCode('''
+class C {
+  List<int>? values;
+
+  void m() {
+    if (values != null) {
+      print((values).length);
+    }
+  }
+}
+''');
+    await assertHasFix('''
+class C {
+  List<int>? values;
+
+  void m() {
+    if (values != null) {
+      print((values)?.length);
+    }
+  }
+}
+''');
+  }
+}
diff --git a/pkg/dartdev/test/commands/flag_test.dart b/pkg/dartdev/test/commands/flag_test.dart
index bfcc02c..5d9d0ab 100644
--- a/pkg/dartdev/test/commands/flag_test.dart
+++ b/pkg/dartdev/test/commands/flag_test.dart
@@ -82,8 +82,8 @@
     var result = p.runSync(['--help', '--verbose']);
 
     expect(result.exitCode, 0);
-    expect(result.stdout, isEmpty);
-    expect(result.stderr,
+    expect(result.stderr, isEmpty);
+    expect(result.stdout,
         contains('The following options are only used for VM development'));
   });
 
@@ -92,8 +92,8 @@
     var result = p.runSync(['--help', '-v']);
 
     expect(result.exitCode, 0);
-    expect(result.stdout, isEmpty);
-    expect(result.stderr,
+    expect(result.stderr, isEmpty);
+    expect(result.stdout,
         contains('The following options are only used for VM development'));
   });
 
diff --git a/pkg/dds/lib/src/dap/adapters/dart.dart b/pkg/dds/lib/src/dap/adapters/dart.dart
index e9710c3..72f7964 100644
--- a/pkg/dds/lib/src/dap/adapters/dart.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart.dart
@@ -107,6 +107,12 @@
   /// yet been made.
   DartDevelopmentService? _dds;
 
+  /// The [InitializeRequestArguments] provided by the client in the
+  /// `initialize` request.
+  ///
+  /// `null` if the `initialize` request has not yet been made.
+  InitializeRequestArguments? _initializeArgs;
+
   /// Whether to use IPv6 for DAP/Debugger services.
   final bool ipv6;
 
@@ -135,6 +141,13 @@
     ...?args.additionalProjectPaths,
   ].whereNotNull().toList();
 
+  /// Whether we have already sent the [TerminatedEvent] to the client.
+  ///
+  /// This is tracked so that we don't send multiple if there are multiple
+  /// events that suggest the session ended (such as a process exiting and the
+  /// VM Service closing).
+  bool _hasSentTerminatedEvent = false;
+
   DartDebugAdapter(
     ByteStreamServerChannel channel, {
     this.ipv6 = false,
@@ -155,6 +168,12 @@
   bool get evaluateToStringInDebugViews =>
       args.evaluateToStringInDebugViews ?? false;
 
+  /// The [InitializeRequestArguments] provided by the client in the
+  /// `initialize` request.
+  ///
+  /// `null` if the `initialize` request has not yet been made.
+  InitializeRequestArguments? get initializeArgs => _initializeArgs;
+
   /// [attachRequest] is called by the client when it wants us to to attach to
   /// an existing app. This will only be called once (and only one of this or
   /// launchRequest will be called).
@@ -236,6 +255,7 @@
     // perhaps gated on a capability/argument).
     this.vmService = vmService;
 
+    unawaited(vmService.onDone.then((_) => _handleVmServiceClosed()));
     _subscriptions.addAll([
       vmService.onIsolateEvent.listen(_handleIsolateEvent),
       vmService.onDebugEvent.listen(_handleDebugEvent),
@@ -464,6 +484,16 @@
     }
   }
 
+  /// Sends a [TerminatedEvent] if one has not already been sent.
+  void handleSessionTerminate() {
+    if (_hasSentTerminatedEvent) {
+      return;
+    }
+
+    _hasSentTerminatedEvent = true;
+    sendEvent(TerminatedEventBody());
+  }
+
   /// [initializeRequest] is the first call from the client during
   /// initialization and allows exchanging capabilities and configuration
   /// between client and server.
@@ -474,9 +504,12 @@
   @override
   Future<void> initializeRequest(
     Request request,
-    InitializeRequestArguments? args,
+    InitializeRequestArguments args,
     void Function(Capabilities) sendResponse,
   ) async {
+    // Capture args so we can read capabilities later.
+    _initializeArgs = args;
+
     // TODO(dantup): Capture/honor editor-specific settings like linesStartAt1
     sendResponse(Capabilities(
       exceptionBreakpointFilters: [
@@ -1052,6 +1085,16 @@
     }
   }
 
+  Future<void> _handleVmServiceClosed() async {
+    // Usually termination is handled by the subclass, but we use VM Service
+    // termination as a fallback for cases where this isn't possible (such as
+    // using `runInTerminal`). However, if we end the session too quickly, the
+    // editor might drop messages from stdout that haven't yet been processed
+    // so we use a short delay before handling termination this way.
+    await Future.delayed(const Duration(seconds: 1));
+    handleSessionTerminate();
+  }
+
   /// Performs some setup that is common to both [launchRequest] and
   /// [attachRequest].
   Future<void> _prepareForLaunchOrAttach() async {
@@ -1130,6 +1173,7 @@
 /// Specialised adapters (such as Flutter) will likely extend this class with
 /// their own additional fields.
 class DartLaunchRequestArguments extends LaunchRequestArguments {
+  final String? name;
   final String program;
   final List<String>? args;
   final String? cwd;
@@ -1146,6 +1190,18 @@
   /// as not-debuggable.
   final List<String>? additionalProjectPaths;
 
+  /// Which console to run the program in.
+  ///
+  /// If "terminal" or "externalTerminal" will cause the program to be run by
+  /// the client by having the server call the `runInTerminal` request on the
+  /// client (as long as the client advertises support for
+  /// `runInTerminalRequest`).
+  ///
+  /// Otherwise will run inside the debug adapter and stdout/stderr will be
+  /// routed to the client using [OutputEvent]s. This is the default (and
+  /// simplest) way, but prevents the user from being able to type into `stdin`.
+  final String? console;
+
   /// Whether SDK libraries should be marked as debuggable.
   ///
   /// Treated as `false` if null, which means "step in" will not step into SDK
@@ -1187,12 +1243,14 @@
   DartLaunchRequestArguments({
     Object? restart,
     bool? noDebug,
+    this.name,
     required this.program,
     this.args,
     this.cwd,
     this.vmServiceInfoFile,
     this.vmServicePort,
     this.vmAdditionalArgs,
+    this.console,
     this.enableAsserts,
     this.additionalProjectPaths,
     this.debugSdkLibraries,
@@ -1203,12 +1261,14 @@
   }) : super(restart: restart, noDebug: noDebug);
 
   DartLaunchRequestArguments.fromMap(Map<String, Object?> obj)
-      : program = obj['program'] as String,
+      : name = obj['name'] as String?,
+        program = obj['program'] as String,
         args = (obj['args'] as List?)?.cast<String>(),
         cwd = obj['cwd'] as String?,
         vmServiceInfoFile = obj['vmServiceInfoFile'] as String?,
         vmServicePort = obj['vmServicePort'] as int?,
         vmAdditionalArgs = (obj['vmAdditionalArgs'] as List?)?.cast<String>(),
+        console = obj['console'] as String?,
         enableAsserts = obj['enableAsserts'] as bool?,
         additionalProjectPaths =
             (obj['additionalProjectPaths'] as List?)?.cast<String>(),
@@ -1225,12 +1285,14 @@
   @override
   Map<String, Object?> toJson() => {
         ...super.toJson(),
+        if (name != null) 'name': name,
         'program': program,
         if (args != null) 'args': args,
         if (cwd != null) 'cwd': cwd,
         if (vmServiceInfoFile != null) 'vmServiceInfoFile': vmServiceInfoFile,
         if (vmServicePort != null) 'vmServicePort': vmServicePort,
         if (vmAdditionalArgs != null) 'vmAdditionalArgs': vmAdditionalArgs,
+        if (console != null) 'console': console,
         if (enableAsserts != null) 'enableAsserts': enableAsserts,
         if (additionalProjectPaths != null)
           'additionalProjectPaths': additionalProjectPaths,
diff --git a/pkg/dds/lib/src/dap/adapters/dart_cli.dart b/pkg/dds/lib/src/dap/adapters/dart_cli.dart
index f0fcd43..80258ca 100644
--- a/pkg/dds/lib/src/dap/adapters/dart_cli.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart_cli.dart
@@ -141,6 +141,80 @@
       this.usePackageConfigFile(packageConfig);
     }
 
+    // If the client supports runInTerminal and args.console is set to either
+    // 'terminal' or 'runInTerminal' we won't run the process ourselves, but
+    // instead call the client to run it for us (this allows it to run in a
+    // terminal where the user can interact with `stdin`).
+    final canRunInTerminal =
+        initializeArgs?.supportsRunInTerminalRequest ?? false;
+
+    // The terminal kinds used by DAP are 'integrated' and 'external'.
+    final terminalKind = canRunInTerminal
+        ? args.console == 'terminal'
+            ? 'integrated'
+            : args.console == 'externalTerminal'
+                ? 'external'
+                : null
+        : null;
+
+    // TODO(dantup): Support passing env to both of these.
+
+    if (terminalKind != null) {
+      await launchInEditorTerminal(debug, terminalKind, vmPath, processArgs);
+    } else {
+      await launchAsProcess(vmPath, processArgs);
+    }
+  }
+
+  /// Calls the client (via a `runInTerminal` request) to spawn the process so
+  /// that it can run in a local terminal that the user can interact with.
+  Future<void> launchInEditorTerminal(
+    bool debug,
+    String terminalKind,
+    String vmPath,
+    List<String> processArgs,
+  ) async {
+    logger?.call('Spawning $vmPath with $processArgs in ${args.cwd}'
+        ' via client ${terminalKind} terminal');
+
+    // runInTerminal is a DAP request that goes from server-to-client that
+    // allows the DA to ask the client editor to run the debugee for us. In this
+    // case we will have no access to the process (although we get the PID) so
+    // for debugging will rely on the process writing the service-info file that
+    // we can detect with the normal watching code.
+    final requestArgs = RunInTerminalRequestArguments(
+      args: [vmPath, ...processArgs],
+      cwd: args.cwd ?? path.dirname(args.program),
+      kind: terminalKind,
+      title: args.name ?? 'Dart',
+    );
+    try {
+      final response = await sendRequest(requestArgs);
+      final body =
+          RunInTerminalResponseBody.fromJson(response as Map<String, Object?>);
+      logger?.call(
+        'Client spawned process'
+        ' (proc: ${body.processId}, shell: ${body.shellProcessId})',
+      );
+    } catch (e) {
+      logger?.call('Client failed to spawn process $e');
+      sendOutput('console', '\nFailed to spawn process: $e');
+      handleSessionTerminate();
+    }
+
+    // When using `runInTerminal` and `noDebug`, we will not connect to the VM
+    // Service so we will have no way of knowing when the process completes, so
+    // we just send the termination event right away.
+    if (!debug) {
+      handleSessionTerminate();
+    }
+  }
+
+  /// Launches the program as a process controlled by the debug adapter.
+  ///
+  /// Output to `stdout`/`stderr` will be sent to the editor using
+  /// [OutputEvent]s.
+  Future<void> launchAsProcess(String vmPath, List<String> processArgs) async {
     logger?.call('Spawning $vmPath with $processArgs in ${args.cwd}');
     final process = await Process.start(
       vmPath,
@@ -204,7 +278,7 @@
     // Always add a leading newline since the last written text might not have
     // had one.
     sendOutput('console', '\nExited$codeSuffix.');
-    sendEvent(TerminatedEventBody());
+    handleSessionTerminate();
   }
 
   void _handleStderr(List<int> data) {
diff --git a/pkg/dds/lib/src/dap/base_debug_adapter.dart b/pkg/dds/lib/src/dap/base_debug_adapter.dart
index a74f1f3..0bfa738 100644
--- a/pkg/dds/lib/src/dap/base_debug_adapter.dart
+++ b/pkg/dds/lib/src/dap/base_debug_adapter.dart
@@ -30,6 +30,10 @@
   int _sequence = 1;
   final ByteStreamServerChannel _channel;
 
+  /// Completers for requests that are sent from the server back to the editor
+  /// such as `runInTerminal`.
+  final _serverToClientRequestCompleters = <int, Completer<Object?>>{};
+
   BaseDebugAdapter(this._channel) {
     _channel.listen(_handleIncomingMessage);
   }
@@ -174,13 +178,19 @@
 
   /// Sends a request to the client, looking up the request type based on the
   /// runtimeType of [arguments].
-  void sendRequest(RequestArguments arguments) {
+  Future<Object?> sendRequest(RequestArguments arguments) {
     final request = Request(
       seq: _sequence++,
       command: commandTypes[arguments.runtimeType]!,
       arguments: arguments,
     );
+
+    // Store a completer to be used when a response comes back.
+    final completer = Completer<Object?>();
+    _serverToClientRequestCompleters[request.seq] = completer;
     _channel.sendRequest(request);
+
+    return completer.future;
   }
 
   Future<void> setBreakpointsRequest(
@@ -318,8 +328,16 @@
   }
 
   void _handleIncomingResponse(Response response) {
-    // TODO(dantup): Implement this when the server sends requests to the client
-    // (for example runInTerminalRequest).
+    final completer =
+        _serverToClientRequestCompleters.remove(response.requestSeq);
+
+    if (response.success) {
+      completer?.complete(response.body);
+    } else {
+      completer?.completeError(
+        response.message ?? 'Request ${response.requestSeq} failed',
+      );
+    }
   }
 
   /// Helpers for requests that have `void` arguments. The supplied args are
diff --git a/pkg/dds/test/dap/integration/debug_test.dart b/pkg/dds/test/dap/integration/debug_test.dart
index 41863f9..2266f6f 100644
--- a/pkg/dds/test/dap/integration/debug_test.dart
+++ b/pkg/dds/test/dap/integration/debug_test.dart
@@ -2,7 +2,10 @@
 // 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:io';
+
 import 'package:dds/src/dap/protocol_generated.dart';
+import 'package:pedantic/pedantic.dart';
 import 'package:test/test.dart';
 
 import 'test_client.dart';
@@ -51,6 +54,53 @@
       ]);
     });
 
+    test('runs a simple script using runInTerminal request', () async {
+      final testFile = dap.createTestFile(emptyProgram);
+
+      // Set up a handler to handle the server calling the clients runInTerminal
+      // request and capture the args.
+      RunInTerminalRequestArguments? runInTerminalArgs;
+      Process? proc;
+      var processExited = false;
+      dap.client.handleRequest(
+        'runInTerminal',
+        (args) async {
+          runInTerminalArgs = RunInTerminalRequestArguments.fromJson(
+            args as Map<String, Object?>,
+          );
+
+          // Run the requested process (emulating what the editor would do) so
+          // that the DA will pick up the service info file, connect to the VM,
+          // resume, and then detect its termination.
+          final runArgs = runInTerminalArgs!;
+          proc = await Process.start(
+            runArgs.args.first,
+            runArgs.args.skip(1).toList(),
+            workingDirectory: runArgs.cwd,
+          );
+          unawaited(proc!.exitCode.then((_) => processExited = true));
+
+          return RunInTerminalResponseBody(processId: proc!.pid);
+        },
+      );
+
+      // Run the script until we get a TerminatedEvent.
+      await Future.wait([
+        dap.client.event('terminated'),
+        dap.client.initialize(supportsRunInTerminalRequest: true),
+        dap.client.launch(testFile.path, console: "terminal"),
+      ], eagerError: true);
+
+      expect(runInTerminalArgs, isNotNull);
+      expect(proc, isNotNull);
+      expect(
+        runInTerminalArgs!.args,
+        containsAllInOrder([Platform.resolvedExecutable, testFile.path]),
+      );
+      expect(proc!.pid, isPositive);
+      expect(processExited, isTrue);
+    });
+
     test('provides a list of threads', () async {
       final client = dap.client;
       final testFile = dap.createTestFile(simpleBreakpointProgram);
diff --git a/pkg/dds/test/dap/integration/no_debug_test.dart b/pkg/dds/test/dap/integration/no_debug_test.dart
index bb0af1d..dec3316 100644
--- a/pkg/dds/test/dap/integration/no_debug_test.dart
+++ b/pkg/dds/test/dap/integration/no_debug_test.dart
@@ -2,9 +2,13 @@
 // 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:io';
+
+import 'package:dds/src/dap/protocol_generated.dart';
 import 'package:test/test.dart';
 
 import 'test_client.dart';
+import 'test_scripts.dart';
 import 'test_support.dart';
 
 main() {
@@ -41,6 +45,40 @@
         'Exited.',
       ]);
     });
+
+    test('runs a simple script using the runInTerminal request', () async {
+      final testFile = dap.createTestFile(emptyProgram);
+
+      // Set up a handler to handle the server calling the clients runInTerminal
+      // request and capture the args.
+      RunInTerminalRequestArguments? runInTerminalArgs;
+      dap.client.handleRequest(
+        'runInTerminal',
+        (args) {
+          runInTerminalArgs = RunInTerminalRequestArguments.fromJson(
+            args as Map<String, Object?>,
+          );
+          return RunInTerminalResponseBody();
+        },
+      );
+
+      // Run the script until we get a TerminatedEvent.
+      await Future.wait([
+        dap.client.event('terminated'),
+        dap.client.initialize(supportsRunInTerminalRequest: true),
+        dap.client.launch(
+          testFile.path,
+          noDebug: true,
+          console: "terminal",
+        ),
+      ], eagerError: true);
+
+      expect(runInTerminalArgs, isNotNull);
+      expect(
+        runInTerminalArgs!.args,
+        containsAllInOrder([Platform.resolvedExecutable, testFile.path]),
+      );
+    });
     // These tests can be slow due to starting up the external server process.
   }, timeout: Timeout.none);
 }
diff --git a/pkg/dds/test/dap/integration/test_client.dart b/pkg/dds/test/dap/integration/test_client.dart
index e1a4aec..dbb9305 100644
--- a/pkg/dds/test/dap/integration/test_client.dart
+++ b/pkg/dds/test/dap/integration/test_client.dart
@@ -31,6 +31,11 @@
   final _eventController = StreamController<Event>.broadcast();
   int _seq = 1;
 
+  /// Functions provided by tests to handle requests that may come from the
+  /// server (such as `runInTerminal`).
+  final _serverRequestHandlers =
+      <String, FutureOr<Object?> Function(Object?)>{};
+
   DapTestClient._(
     this._channel,
     this._logger, {
@@ -97,14 +102,28 @@
     return _eventController.stream.where((e) => e.event == event);
   }
 
+  /// Records a handler for when the server sends a [request] request.
+  void handleRequest(
+    String request,
+    FutureOr<Object?> Function(Object?) handler,
+  ) {
+    _serverRequestHandlers[request] = handler;
+  }
+
   /// Send an initialize request to the server.
   ///
   /// This occurs before the request to start running/debugging a script and is
   /// used to exchange capabilities and send breakpoints and other settings.
-  Future<Response> initialize({String exceptionPauseMode = 'None'}) async {
+  Future<Response> initialize({
+    String exceptionPauseMode = 'None',
+    bool? supportsRunInTerminalRequest,
+  }) async {
     final responses = await Future.wait([
       event('initialized'),
-      sendRequest(InitializeRequestArguments(adapterID: 'test')),
+      sendRequest(InitializeRequestArguments(
+        adapterID: 'test',
+        supportsRunInTerminalRequest: supportsRunInTerminalRequest,
+      )),
       sendRequest(
         SetExceptionBreakpointsArguments(
           filters: [exceptionPauseMode],
@@ -122,6 +141,7 @@
     String? cwd,
     bool? noDebug,
     List<String>? additionalProjectPaths,
+    String? console,
     bool? debugSdkLibraries,
     bool? debugExternalPackageLibraries,
     bool? evaluateGettersInDebugViews,
@@ -134,6 +154,7 @@
         cwd: cwd,
         args: args,
         additionalProjectPaths: additionalProjectPaths,
+        console: console,
         debugSdkLibraries: debugSdkLibraries,
         debugExternalPackageLibraries: debugExternalPackageLibraries,
         evaluateGettersInDebugViews: evaluateGettersInDebugViews,
@@ -181,6 +202,21 @@
     return _logIfSlow('Request "$command"', completer.future);
   }
 
+  /// Sends a response to the server.
+  ///
+  /// This is used to respond to server-to-client requests such as
+  /// `runInTerminal`.
+  void sendResponse(Request request, Object? responseBody) {
+    final response = Response(
+      success: true,
+      requestSeq: request.seq,
+      seq: _seq++,
+      command: request.command,
+      body: responseBody,
+    );
+    _channel.sendResponse(response);
+  }
+
   /// Sends a stackTrace request to the server to request the call stack for a
   /// given thread.
   ///
@@ -200,7 +236,6 @@
     File? file,
     Future<Response> Function()? launch,
   }) {
-    // Launch script and wait for termination.
     return Future.wait([
       initialize(),
       launch?.call() ?? this.launch(file!.path),
@@ -258,7 +293,7 @@
 
   /// Handles an incoming message from the server, completing the relevant request
   /// of raising the appropriate event.
-  void _handleMessage(message) {
+  Future<void> _handleMessage(message) async {
     if (message is Response) {
       final pendingRequest = _pendingRequests.remove(message.requestSeq);
       if (pendingRequest == null) {
@@ -277,8 +312,19 @@
       // tests are waiting on something that will never come, they fail at
       // a useful location.
       if (message.event == 'terminated') {
-        _eventController.close();
+        unawaited(_eventController.close());
       }
+    } else if (message is Request) {
+      // The server sent a request to the client. Call the handler and then send
+      // back its result in a response.
+      final command = message.command;
+      final args = message.arguments;
+      final handler = _serverRequestHandlers[command];
+      if (handler == null) {
+        throw 'Test did not configure a handler for servers request: $command';
+      }
+      final result = await handler(args);
+      sendResponse(message, result);
     }
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
index ada23ac..2452d86 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constructor_tearoff_lowering.dart
@@ -253,7 +253,19 @@
     FreshTypeParameters freshTypeParameters) {
   int fileOffset = tearOff.fileOffset;
 
+  List<TypeParameter> typeParameters;
+  if (target is Constructor) {
+    typeParameters = target.enclosingClass.typeParameters;
+  } else {
+    typeParameters = target.function!.typeParameters;
+  }
+
   if (!freshTypeParameters.substitution.isEmpty) {
+    if (typeArguments.length != typeParameters.length) {
+      // Error case: Use default types as type arguments.
+      typeArguments = new List<DartType>.generate(typeParameters.length,
+          (int index) => typeParameters[index].defaultType);
+    }
     if (typeArguments.isNotEmpty) {
       // Translate [typeArgument] into the context of the synthesized procedure.
       typeArguments = new List<DartType>.generate(
@@ -262,14 +274,21 @@
               .substituteType(typeArguments[index]));
     }
   }
-
+  Map<TypeParameter, DartType> substitutionMap;
+  if (typeParameters.length == typeArguments.length) {
+    substitutionMap = new Map<TypeParameter, DartType>.fromIterables(
+        typeParameters, typeArguments);
+  } else {
+    // Error case: Substitute type parameters with `dynamic`.
+    substitutionMap = new Map<TypeParameter, DartType>.fromIterables(
+        typeParameters,
+        new List<DartType>.generate(
+            typeParameters.length, (int index) => const DynamicType()));
+  }
   Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
   _createTearOffBody(tearOff, target, arguments);
   return new SynthesizedFunctionNode(
-      new Map<TypeParameter, DartType>.fromIterables(
-          target.enclosingClass!.typeParameters, typeArguments),
-      target.function!,
-      tearOff.function,
+      substitutionMap, target.function!, tearOff.function,
       identicalSignatures: false);
 }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index 82dbe5c..20372bb 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -3218,8 +3218,8 @@
                     _helper.buildDartTypeArguments(typeArguments);
               }
               if (isGenericTypedefTearOff) {
-                if (isProperRenameForClass(
-                    _helper.typeEnvironment, aliasBuilder!.typedef)) {
+                if (isProperRenameForClass(_helper.typeEnvironment,
+                    aliasBuilder!.typedef, aliasBuilder.library.library)) {
                   return tearOffExpression;
                 }
                 Procedure? tearOffLowering =
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
index c19553b..2a2bf65 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
@@ -33,6 +33,7 @@
         FunctionNode,
         Initializer,
         InterfaceType,
+        Library,
         Member,
         Name,
         Procedure,
@@ -186,7 +187,8 @@
 }
 
 /// Checks that a generic [typedef] for a generic class.
-bool isProperRenameForClass(TypeEnvironment typeEnvironment, Typedef typedef) {
+bool isProperRenameForClass(
+    TypeEnvironment typeEnvironment, Typedef typedef, Library typedefLibrary) {
   DartType? rhsType = typedef.type;
   if (rhsType is! InterfaceType) {
     return false;
@@ -201,7 +203,7 @@
   for (int i = 0; i < fromParameters.length; ++i) {
     if (typeArguments[i] !=
         new TypeParameterType.withDefaultNullabilityForLibrary(
-            fromParameters[i], typedef.enclosingLibrary)) {
+            fromParameters[i], typedefLibrary)) {
       return false;
     }
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index fab3ab7..90d2f7b 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -4790,7 +4790,8 @@
             checkReturn =
                 TypeInferrerImpl.returnedTypeParametersOccurNonCovariantly(
                     interfaceMember.enclosingClass!,
-                    interfaceMember.function.returnType);
+                    interfaceMember.function
+                        .computeFunctionType(inferrer.library.nonNullable));
           } else if (interfaceMember is Field) {
             checkReturn =
                 TypeInferrerImpl.returnedTypeParametersOccurNonCovariantly(
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
index 71176e5..bb99b32 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_helper.dart
@@ -59,32 +59,54 @@
 
     // For mixin application constructors, the argument count is the same, but
     // for redirecting tear off lowerings, the argument count of the tear off
-    // can be less than that of the redirection target.
-
-    assert(_synthesized.positionalParameters.length <=
-        _original.positionalParameters.length);
-    for (int i = 0; i < _synthesized.positionalParameters.length; i++) {
-      cloneInitializer(_original.positionalParameters[i],
-          _synthesized.positionalParameters[i]);
-    }
+    // can be less than that of the redirection target or, in errors cases, be
+    // unrelated.
 
     if (identicalSignatures) {
+      assert(_synthesized.positionalParameters.length ==
+          _original.positionalParameters.length);
+      for (int i = 0; i < _synthesized.positionalParameters.length; i++) {
+        cloneInitializer(_original.positionalParameters[i],
+            _synthesized.positionalParameters[i]);
+      }
       assert(_synthesized.namedParameters.length ==
           _original.namedParameters.length);
       for (int i = 0; i < _synthesized.namedParameters.length; i++) {
         cloneInitializer(
             _original.namedParameters[i], _synthesized.namedParameters[i]);
       }
-    } else if (_synthesized.namedParameters.isNotEmpty) {
-      Map<String, VariableDeclaration> originalParameters = {};
-      for (int i = 0; i < _original.namedParameters.length; i++) {
-        originalParameters[_original.namedParameters[i].name!] =
-            _original.namedParameters[i];
+    } else {
+      for (int i = 0; i < _synthesized.positionalParameters.length; i++) {
+        VariableDeclaration synthesizedParameter =
+            _synthesized.positionalParameters[i];
+        if (i < _original.positionalParameters.length) {
+          cloneInitializer(
+              _original.positionalParameters[i], synthesizedParameter);
+        } else {
+          // Error case: use `null` as initializer.
+          synthesizedParameter.initializer = new NullLiteral()
+            ..parent = synthesizedParameter;
+        }
       }
-      for (int i = 0; i < _synthesized.namedParameters.length; i++) {
-        cloneInitializer(
-            originalParameters[_synthesized.namedParameters[i].name!]!,
-            _synthesized.namedParameters[i]);
+      if (_synthesized.namedParameters.isNotEmpty) {
+        Map<String, VariableDeclaration> originalParameters = {};
+        for (int i = 0; i < _original.namedParameters.length; i++) {
+          originalParameters[_original.namedParameters[i].name!] =
+              _original.namedParameters[i];
+        }
+        for (int i = 0; i < _synthesized.namedParameters.length; i++) {
+          VariableDeclaration synthesizedParameter =
+              _synthesized.namedParameters[i];
+          VariableDeclaration? originalParameter =
+              originalParameters[synthesizedParameter.name!];
+          if (originalParameter != null) {
+            cloneInitializer(originalParameter, synthesizedParameter);
+          } else {
+            // Error case: use `null` as initializer.
+            synthesizedParameter.initializer = new NullLiteral()
+              ..parent = synthesizedParameter;
+          }
+        }
       }
     }
   }
diff --git a/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart b/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
index 67ffb10..5bdcbaa 100644
--- a/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart
@@ -282,7 +282,8 @@
     if (declaration is ClassBuilder &&
         targetType is InterfaceType &&
         typedef.typeParameters.isNotEmpty &&
-        !isProperRenameForClass(library.loader.typeEnvironment, typedef)) {
+        !isProperRenameForClass(
+            library.loader.typeEnvironment, typedef, library.library)) {
       tearOffs = {};
       _tearOffDependencies = {};
       declaration
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 150c716..14694ef 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -144,6 +144,8 @@
 c7a
 c8a
 c8b
+c8c
+c8d
 ca
 cafebabe
 calloc
@@ -386,6 +388,7 @@
 f6b
 f7a
 f8a
+f8b
 fac
 faking
 falling
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart
new file mode 100644
index 0000000..78a304a
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// From co19/Language/Types/Type_Aliases/scope_t02
+
+class A {}
+
+class C<T> {}
+
+typedef AAlias = A;
+typedef CAlias<T> = C<T>;
+
+typedef AAlias = A; //  error
+typedef AAlias = C<String>; // error
+typedef CAlias<T> = C<T>; //  error
+typedef CAlias = C<String>; //  error
+typedef CAlias<T1, T2> = C<T1>; //  error
+
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.strong.expect
new file mode 100644
index 0000000..a612cdc
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.strong.expect
@@ -0,0 +1,59 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:14:9: Error: 'AAlias' is already declared in this scope.
+// typedef AAlias = A; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:11:9: Context: Previous declaration of 'AAlias'.
+// typedef AAlias = A;
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:15:9: Error: 'AAlias' is already declared in this scope.
+// typedef AAlias = C<String>; // error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:14:9: Context: Previous declaration of 'AAlias'.
+// typedef AAlias = A; //  error
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:16:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias<T> = C<T>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:12:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias<T> = C<T>;
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:17:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias = C<String>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:16:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias<T> = C<T>; //  error
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:18:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias<T1, T2> = C<T1>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:17:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias = C<String>; //  error
+//         ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef AAlias = self::A;
+typedef CAlias<T extends core::Object? = dynamic> = self::C<T%>;
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff() → self::A
+    return new self::A::•();
+}
+class C<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T%>
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::C<self::C::_#new#tearOff::T%>
+    return new self::C::•<self::C::_#new#tearOff::T%>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.strong.transformed.expect
new file mode 100644
index 0000000..a612cdc
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.strong.transformed.expect
@@ -0,0 +1,59 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:14:9: Error: 'AAlias' is already declared in this scope.
+// typedef AAlias = A; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:11:9: Context: Previous declaration of 'AAlias'.
+// typedef AAlias = A;
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:15:9: Error: 'AAlias' is already declared in this scope.
+// typedef AAlias = C<String>; // error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:14:9: Context: Previous declaration of 'AAlias'.
+// typedef AAlias = A; //  error
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:16:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias<T> = C<T>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:12:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias<T> = C<T>;
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:17:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias = C<String>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:16:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias<T> = C<T>; //  error
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:18:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias<T1, T2> = C<T1>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:17:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias = C<String>; //  error
+//         ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef AAlias = self::A;
+typedef CAlias<T extends core::Object? = dynamic> = self::C<T%>;
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff() → self::A
+    return new self::A::•();
+}
+class C<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T%>
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::C<self::C::_#new#tearOff::T%>
+    return new self::C::•<self::C::_#new#tearOff::T%>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.textual_outline.expect
new file mode 100644
index 0000000..43abe4c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.textual_outline.expect
@@ -0,0 +1,12 @@
+class A {}
+
+class C<T> {}
+
+typedef AAlias = A;
+typedef CAlias<T> = C<T>;
+typedef AAlias = A;
+typedef AAlias = C<String>;
+typedef CAlias<T> = C<T>;
+typedef CAlias = C<String>;
+typedef CAlias<T1, T2> = C<T1>;
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..213093e
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.textual_outline_modelled.expect
@@ -0,0 +1,12 @@
+class A {}
+
+class C<T> {}
+
+main() {}
+typedef AAlias = A;
+typedef AAlias = A;
+typedef AAlias = C<String>;
+typedef CAlias<T> = C<T>;
+typedef CAlias<T> = C<T>;
+typedef CAlias<T1, T2> = C<T1>;
+typedef CAlias = C<String>;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.weak.expect
new file mode 100644
index 0000000..a612cdc
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.weak.expect
@@ -0,0 +1,59 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:14:9: Error: 'AAlias' is already declared in this scope.
+// typedef AAlias = A; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:11:9: Context: Previous declaration of 'AAlias'.
+// typedef AAlias = A;
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:15:9: Error: 'AAlias' is already declared in this scope.
+// typedef AAlias = C<String>; // error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:14:9: Context: Previous declaration of 'AAlias'.
+// typedef AAlias = A; //  error
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:16:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias<T> = C<T>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:12:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias<T> = C<T>;
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:17:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias = C<String>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:16:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias<T> = C<T>; //  error
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:18:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias<T1, T2> = C<T1>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:17:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias = C<String>; //  error
+//         ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef AAlias = self::A;
+typedef CAlias<T extends core::Object? = dynamic> = self::C<T%>;
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff() → self::A
+    return new self::A::•();
+}
+class C<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T%>
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::C<self::C::_#new#tearOff::T%>
+    return new self::C::•<self::C::_#new#tearOff::T%>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.weak.outline.expect
new file mode 100644
index 0000000..47b5558
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.weak.outline.expect
@@ -0,0 +1,58 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:14:9: Error: 'AAlias' is already declared in this scope.
+// typedef AAlias = A; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:11:9: Context: Previous declaration of 'AAlias'.
+// typedef AAlias = A;
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:15:9: Error: 'AAlias' is already declared in this scope.
+// typedef AAlias = C<String>; // error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:14:9: Context: Previous declaration of 'AAlias'.
+// typedef AAlias = A; //  error
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:16:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias<T> = C<T>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:12:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias<T> = C<T>;
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:17:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias = C<String>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:16:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias<T> = C<T>; //  error
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:18:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias<T1, T2> = C<T1>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:17:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias = C<String>; //  error
+//         ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef AAlias = self::A;
+typedef CAlias<T extends core::Object? = dynamic> = self::C<T%>;
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    ;
+  static method _#new#tearOff() → self::A
+    return new self::A::•();
+}
+class C<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T%>
+    ;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::C<self::C::_#new#tearOff::T%>
+    return new self::C::•<self::C::_#new#tearOff::T%>();
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.weak.transformed.expect
new file mode 100644
index 0000000..a612cdc
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart.weak.transformed.expect
@@ -0,0 +1,59 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:14:9: Error: 'AAlias' is already declared in this scope.
+// typedef AAlias = A; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:11:9: Context: Previous declaration of 'AAlias'.
+// typedef AAlias = A;
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:15:9: Error: 'AAlias' is already declared in this scope.
+// typedef AAlias = C<String>; // error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:14:9: Context: Previous declaration of 'AAlias'.
+// typedef AAlias = A; //  error
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:16:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias<T> = C<T>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:12:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias<T> = C<T>;
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:17:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias = C<String>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:16:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias<T> = C<T>; //  error
+//         ^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:18:9: Error: 'CAlias' is already declared in this scope.
+// typedef CAlias<T1, T2> = C<T1>; //  error
+//         ^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/duplicate_typedefs.dart:17:9: Context: Previous declaration of 'CAlias'.
+// typedef CAlias = C<String>; //  error
+//         ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef AAlias = self::A;
+typedef CAlias<T extends core::Object? = dynamic> = self::C<T%>;
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff() → self::A
+    return new self::A::•();
+}
+class C<T extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T%>
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::C<self::C::_#new#tearOff::T%>
+    return new self::C::•<self::C::_#new#tearOff::T%>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart
new file mode 100644
index 0000000..6b12c8a
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2011, 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.
+
+abstract class Link<T> {
+  factory Link.create1() = LinkFactory<T>.create;
+  factory Link.create2() = LinkFactory<T, T>.create;
+  factory Link.create3(int i) = LinkFactory.create;
+  factory Link.create4({int i}) = LinkFactory.create;
+}
+
+class LinkFactory {
+  factory Link.create() {
+    return null;
+  }
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.strong.expect
new file mode 100644
index 0000000..165ec42
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.strong.expect
@@ -0,0 +1,53 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:11:11: Error: The name of a constructor must match the name of the enclosing class.
+//   factory Link.create() {
+//           ^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:10:7: Context: The name of the enclosing class is 'LinkFactory'.
+// class LinkFactory {
+//       ^^^^^^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:27: Error: Expected 0 type arguments.
+//   factory Link.create() = LinkFactory<T>.create;
+//                           ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:28: Error: Expected 0 type arguments.
+//   factory Link.create2() = LinkFactory<T, T>.create;
+//                            ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:12:12: Error: The value 'null' can't be returned from a function with return type 'LinkFactory' because 'LinkFactory' is not nullable.
+//  - 'LinkFactory' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart'.
+//     return null;
+//            ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class Link<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Link::create, self::Link::create2]/*isLegacy*/;
+  static factory create<T extends core::Object? = dynamic>() → self::Link<self::Link::create::T%>
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:27: Error: Expected 0 type arguments.
+  factory Link.create() = LinkFactory<T>.create;
+                          ^";
+  static method _#create#tearOff<T extends core::Object? = dynamic>() → self::Link<self::Link::_#create#tearOff::T%>
+    return self::LinkFactory::create();
+  static factory create2<T extends core::Object? = dynamic>() → self::Link<self::Link::create2::T%>
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:28: Error: Expected 0 type arguments.
+  factory Link.create2() = LinkFactory<T, T>.create;
+                           ^";
+  static method _#create2#tearOff<T extends core::Object? = dynamic>() → self::Link<self::Link::_#create2#tearOff::T%>
+    return self::LinkFactory::create();
+}
+class LinkFactory extends core::Object {
+  static factory create() → self::LinkFactory {
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:12:12: Error: The value 'null' can't be returned from a function with return type 'LinkFactory' because 'LinkFactory' is not nullable.
+ - 'LinkFactory' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart'.
+    return null;
+           ^" in null as{TypeError,ForNonNullableByDefault} self::LinkFactory;
+  }
+  static method _#create#tearOff() → self::LinkFactory
+    return self::LinkFactory::create();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.strong.transformed.expect
new file mode 100644
index 0000000..b814114
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.strong.transformed.expect
@@ -0,0 +1,57 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:11: Error: 'Link.create' is already declared in this scope.
+//   factory Link.create() = LinkFactory<T, S>.create;
+//           ^^^^^^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:11: Context: Previous declaration of 'Link.create'.
+//   factory Link.create() = LinkFactory<T>.create;
+//           ^^^^^^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:11:11: Error: The name of a constructor must match the name of the enclosing class.
+//   factory Link.create() {
+//           ^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:10:7: Context: The name of the enclosing class is 'LinkFactory'.
+// class LinkFactory {
+//       ^^^^^^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:42: Error: Type 'S' not found.
+//   factory Link.create() = LinkFactory<T, S>.create;
+//                                          ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:27: Error: Expected 0 type arguments.
+//   factory Link.create() = LinkFactory<T, S>.create;
+//                           ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:27: Error: Expected 0 type arguments.
+//   factory Link.create() = LinkFactory<T>.create;
+//                           ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:12:12: Error: The value 'null' can't be returned from a function with return type 'LinkFactory' because 'LinkFactory' is not nullable.
+//  - 'LinkFactory' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart'.
+//     return null;
+//            ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class Link<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Link::create]/*isLegacy*/;
+  static factory create<T extends core::Object? = dynamic>() → self::Link<self::Link::create::T%>
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:27: Error: Expected 0 type arguments.
+  factory Link.create() = LinkFactory<T>.create;
+                          ^";
+  static method _#create#tearOff<T extends core::Object? = dynamic>() → self::Link<self::Link::_#create#tearOff::T%>;
+}
+class LinkFactory extends core::Object {
+  static factory create() → self::LinkFactory {
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:12:12: Error: The value 'null' can't be returned from a function with return type 'LinkFactory' because 'LinkFactory' is not nullable.
+ - 'LinkFactory' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart'.
+    return null;
+           ^" in let Null #t1 = null in #t1 == null ?{self::LinkFactory} #t1 as{TypeError,ForNonNullableByDefault} self::LinkFactory : #t1{self::LinkFactory};
+  }
+  static method _#create#tearOff() → self::LinkFactory
+    return self::LinkFactory::create();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.textual_outline.expect
new file mode 100644
index 0000000..fcd783b
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.textual_outline.expect
@@ -0,0 +1,12 @@
+abstract class Link<T> {
+  factory Link.create1() = LinkFactory<T>.create;
+  factory Link.create2() = LinkFactory<T, T>.create;
+  factory Link.create3(int i) = LinkFactory.create;
+  factory Link.create4({int i}) = LinkFactory.create;
+}
+
+class LinkFactory {
+  factory Link.create() {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..fcd783b
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.textual_outline_modelled.expect
@@ -0,0 +1,12 @@
+abstract class Link<T> {
+  factory Link.create1() = LinkFactory<T>.create;
+  factory Link.create2() = LinkFactory<T, T>.create;
+  factory Link.create3(int i) = LinkFactory.create;
+  factory Link.create4({int i}) = LinkFactory.create;
+}
+
+class LinkFactory {
+  factory Link.create() {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.weak.expect
new file mode 100644
index 0000000..165ec42
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.weak.expect
@@ -0,0 +1,53 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:11:11: Error: The name of a constructor must match the name of the enclosing class.
+//   factory Link.create() {
+//           ^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:10:7: Context: The name of the enclosing class is 'LinkFactory'.
+// class LinkFactory {
+//       ^^^^^^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:27: Error: Expected 0 type arguments.
+//   factory Link.create() = LinkFactory<T>.create;
+//                           ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:28: Error: Expected 0 type arguments.
+//   factory Link.create2() = LinkFactory<T, T>.create;
+//                            ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:12:12: Error: The value 'null' can't be returned from a function with return type 'LinkFactory' because 'LinkFactory' is not nullable.
+//  - 'LinkFactory' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart'.
+//     return null;
+//            ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class Link<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Link::create, self::Link::create2]/*isLegacy*/;
+  static factory create<T extends core::Object? = dynamic>() → self::Link<self::Link::create::T%>
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:27: Error: Expected 0 type arguments.
+  factory Link.create() = LinkFactory<T>.create;
+                          ^";
+  static method _#create#tearOff<T extends core::Object? = dynamic>() → self::Link<self::Link::_#create#tearOff::T%>
+    return self::LinkFactory::create();
+  static factory create2<T extends core::Object? = dynamic>() → self::Link<self::Link::create2::T%>
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:28: Error: Expected 0 type arguments.
+  factory Link.create2() = LinkFactory<T, T>.create;
+                           ^";
+  static method _#create2#tearOff<T extends core::Object? = dynamic>() → self::Link<self::Link::_#create2#tearOff::T%>
+    return self::LinkFactory::create();
+}
+class LinkFactory extends core::Object {
+  static factory create() → self::LinkFactory {
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:12:12: Error: The value 'null' can't be returned from a function with return type 'LinkFactory' because 'LinkFactory' is not nullable.
+ - 'LinkFactory' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart'.
+    return null;
+           ^" in null as{TypeError,ForNonNullableByDefault} self::LinkFactory;
+  }
+  static method _#create#tearOff() → self::LinkFactory
+    return self::LinkFactory::create();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.weak.outline.expect
new file mode 100644
index 0000000..3de7ee2
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.weak.outline.expect
@@ -0,0 +1,45 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:11:11: Error: The name of a constructor must match the name of the enclosing class.
+//   factory Link.create() {
+//           ^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:10:7: Context: The name of the enclosing class is 'LinkFactory'.
+// class LinkFactory {
+//       ^^^^^^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:27: Error: Expected 0 type arguments.
+//   factory Link.create() = LinkFactory<T>.create;
+//                           ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:28: Error: Expected 0 type arguments.
+//   factory Link.create2() = LinkFactory<T, T>.create;
+//                            ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class Link<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Link::create, self::Link::create2]/*isLegacy*/;
+  static factory create<T extends core::Object? = dynamic>() → self::Link<self::Link::create::T%>
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:27: Error: Expected 0 type arguments.
+  factory Link.create() = LinkFactory<T>.create;
+                          ^";
+  static method _#create#tearOff<T extends core::Object? = dynamic>() → self::Link<self::Link::_#create#tearOff::T%>
+    return self::LinkFactory::create();
+  static factory create2<T extends core::Object? = dynamic>() → self::Link<self::Link::create2::T%>
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:28: Error: Expected 0 type arguments.
+  factory Link.create2() = LinkFactory<T, T>.create;
+                           ^";
+  static method _#create2#tearOff<T extends core::Object? = dynamic>() → self::Link<self::Link::_#create2#tearOff::T%>
+    return self::LinkFactory::create();
+}
+class LinkFactory extends core::Object {
+  static factory create() → self::LinkFactory
+    ;
+  static method _#create#tearOff() → self::LinkFactory
+    return self::LinkFactory::create();
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.weak.transformed.expect
new file mode 100644
index 0000000..e14fbed
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart.weak.transformed.expect
@@ -0,0 +1,57 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:11: Error: 'Link.create' is already declared in this scope.
+//   factory Link.create() = LinkFactory<T, S>.create;
+//           ^^^^^^^^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:11: Context: Previous declaration of 'Link.create'.
+//   factory Link.create() = LinkFactory<T>.create;
+//           ^^^^^^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:11:11: Error: The name of a constructor must match the name of the enclosing class.
+//   factory Link.create() {
+//           ^^^^
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:10:7: Context: The name of the enclosing class is 'LinkFactory'.
+// class LinkFactory {
+//       ^^^^^^^^^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:42: Error: Type 'S' not found.
+//   factory Link.create() = LinkFactory<T, S>.create;
+//                                          ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:7:27: Error: Expected 0 type arguments.
+//   factory Link.create() = LinkFactory<T, S>.create;
+//                           ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:27: Error: Expected 0 type arguments.
+//   factory Link.create() = LinkFactory<T>.create;
+//                           ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:12:12: Error: The value 'null' can't be returned from a function with return type 'LinkFactory' because 'LinkFactory' is not nullable.
+//  - 'LinkFactory' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart'.
+//     return null;
+//            ^
+//
+import self as self;
+import "dart:core" as core;
+
+abstract class Link<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Link::create]/*isLegacy*/;
+  static factory create<T extends core::Object? = dynamic>() → self::Link<self::Link::create::T%>
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:6:27: Error: Expected 0 type arguments.
+  factory Link.create() = LinkFactory<T>.create;
+                          ^";
+  static method _#create#tearOff<T extends core::Object? = dynamic>() → self::Link<self::Link::_#create#tearOff::T%>;
+}
+class LinkFactory extends core::Object {
+  static factory create() → self::LinkFactory {
+    return invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart:12:12: Error: The value 'null' can't be returned from a function with return type 'LinkFactory' because 'LinkFactory' is not nullable.
+ - 'LinkFactory' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/invalid_redirect.dart'.
+    return null;
+           ^" in null;
+  }
+  static method _#create#tearOff() → self::LinkFactory
+    return self::LinkFactory::create();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart
index 765da64..bb04095 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart
@@ -85,10 +85,12 @@
 
 class Class8a<T> implements Class8b<T> {
   Class8a();
+  factory Class8a.fact() => new Class8a();
 }
 
 class Class8b<T> {
   factory Class8b() = Class8a<T>;
+  factory Class8b.fact() = Class8a<T>.fact;
 }
 
 testArgs() {
@@ -174,6 +176,15 @@
   expect(true, c8b is Class8a<int>);
   expect(true, c8b is Class8b<int>);
   expect(false, c8b is Class8b<String>);
+
+  var f8b = Class8b.fact;
+  var c8c = f8b();
+  expect(true, c8c is Class8a);
+  expect(true, c8c is Class8b);
+  var c8d = f8b<int>();
+  expect(true, c8d is Class8a<int>);
+  expect(true, c8d is Class8b<int>);
+  expect(false, c8d is Class8b<String>);
 }
 
 expect(expected, actual) {
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect
index 8356f0d..c74b167 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect
@@ -2,43 +2,43 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:101:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f3a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:102:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f3a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:117:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f4a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:131:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f5a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:132:8: Error: Too many positional arguments: 2 allowed, but 3 found.
 // Try removing the extra positional arguments.
 //     f5a(42, 87, 123); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f6a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Required named parameter 'field3' must be provided.
 //     f6a(42); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:146:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f6a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:147:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f6a(field1: 87, field2: 87); // error
 //        ^
 //
@@ -148,13 +148,21 @@
     ;
   static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#new#tearOff::T%>
     return new self::Class8a::•<self::Class8a::_#new#tearOff::T%>();
+  static factory fact<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::fact::T%>
+    return new self::Class8a::•<self::Class8a::fact::T%>();
+  static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#fact#tearOff::T%>
+    return self::Class8a::fact<self::Class8a::_#fact#tearOff::T%>();
 }
 class Class8b<T extends core::Object? = dynamic> extends core::Object {
-  static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+  static final field dynamic _redirecting# = <dynamic>[self::Class8b::•, self::Class8b::fact]/*isLegacy*/;
   static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
     return new self::Class8a::•<self::Class8b::•::T%>();
   static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#new#tearOff::T%>
     return new self::Class8a::•<self::Class8b::_#new#tearOff::T%>();
+  static factory fact<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::fact::T%>
+    return self::Class8a::fact<self::Class8b::fact::T%>();
+  static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#fact#tearOff::T%>
+    return self::Class8a::fact<self::Class8b::_#fact#tearOff::T%>();
 }
 static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
 static method main() → dynamic {
@@ -183,10 +191,10 @@
   self::Class3 c3a = f3a(42){(core::int) → self::Class3};
   self::expect(42, c3a.{self::Class3::field}{core::int});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:101:8: Error: Too few positional arguments: 1 required, 0 given.
     f3a(); // error
        ^" in f3a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:102:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f3a(42, 87); // error
        ^" in f3a{<inapplicable>}.(42, 87);
@@ -202,7 +210,7 @@
   self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
   self::expect(42, c4b.{self::Class4::field}{core::int?});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:117:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f4a(42, 87); // error
        ^" in f4a{<inapplicable>}.(42, 87);
@@ -217,10 +225,10 @@
   self::expect(87, c5b.{self::Class5::field1}{core::int});
   self::expect(42, c5b.{self::Class5::field2}{core::int?});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:131:8: Error: Too few positional arguments: 1 required, 0 given.
     f5a(); // error
        ^" in f5a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:132:8: Error: Too many positional arguments: 2 allowed, but 3 found.
 Try removing the extra positional arguments.
     f5a(42, 87, 123); // error
        ^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -234,17 +242,17 @@
   self::expect(null, c6a.{self::Class6::field2}{core::int?});
   self::expect(87, c6a.{self::Class6::field3}{core::int});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too few positional arguments: 1 required, 0 given.
     f6a(); // error
        ^" in f6a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Required named parameter 'field3' must be provided.
     f6a(42); // error
        ^" in f6a{<inapplicable>}.(42);
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:146:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f6a(42, 87); // error
        ^" in f6a{<inapplicable>}.(42, 87);
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:147:8: Error: Too few positional arguments: 1 required, 0 given.
     f6a(field1: 87, field2: 87); // error
        ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
   };
@@ -273,12 +281,20 @@
   self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
   self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
   self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
+  <T extends core::Object? = dynamic>() → self::Class8b<T%> f8b = #C10;
+  self::Class8b<dynamic> c8c = f8b<dynamic>(){() → self::Class8b<dynamic>};
+  self::expect(true, c8c is{ForNonNullableByDefault} self::Class8a<dynamic>);
+  self::expect(true, c8c is{ForNonNullableByDefault} self::Class8b<dynamic>);
+  self::Class8b<core::int> c8d = f8b<core::int>(){() → self::Class8b<core::int>};
+  self::expect(true, c8d is{ForNonNullableByDefault} self::Class8a<core::int>);
+  self::expect(true, c8d is{ForNonNullableByDefault} self::Class8b<core::int>);
+  self::expect(false, c8d is{ForNonNullableByDefault} self::Class8b<core::String>);
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
   if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
     throw "Expected ${expected}, actual ${actual}";
 }
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C11}) → dynamic {
   try {
     f(){() → dynamic};
   }
@@ -302,5 +318,6 @@
   #C7 = static-tearoff self::Class6::_#new#tearOff
   #C8 = static-tearoff self::Class7b::_#new#tearOff
   #C9 = static-tearoff self::Class8b::_#new#tearOff
-  #C10 = false
+  #C10 = static-tearoff self::Class8b::_#fact#tearOff
+  #C11 = false
 }
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect
index 6ee2990..46d6ccc 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect
@@ -2,43 +2,43 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:101:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f3a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:102:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f3a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:117:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f4a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:131:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f5a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:132:8: Error: Too many positional arguments: 2 allowed, but 3 found.
 // Try removing the extra positional arguments.
 //     f5a(42, 87, 123); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f6a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Required named parameter 'field3' must be provided.
 //     f6a(42); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:146:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f6a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:147:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f6a(field1: 87, field2: 87); // error
 //        ^
 //
@@ -148,13 +148,21 @@
     ;
   static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#new#tearOff::T%>
     return new self::Class8a::•<self::Class8a::_#new#tearOff::T%>();
+  static factory fact<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::fact::T%>
+    return new self::Class8a::•<self::Class8a::fact::T%>();
+  static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#fact#tearOff::T%>
+    return self::Class8a::fact<self::Class8a::_#fact#tearOff::T%>();
 }
 class Class8b<T extends core::Object? = dynamic> extends core::Object {
-  static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+  static final field dynamic _redirecting# = <dynamic>[self::Class8b::•, self::Class8b::fact]/*isLegacy*/;
   static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
     return new self::Class8a::•<self::Class8b::•::T%>();
   static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#new#tearOff::T%>
     return new self::Class8a::•<self::Class8b::_#new#tearOff::T%>();
+  static factory fact<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::fact::T%>
+    return self::Class8a::fact<self::Class8b::fact::T%>();
+  static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#fact#tearOff::T%>
+    return self::Class8a::fact<self::Class8b::_#fact#tearOff::T%>();
 }
 static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
 static method main() → dynamic {
@@ -183,10 +191,10 @@
   self::Class3 c3a = f3a(42){(core::int) → self::Class3};
   self::expect(42, c3a.{self::Class3::field}{core::int});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:101:8: Error: Too few positional arguments: 1 required, 0 given.
     f3a(); // error
        ^" in f3a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:102:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f3a(42, 87); // error
        ^" in f3a{<inapplicable>}.(42, 87);
@@ -202,7 +210,7 @@
   self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
   self::expect(42, c4b.{self::Class4::field}{core::int?});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:117:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f4a(42, 87); // error
        ^" in f4a{<inapplicable>}.(42, 87);
@@ -217,10 +225,10 @@
   self::expect(87, c5b.{self::Class5::field1}{core::int});
   self::expect(42, c5b.{self::Class5::field2}{core::int?});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:131:8: Error: Too few positional arguments: 1 required, 0 given.
     f5a(); // error
        ^" in f5a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:132:8: Error: Too many positional arguments: 2 allowed, but 3 found.
 Try removing the extra positional arguments.
     f5a(42, 87, 123); // error
        ^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -234,17 +242,17 @@
   self::expect(null, c6a.{self::Class6::field2}{core::int?});
   self::expect(87, c6a.{self::Class6::field3}{core::int});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too few positional arguments: 1 required, 0 given.
     f6a(); // error
        ^" in f6a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Required named parameter 'field3' must be provided.
     f6a(42); // error
        ^" in f6a{<inapplicable>}.(42);
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:146:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f6a(42, 87); // error
        ^" in f6a{<inapplicable>}.(42, 87);
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:147:8: Error: Too few positional arguments: 1 required, 0 given.
     f6a(field1: 87, field2: 87); // error
        ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
   };
@@ -273,12 +281,20 @@
   self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
   self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
   self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
+  <T extends core::Object? = dynamic>() → self::Class8b<T%> f8b = #C10;
+  self::Class8b<dynamic> c8c = f8b<dynamic>(){() → self::Class8b<dynamic>};
+  self::expect(true, c8c is{ForNonNullableByDefault} self::Class8a<dynamic>);
+  self::expect(true, c8c is{ForNonNullableByDefault} self::Class8b<dynamic>);
+  self::Class8b<core::int> c8d = f8b<core::int>(){() → self::Class8b<core::int>};
+  self::expect(true, c8d is{ForNonNullableByDefault} self::Class8a<core::int>);
+  self::expect(true, c8d is{ForNonNullableByDefault} self::Class8b<core::int>);
+  self::expect(false, c8d is{ForNonNullableByDefault} self::Class8b<core::String>);
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
   if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
     throw "Expected ${expected}, actual ${actual}";
 }
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C11}) → dynamic {
   try {
     f(){() → dynamic};
   }
@@ -302,5 +318,6 @@
   #C7 = static-tearoff self::Class6::_#new#tearOff
   #C8 = static-tearoff self::Class7b::_#new#tearOff
   #C9 = static-tearoff self::Class8b::_#new#tearOff
-  #C10 = false
+  #C10 = static-tearoff self::Class8b::_#fact#tearOff
+  #C11 = false
 }
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect
index 2fa25d6..7cf5cb1 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect
@@ -51,10 +51,12 @@
 
 class Class8a<T> implements Class8b<T> {
   Class8a();
+  factory Class8a.fact() => new Class8a();
 }
 
 class Class8b<T> {
   factory Class8b() = Class8a<T>;
+  factory Class8b.fact() = Class8a<T>.fact;
 }
 
 testArgs() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
index 0500e74..e522b6c 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
@@ -46,10 +46,12 @@
 
 class Class8a<T> implements Class8b<T> {
   Class8a();
+  factory Class8a.fact() => new Class8a();
 }
 
 class Class8b<T> {
   factory Class8b() = Class8a<T>;
+  factory Class8b.fact() = Class8a<T>.fact;
 }
 
 expect(expected, actual) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect
index 8356f0d..c74b167 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect
@@ -2,43 +2,43 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:101:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f3a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:102:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f3a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:117:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f4a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:131:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f5a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:132:8: Error: Too many positional arguments: 2 allowed, but 3 found.
 // Try removing the extra positional arguments.
 //     f5a(42, 87, 123); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f6a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Required named parameter 'field3' must be provided.
 //     f6a(42); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:146:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f6a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:147:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f6a(field1: 87, field2: 87); // error
 //        ^
 //
@@ -148,13 +148,21 @@
     ;
   static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#new#tearOff::T%>
     return new self::Class8a::•<self::Class8a::_#new#tearOff::T%>();
+  static factory fact<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::fact::T%>
+    return new self::Class8a::•<self::Class8a::fact::T%>();
+  static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#fact#tearOff::T%>
+    return self::Class8a::fact<self::Class8a::_#fact#tearOff::T%>();
 }
 class Class8b<T extends core::Object? = dynamic> extends core::Object {
-  static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+  static final field dynamic _redirecting# = <dynamic>[self::Class8b::•, self::Class8b::fact]/*isLegacy*/;
   static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
     return new self::Class8a::•<self::Class8b::•::T%>();
   static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#new#tearOff::T%>
     return new self::Class8a::•<self::Class8b::_#new#tearOff::T%>();
+  static factory fact<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::fact::T%>
+    return self::Class8a::fact<self::Class8b::fact::T%>();
+  static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#fact#tearOff::T%>
+    return self::Class8a::fact<self::Class8b::_#fact#tearOff::T%>();
 }
 static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
 static method main() → dynamic {
@@ -183,10 +191,10 @@
   self::Class3 c3a = f3a(42){(core::int) → self::Class3};
   self::expect(42, c3a.{self::Class3::field}{core::int});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:101:8: Error: Too few positional arguments: 1 required, 0 given.
     f3a(); // error
        ^" in f3a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:102:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f3a(42, 87); // error
        ^" in f3a{<inapplicable>}.(42, 87);
@@ -202,7 +210,7 @@
   self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
   self::expect(42, c4b.{self::Class4::field}{core::int?});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:117:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f4a(42, 87); // error
        ^" in f4a{<inapplicable>}.(42, 87);
@@ -217,10 +225,10 @@
   self::expect(87, c5b.{self::Class5::field1}{core::int});
   self::expect(42, c5b.{self::Class5::field2}{core::int?});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:131:8: Error: Too few positional arguments: 1 required, 0 given.
     f5a(); // error
        ^" in f5a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:132:8: Error: Too many positional arguments: 2 allowed, but 3 found.
 Try removing the extra positional arguments.
     f5a(42, 87, 123); // error
        ^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -234,17 +242,17 @@
   self::expect(null, c6a.{self::Class6::field2}{core::int?});
   self::expect(87, c6a.{self::Class6::field3}{core::int});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too few positional arguments: 1 required, 0 given.
     f6a(); // error
        ^" in f6a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Required named parameter 'field3' must be provided.
     f6a(42); // error
        ^" in f6a{<inapplicable>}.(42);
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:146:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f6a(42, 87); // error
        ^" in f6a{<inapplicable>}.(42, 87);
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:147:8: Error: Too few positional arguments: 1 required, 0 given.
     f6a(field1: 87, field2: 87); // error
        ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
   };
@@ -273,12 +281,20 @@
   self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
   self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
   self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
+  <T extends core::Object? = dynamic>() → self::Class8b<T%> f8b = #C10;
+  self::Class8b<dynamic> c8c = f8b<dynamic>(){() → self::Class8b<dynamic>};
+  self::expect(true, c8c is{ForNonNullableByDefault} self::Class8a<dynamic>);
+  self::expect(true, c8c is{ForNonNullableByDefault} self::Class8b<dynamic>);
+  self::Class8b<core::int> c8d = f8b<core::int>(){() → self::Class8b<core::int>};
+  self::expect(true, c8d is{ForNonNullableByDefault} self::Class8a<core::int>);
+  self::expect(true, c8d is{ForNonNullableByDefault} self::Class8b<core::int>);
+  self::expect(false, c8d is{ForNonNullableByDefault} self::Class8b<core::String>);
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
   if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
     throw "Expected ${expected}, actual ${actual}";
 }
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C11}) → dynamic {
   try {
     f(){() → dynamic};
   }
@@ -302,5 +318,6 @@
   #C7 = static-tearoff self::Class6::_#new#tearOff
   #C8 = static-tearoff self::Class7b::_#new#tearOff
   #C9 = static-tearoff self::Class8b::_#new#tearOff
-  #C10 = false
+  #C10 = static-tearoff self::Class8b::_#fact#tearOff
+  #C11 = false
 }
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect
index e104583..a5fb580 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect
@@ -97,13 +97,21 @@
     ;
   static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#new#tearOff::T%>
     return new self::Class8a::•<self::Class8a::_#new#tearOff::T%>();
+  static factory fact<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::fact::T%>
+    ;
+  static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#fact#tearOff::T%>
+    return self::Class8a::fact<self::Class8a::_#fact#tearOff::T%>();
 }
 class Class8b<T extends core::Object? = dynamic> extends core::Object {
-  static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+  static final field dynamic _redirecting# = <dynamic>[self::Class8b::•, self::Class8b::fact]/*isLegacy*/;
   static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
     return new self::Class8a::•<self::Class8b::•::T%>();
   static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#new#tearOff::T%>
     return new self::Class8a::•<self::Class8b::_#new#tearOff::T%>();
+  static factory fact<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::fact::T%>
+    return self::Class8a::fact<self::Class8b::fact::T%>();
+  static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#fact#tearOff::T%>
+    return self::Class8a::fact<self::Class8b::_#fact#tearOff::T%>();
 }
 static final field core::bool inSoundMode;
 static method main() → dynamic
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect
index 6ee2990..46d6ccc 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect
@@ -2,43 +2,43 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:101:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f3a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:102:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f3a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:117:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f4a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:131:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f5a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:132:8: Error: Too many positional arguments: 2 allowed, but 3 found.
 // Try removing the extra positional arguments.
 //     f5a(42, 87, 123); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f6a(); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Required named parameter 'field3' must be provided.
 //     f6a(42); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:146:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f6a(42, 87); // error
 //        ^
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:147:8: Error: Too few positional arguments: 1 required, 0 given.
 //     f6a(field1: 87, field2: 87); // error
 //        ^
 //
@@ -148,13 +148,21 @@
     ;
   static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#new#tearOff::T%>
     return new self::Class8a::•<self::Class8a::_#new#tearOff::T%>();
+  static factory fact<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::fact::T%>
+    return new self::Class8a::•<self::Class8a::fact::T%>();
+  static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class8a<self::Class8a::_#fact#tearOff::T%>
+    return self::Class8a::fact<self::Class8a::_#fact#tearOff::T%>();
 }
 class Class8b<T extends core::Object? = dynamic> extends core::Object {
-  static final field dynamic _redirecting# = <dynamic>[self::Class8b::•]/*isLegacy*/;
+  static final field dynamic _redirecting# = <dynamic>[self::Class8b::•, self::Class8b::fact]/*isLegacy*/;
   static factory •<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::•::T%>
     return new self::Class8a::•<self::Class8b::•::T%>();
   static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#new#tearOff::T%>
     return new self::Class8a::•<self::Class8b::_#new#tearOff::T%>();
+  static factory fact<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::fact::T%>
+    return self::Class8a::fact<self::Class8b::fact::T%>();
+  static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class8b<self::Class8b::_#fact#tearOff::T%>
+    return self::Class8a::fact<self::Class8b::_#fact#tearOff::T%>();
 }
 static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
 static method main() → dynamic {
@@ -183,10 +191,10 @@
   self::Class3 c3a = f3a(42){(core::int) → self::Class3};
   self::expect(42, c3a.{self::Class3::field}{core::int});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:99:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:101:8: Error: Too few positional arguments: 1 required, 0 given.
     f3a(); // error
        ^" in f3a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:100:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:102:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f3a(42, 87); // error
        ^" in f3a{<inapplicable>}.(42, 87);
@@ -202,7 +210,7 @@
   self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
   self::expect(42, c4b.{self::Class4::field}{core::int?});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:115:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:117:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f4a(42, 87); // error
        ^" in f4a{<inapplicable>}.(42, 87);
@@ -217,10 +225,10 @@
   self::expect(87, c5b.{self::Class5::field1}{core::int});
   self::expect(42, c5b.{self::Class5::field2}{core::int?});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:129:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:131:8: Error: Too few positional arguments: 1 required, 0 given.
     f5a(); // error
        ^" in f5a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:130:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:132:8: Error: Too many positional arguments: 2 allowed, but 3 found.
 Try removing the extra positional arguments.
     f5a(42, 87, 123); // error
        ^" in f5a{<inapplicable>}.(42, 87, 123);
@@ -234,17 +242,17 @@
   self::expect(null, c6a.{self::Class6::field2}{core::int?});
   self::expect(87, c6a.{self::Class6::field3}{core::int});
   () → Null {
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:142:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too few positional arguments: 1 required, 0 given.
     f6a(); // error
        ^" in f6a{<inapplicable>}.();
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:143:8: Error: Required named parameter 'field3' must be provided.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Required named parameter 'field3' must be provided.
     f6a(42); // error
        ^" in f6a{<inapplicable>}.(42);
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:144:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:146:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f6a(42, 87); // error
        ^" in f6a{<inapplicable>}.(42, 87);
-    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:145:8: Error: Too few positional arguments: 1 required, 0 given.
+    invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:147:8: Error: Too few positional arguments: 1 required, 0 given.
     f6a(field1: 87, field2: 87); // error
        ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
   };
@@ -273,12 +281,20 @@
   self::expect(true, c8b is{ForNonNullableByDefault} self::Class8a<core::int>);
   self::expect(true, c8b is{ForNonNullableByDefault} self::Class8b<core::int>);
   self::expect(false, c8b is{ForNonNullableByDefault} self::Class8b<core::String>);
+  <T extends core::Object? = dynamic>() → self::Class8b<T%> f8b = #C10;
+  self::Class8b<dynamic> c8c = f8b<dynamic>(){() → self::Class8b<dynamic>};
+  self::expect(true, c8c is{ForNonNullableByDefault} self::Class8a<dynamic>);
+  self::expect(true, c8c is{ForNonNullableByDefault} self::Class8b<dynamic>);
+  self::Class8b<core::int> c8d = f8b<core::int>(){() → self::Class8b<core::int>};
+  self::expect(true, c8d is{ForNonNullableByDefault} self::Class8a<core::int>);
+  self::expect(true, c8d is{ForNonNullableByDefault} self::Class8b<core::int>);
+  self::expect(false, c8d is{ForNonNullableByDefault} self::Class8b<core::String>);
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
   if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
     throw "Expected ${expected}, actual ${actual}";
 }
-static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C10}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C11}) → dynamic {
   try {
     f(){() → dynamic};
   }
@@ -302,5 +318,6 @@
   #C7 = static-tearoff self::Class6::_#new#tearOff
   #C8 = static-tearoff self::Class7b::_#new#tearOff
   #C9 = static-tearoff self::Class8b::_#new#tearOff
-  #C10 = false
+  #C10 = static-tearoff self::Class8b::_#fact#tearOff
+  #C11 = false
 }
diff --git a/pkg/front_end/testcases/general/bug33298.dart.weak.expect b/pkg/front_end/testcases/general/bug33298.dart.weak.expect
index 397db9f..bac28d2 100644
--- a/pkg/front_end/testcases/general/bug33298.dart.weak.expect
+++ b/pkg/front_end/testcases/general/bug33298.dart.weak.expect
@@ -65,7 +65,7 @@
   core::List<core::String*>* list1 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(a.{self::A::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
   core::List<core::String*>* list2 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(let final self::A* #t1 = a in #t1 == null ?{(core::String*) →* core::String*} null : #t1.{self::A::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
   self::B<core::String*>* b = new self::B::•<core::String*>();
-  core::List<core::String*>* list3 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(b.{self::B::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
+  core::List<core::String*>* list3 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(b.{self::B::call}{(core::String*) →* core::String*} as{TypeError,CovarianceCheck} (core::String*) →* core::String*){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
   core::List<core::String*>* list4 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(let final self::B<core::String*>* #t2 = b in #t2 == null ?{(core::String*) →* core::String*} null : #t2.{self::B::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
   self::C* c = new self::C::•();
   core::List<core::String*>* list5 = <core::String*>["a", "b", "c"].{core::Iterable::map}<core::String*>(c.{self::C::call}{<T extends core::Object* = dynamic>(T*) →* T*}<core::String*>){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
diff --git a/pkg/front_end/testcases/general/bug33298.dart.weak.transformed.expect b/pkg/front_end/testcases/general/bug33298.dart.weak.transformed.expect
index 8f7030e..2fa1eb2 100644
--- a/pkg/front_end/testcases/general/bug33298.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/bug33298.dart.weak.transformed.expect
@@ -65,7 +65,7 @@
   core::List<core::String*>* list1 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(a.{self::A::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
   core::List<core::String*>* list2 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(let final self::A* #t1 = a in #t1 == null ?{(core::String*) →* core::String*} null : #t1.{self::A::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
   self::B<core::String*>* b = new self::B::•<core::String*>();
-  core::List<core::String*>* list3 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(b.{self::B::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
+  core::List<core::String*>* list3 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(b.{self::B::call}{(core::String*) →* core::String*} as{TypeError,CovarianceCheck} (core::String*) →* core::String*){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
   core::List<core::String*>* list4 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(let final self::B<core::String*>* #t2 = b in #t2 == null ?{(core::String*) →* core::String*} null : #t2.{self::B::call}{(core::String*) →* core::String*}){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
   self::C* c = new self::C::•();
   core::List<core::String*>* list5 = core::_GrowableList::_literal3<core::String*>("a", "b", "c").{core::Iterable::map}<core::String*>(c.{self::C::call}{<T extends core::Object* = dynamic>(T*) →* T*}<core::String*>){((core::String*) →* core::String*) →* core::Iterable<core::String*>*}.{core::Iterable::toList}(){({growable: core::bool*}) →* core::List<core::String*>*};
diff --git a/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart
new file mode 100644
index 0000000..8d1ca89
--- /dev/null
+++ b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A<X extends num> {
+  void f<Y extends X>(Y y) {}
+}
+
+expectThrows(void Function() f) {
+  try {
+    f();
+  } catch (e) {
+    return;
+  }
+  throw "Expected an exception to be thrown!";
+}
+
+main() {
+  A<num> a = new A<int>();
+  expectThrows(() {
+    void Function<Y extends num>(Y) f = a.f;
+  });
+}
diff --git a/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.textual_outline.expect b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.textual_outline.expect
new file mode 100644
index 0000000..cf5cf7d
--- /dev/null
+++ b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.textual_outline.expect
@@ -0,0 +1,6 @@
+class A<X extends num> {
+  void f<Y extends X>(Y y) {}
+}
+
+expectThrows(void Function() f) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..cf5cf7d
--- /dev/null
+++ b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.textual_outline_modelled.expect
@@ -0,0 +1,6 @@
+class A<X extends num> {
+  void f<Y extends X>(Y y) {}
+}
+
+expectThrows(void Function() f) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.weak.expect b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.weak.expect
new file mode 100644
index 0000000..b5abc6f
--- /dev/null
+++ b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.weak.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::num> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X>
+    : super core::Object::•()
+    ;
+  method f<generic-covariant-impl Y extends self::A::X>(self::A::f::Y y) → void {}
+}
+static method expectThrows(() → void f) → dynamic {
+  try {
+    f(){() → void};
+  }
+  on core::Object catch(final core::Object e) {
+    return;
+  }
+  throw "Expected an exception to be thrown!";
+}
+static method main() → dynamic {
+  self::A<core::num> a = new self::A::•<core::int>();
+  self::expectThrows(() → void {
+    <Y extends core::num>(Y) → void f = a.{self::A::f}{<generic-covariant-impl Y extends core::num>(Y) → void} as{TypeError,CovarianceCheck,ForNonNullableByDefault} <generic-covariant-impl Y extends core::num>(Y) → void;
+  });
+}
diff --git a/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.weak.outline.expect b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.weak.outline.expect
new file mode 100644
index 0000000..18ac6fe
--- /dev/null
+++ b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.weak.outline.expect
@@ -0,0 +1,14 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::num> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X>
+    ;
+  method f<generic-covariant-impl Y extends self::A::X>(self::A::f::Y y) → void
+    ;
+}
+static method expectThrows(() → void f) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.weak.transformed.expect b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.weak.transformed.expect
new file mode 100644
index 0000000..b5abc6f
--- /dev/null
+++ b/pkg/front_end/testcases/general/method_tearoff_covariant_generic_type_check.dart.weak.transformed.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::num> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X>
+    : super core::Object::•()
+    ;
+  method f<generic-covariant-impl Y extends self::A::X>(self::A::f::Y y) → void {}
+}
+static method expectThrows(() → void f) → dynamic {
+  try {
+    f(){() → void};
+  }
+  on core::Object catch(final core::Object e) {
+    return;
+  }
+  throw "Expected an exception to be thrown!";
+}
+static method main() → dynamic {
+  self::A<core::num> a = new self::A::•<core::int>();
+  self::expectThrows(() → void {
+    <Y extends core::num>(Y) → void f = a.{self::A::f}{<generic-covariant-impl Y extends core::num>(Y) → void} as{TypeError,CovarianceCheck,ForNonNullableByDefault} <generic-covariant-impl Y extends core::num>(Y) → void;
+  });
+}
diff --git a/pkg/front_end/testcases/outline.status b/pkg/front_end/testcases/outline.status
index a59e9fd..428a77b 100644
--- a/pkg/front_end/testcases/outline.status
+++ b/pkg/front_end/testcases/outline.status
@@ -3,6 +3,7 @@
 # BSD-style license that can be found in the LICENSE.md file.
 
 const_functions/const_functions_const_factory: VerificationError
+constructor_tearoffs/lowering/invalid_redirect: VerificationError
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized
 extension_types/simple_getter_resolution: ExpectationFileMismatchSerialized
diff --git a/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart b/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart
index 0d4dd96..11693a1 100644
--- a/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart
+++ b/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart
@@ -15,7 +15,7 @@
 }
 
 F<num> g1(C<num> c) {
-  return c.f1;
+  return c. /*@ checkReturn=(num*) ->* void*/ f1;
 }
 
 void g2(C<int> c, Object x) {
@@ -24,7 +24,7 @@
 }
 
 G<List<num>, num> g3(C<num> c) {
-  return c.f2;
+  return c. /*@ checkReturn=(List<num*>*) ->* num**/ f2;
 }
 
 void test() {
diff --git a/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart.weak.expect b/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart.weak.expect
index 05ac14b..5d38dc5 100644
--- a/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart.weak.expect
+++ b/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart.weak.expect
@@ -23,14 +23,14 @@
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
 static method g1(self::C<core::num*>* c) → (core::num*) →* void {
-  return c.{self::C::f1}{(core::num*) →* void};
+  return c.{self::C::f1}{(core::num*) →* void} as{TypeError,CovarianceCheck} (core::num*) →* void;
 }
 static method g2(self::C<core::int*>* c, core::Object* x) → void {
   (core::Object*) →* void f = self::g1(c) as (core::Object*) →* void;
   f(x){(core::Object*) →* void};
 }
 static method g3(self::C<core::num*>* c) → (core::List<core::num*>*) →* core::num* {
-  return c.{self::C::f2}{(core::List<core::num*>*) →* core::num*};
+  return c.{self::C::f2}{(core::List<core::num*>*) →* core::num*} as{TypeError,CovarianceCheck} (core::List<core::num*>*) →* core::num*;
 }
 static method test() → void {
   (core::num*) →* void x = self::g1(new self::C::•<core::int*>());
diff --git a/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart.weak.transformed.expect
index 05ac14b..5d38dc5 100644
--- a/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/runtime_checks/covariant_generic_parameter_tear_off.dart.weak.transformed.expect
@@ -23,14 +23,14 @@
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
 static method g1(self::C<core::num*>* c) → (core::num*) →* void {
-  return c.{self::C::f1}{(core::num*) →* void};
+  return c.{self::C::f1}{(core::num*) →* void} as{TypeError,CovarianceCheck} (core::num*) →* void;
 }
 static method g2(self::C<core::int*>* c, core::Object* x) → void {
   (core::Object*) →* void f = self::g1(c) as (core::Object*) →* void;
   f(x){(core::Object*) →* void};
 }
 static method g3(self::C<core::num*>* c) → (core::List<core::num*>*) →* core::num* {
-  return c.{self::C::f2}{(core::List<core::num*>*) →* core::num*};
+  return c.{self::C::f2}{(core::List<core::num*>*) →* core::num*} as{TypeError,CovarianceCheck} (core::List<core::num*>*) →* core::num*;
 }
 static method test() → void {
   (core::num*) →* void x = self::g1(new self::C::•<core::int*>());
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 65e627a..5cd897f 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -10,6 +10,7 @@
 
 constructor_tearoffs/call_instantiation: TypeCheckError
 constructor_tearoffs/const_tear_off: RuntimeError
+constructor_tearoffs/lowering/invalid_redirect: VerificationError
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
 extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 9803b19..dc2b0b7 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -8,6 +8,7 @@
 
 constructor_tearoffs/call_instantiation: TypeCheckError
 constructor_tearoffs/const_tear_off: RuntimeError
+constructor_tearoffs/lowering/invalid_redirect: VerificationError
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
 extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 60c84f44..0281cb6 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -13,6 +13,7 @@
 
 constructor_tearoffs/call_instantiation: TypeCheckError
 constructor_tearoffs/const_tear_off: RuntimeError
+constructor_tearoffs/lowering/invalid_redirect: VerificationError
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
 extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index e598523..9581107 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -109,7 +109,9 @@
 /// mapping to be used for replacing other types to use the new type parameters.
 FreshTypeParameters getFreshTypeParameters(List<TypeParameter> typeParameters) {
   List<TypeParameter> freshParameters = new List<TypeParameter>.generate(
-      typeParameters.length, (i) => new TypeParameter(typeParameters[i].name),
+      typeParameters.length,
+      (i) => new TypeParameter(typeParameters[i].name)
+        ..flags = typeParameters[i].flags,
       growable: true);
   List<DartType> freshTypeArguments =
       new List<DartType>.generate(typeParameters.length, (int i) {
@@ -138,8 +140,10 @@
 class FreshTypeParameters {
   /// The newly created type parameters.
   final List<TypeParameter> freshTypeParameters;
+
   /// List of [TypeParameterType]s for [TypeParameter].
   final List<DartType> freshTypeArguments;
+
   /// Substitution from the original type parameters to [freshTypeArguments].
   final Substitution substitution;
 
@@ -389,7 +393,7 @@
   }
 
   TypeParameter freshTypeParameter(TypeParameter node) {
-    TypeParameter fresh = new TypeParameter(node.name);
+    TypeParameter fresh = new TypeParameter(node.name)..flags = node.flags;
     TypeParameterType typeParameterType = substitution[node] =
         new TypeParameterType.forAlphaRenaming(node, fresh);
     fresh.bound = visit(node.bound);
diff --git a/pkg/vm_service/test/cpu_samples_stream_test.dart b/pkg/vm_service/test/cpu_samples_stream_test.dart
index d6846ef..8ef6ff6 100644
--- a/pkg/vm_service/test/cpu_samples_stream_test.dart
+++ b/pkg/vm_service/test/cpu_samples_stream_test.dart
@@ -4,7 +4,8 @@
 
 import 'dart:async';
 
-import 'package:test/test.dart';
+// TODO(bkonyi): re-import after sample streaming is fixed.
+// import 'package:test/test.dart';
 import 'package:vm_service/vm_service.dart';
 
 import 'common/service_test_common.dart';
@@ -31,7 +32,9 @@
 
 var tests = <IsolateTest>[
   (VmService service, IsolateRef isolate) async {
-    final completer = Completer<void>();
+    // TODO(bkonyi): re-enable after sample streaming is fixed.
+    // See https://github.com/dart-lang/sdk/issues/46825
+    /*final completer = Completer<void>();
     int count = 0;
     int previousOrigin = 0;
     sub = service.onProfilerEvent.listen((event) async {
@@ -56,6 +59,7 @@
 
     await completer.future;
     await service.streamCancel(EventStreams.kProfiler);
+    */
   },
 ];
 
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index 108fc91..a3fb4e1 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -127,19 +127,19 @@
                       hot_reload_rollback_test_mode_callback);
 
 void Options::PrintVersion() {
-  Syslog::PrintErr("Dart SDK version: %s\n", Dart_VersionString());
+  Syslog::Print("Dart SDK version: %s\n", Dart_VersionString());
 }
 
 // clang-format off
 void Options::PrintUsage() {
-  Syslog::PrintErr(
+  Syslog::Print(
       "Usage: dart [<vm-flags>] <dart-script-file> [<script-arguments>]\n"
       "\n"
       "Executes the Dart script <dart-script-file> with "
       "the given list of <script-arguments>.\n"
       "\n");
   if (!Options::verbose_option()) {
-    Syslog::PrintErr(
+    Syslog::Print(
 "Common VM flags:\n"
 "--enable-asserts\n"
 "  Enable assert statements.\n"
@@ -176,7 +176,7 @@
 "--version\n"
 "  Print the SDK version.\n");
   } else {
-    Syslog::PrintErr(
+    Syslog::Print(
 "Supported options:\n"
 "--enable-asserts\n"
 "  Enable assert statements.\n"
diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc
index 26ff8e2..49dadd2 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -113,30 +113,29 @@
     }
     switch (type_) {
       case kBoolean: {
-        OS::PrintErr("%s: %s (%s)\n", name_,
-                     *this->bool_ptr_ ? "true" : "false", comment_);
+        OS::Print("%s: %s (%s)\n", name_, *this->bool_ptr_ ? "true" : "false",
+                  comment_);
         break;
       }
       case kInteger: {
-        OS::PrintErr("%s: %d (%s)\n", name_, *this->int_ptr_, comment_);
+        OS::Print("%s: %d (%s)\n", name_, *this->int_ptr_, comment_);
         break;
       }
       case kUint64: {
-        OS::PrintErr("%s: %" Pu64 " (%s)\n", name_, *this->uint64_ptr_,
-                     comment_);
+        OS::Print("%s: %" Pu64 " (%s)\n", name_, *this->uint64_ptr_, comment_);
         break;
       }
       case kString: {
         if (*this->charp_ptr_ != NULL) {
-          OS::PrintErr("%s: '%s' (%s)\n", name_, *this->charp_ptr_, comment_);
+          OS::Print("%s: '%s' (%s)\n", name_, *this->charp_ptr_, comment_);
         } else {
-          OS::PrintErr("%s: (null) (%s)\n", name_, comment_);
+          OS::Print("%s: (null) (%s)\n", name_, comment_);
         }
         break;
       }
       case kOptionHandler:
       case kFlagHandler: {
-        OS::PrintErr("%s: (%s)\n", name_, comment_);
+        OS::Print("%s: (%s)\n", name_, comment_);
         break;
       }
       default:
@@ -499,7 +498,7 @@
 }
 
 void Flags::PrintFlags() {
-  OS::PrintErr("Flag settings:\n");
+  OS::Print("Flag settings:\n");
   for (intptr_t i = 0; i < num_flags_; ++i) {
     flags_[i]->Print();
   }
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 2436574..fae638f 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -306,6 +306,12 @@
   Sample* sample = nullptr;
   if (block != nullptr) {
     sample = block->ReserveSample();
+    if (sample != nullptr && block->is_full()) {
+      // TODO(bkonyi): remove once streaming is re-enabled.
+      // https://github.com/dart-lang/sdk/issues/46825
+      block->evictable_ = true;
+      FreeBlock(block);
+    }
   }
   if (sample != nullptr) {
     return sample;
@@ -330,8 +336,11 @@
     isolate->set_current_sample_block(next);
   }
   next->set_is_allocation_block(allocation_sample);
+
   can_process_block_.store(true);
-  isolate->mutator_thread()->ScheduleInterrupts(Thread::kVMInterrupt);
+  // TODO(bkonyi): re-enable after block streaming is fixed.
+  // See https://github.com/dart-lang/sdk/issues/46825
+  // isolate->mutator_thread()->ScheduleInterrupts(Thread::kVMInterrupt);
   return ReserveSampleImpl(isolate, allocation_sample);
 }
 
diff --git a/tests/language/closure/identity_equality_tearoff_test.dart b/tests/language/closure/identity_equality_tearoff_test.dart
index cdf7585..549f2d4 100644
--- a/tests/language/closure/identity_equality_tearoff_test.dart
+++ b/tests/language/closure/identity_equality_tearoff_test.dart
@@ -40,6 +40,26 @@
 
   void instanceMethod() {}
   X? genericInstanceMethod<X>() => null;
+
+  // Enable a mixed-in method in `M` that has a superinvocation.
+  int mixedInSuperMethod() => 0;
+}
+
+mixin M on A {
+  void mixedInMethod() {}
+  int mixedInSuperMethod() => super.mixedInSuperMethod() + 1;
+}
+
+class AM extends A with M {
+  int Function() get tearoffSuperMethod => super.mixedInSuperMethod;
+}
+
+class AMM extends AM with M {
+  // Tear off the second copy of M.mixedInSuperMethod
+  // (`tearoffSuperMethod` still tears off the first copy).
+  int Function() get tearoffSuperMethodSecond => super.mixedInSuperMethod;
+  // In this case, `super.` should not make a difference.
+  int Function() get tearoffSuperMethodSecondNoSuper => mixedInSuperMethod;
 }
 
 const cTopLevelFunction = topLevelFunction;
@@ -104,6 +124,7 @@
   checkIdentical(cIntStaticMethod1, vIntStaticMethod2);
   checkIdentical(vIntTopLevelFunction1, vIntTopLevelFunction2);
   checkIdentical(vIntStaticMethod1, vIntStaticMethod2);
+  checkEqual(vIntInstanceMethod1, vIntInstanceMethod2);
 
   const CheckIdentical(topLevelFunction, topLevelFunction);
   const CheckIdentical(A.staticMethod, A.staticMethod);
@@ -268,6 +289,56 @@
   const CheckNotIdentical(cIntTopLevelFunction1, cStringTopLevelFunction);
   const CheckNotIdentical(cIntStaticMethod1, cStringStaticMethod);
 
+  {
+    var am = AM();
+    void Function() vMixedInMethod1 = am.mixedInMethod;
+    void Function() vMixedInMethod2 = am.mixedInMethod;
+    int Function() vMixedInSuperMethod1 = am.mixedInSuperMethod;
+    int Function() vMixedInSuperMethod2 = am.mixedInSuperMethod;
+
+    checkEqual(am.mixedInMethod, am.mixedInMethod);
+    checkEqual(vMixedInMethod1, vMixedInMethod2);
+    checkEqual(am.mixedInSuperMethod, am.mixedInSuperMethod);
+    checkEqual(vMixedInSuperMethod1, vMixedInSuperMethod2);
+  }
+  {
+    var amm = AMM();
+    void Function() vMixedInMethod1 = amm.mixedInMethod;
+    void Function() vMixedInMethod2 = amm.mixedInMethod;
+    int Function() vMixedInSuperMethod1 = amm.tearoffSuperMethod;
+    int Function() vMixedInSuperMethod2 = amm.tearoffSuperMethod;
+    int Function() vMixedInSuperMethodSecond1 = amm.tearoffSuperMethodSecond;
+    int Function() vMixedInSuperMethodSecond2 = amm.tearoffSuperMethodSecond;
+    int Function() vMixedInSuperMethodSecondNoSuper1 =
+        amm.tearoffSuperMethodSecondNoSuper;
+    int Function() vMixedInSuperMethodSecondNoSuper2 =
+        amm.tearoffSuperMethodSecondNoSuper;
+
+    checkEqual(amm.mixedInMethod, amm.mixedInMethod);
+    checkEqual(vMixedInMethod1, vMixedInMethod2);
+
+    checkEqual(amm.tearoffSuperMethod, amm.tearoffSuperMethod);
+    checkEqual(vMixedInSuperMethod1, vMixedInSuperMethod2);
+    checkEqual(amm.tearoffSuperMethodSecond, amm.tearoffSuperMethodSecond);
+    checkEqual(vMixedInSuperMethodSecond1, vMixedInSuperMethodSecond2);
+    checkUnequal(amm.tearoffSuperMethod, amm.tearoffSuperMethodSecond);
+    checkUnequal(vMixedInSuperMethod1, vMixedInSuperMethodSecond2);
+    checkUnequal(amm.tearoffSuperMethodSecond, amm.tearoffSuperMethod);
+    checkUnequal(vMixedInSuperMethodSecond1, vMixedInSuperMethod2);
+
+    checkEqual(amm.tearoffSuperMethodSecondNoSuper,
+        amm.tearoffSuperMethodSecondNoSuper);
+    checkEqual(
+        vMixedInSuperMethodSecondNoSuper1, vMixedInSuperMethodSecondNoSuper2);
+    checkUnequal(amm.tearoffSuperMethod, amm.tearoffSuperMethodSecondNoSuper);
+    checkUnequal(vMixedInSuperMethod1, vMixedInSuperMethodSecondNoSuper2);
+    checkUnequal(amm.tearoffSuperMethodSecondNoSuper, amm.tearoffSuperMethod);
+    checkUnequal(vMixedInSuperMethodSecondNoSuper1, vMixedInSuperMethod2);
+
+    checkEqual(
+        amm.tearoffSuperMethodSecond, amm.tearoffSuperMethodSecondNoSuper);
+  }
+
   <X>() {
     X? Function() vXTopLevelFunction1 = genericTopLevelFunction;
     X? Function() vXStaticMethod1 = A.genericStaticMethod;
@@ -276,6 +347,14 @@
     X? Function() vXInstanceMethod1 = a.genericInstanceMethod;
     X? Function() vXInstanceMethod2 = a.genericInstanceMethod;
 
+    checkEqual(vXTopLevelFunction1, vXTopLevelFunction2);
+    checkEqual(vXStaticMethod1, vXStaticMethod2);
+    checkEqual(vXInstanceMethod1, vXInstanceMethod2);
+
+    checkEqual(vXTopLevelFunction1, vIntTopLevelFunction1);
+    checkEqual(vXStaticMethod1, vIntStaticMethod1);
+    checkEqual(vXInstanceMethod1, vIntInstanceMethod2);
+
     checkUnequal(vXTopLevelFunction1, vXStaticMethod1);
     checkUnequal(vXTopLevelFunction1, vXInstanceMethod1);
     checkUnequal(vXStaticMethod1, vXInstanceMethod1);
diff --git a/tests/standalone/io/directory_fuzz_test.dart b/tests/standalone/io/directory_fuzz_test.dart
index 358bcff..0e3cbe6 100644
--- a/tests/standalone/io/directory_fuzz_test.dart
+++ b/tests/standalone/io/directory_fuzz_test.dart
@@ -12,68 +12,75 @@
 import "package:expect/expect.dart";
 
 import 'fuzz_support.dart';
+import 'file_write_only_test.dart' show withTempDir, withTempDirSync;
 
 fuzzSyncMethods() {
-  typeMapping.forEach((k, v) {
-    doItSync(() {
-      Directory.systemTemp.createTempSync(v as String?).deleteSync();
-    });
-    Directory? directory;
-    doItSync(() => directory = new Directory(v as String));
-    if (directory == null) return;
-    final d = directory!;
-    doItSync(d.existsSync);
-    doItSync(d.createSync);
-    doItSync(d.deleteSync);
-    doItSync(d.listSync);
-    doItSync(() {
-      d.createTempSync('tempdir').deleteSync();
-    });
-    doItSync(() {
-      // Let's be a little careful. If the directory exists we don't
-      // want to delete it and all its contents.
-      if (!d.existsSync()) d.deleteSync(recursive: true);
-    });
-    typeMapping.forEach((k2, v2) {
-      doItSync(() => d.renameSync(v2 as String));
-      doItSync(() => d.listSync(recursive: v2 as bool));
+  withTempDirSync('dart_directory_fuzz', (temp) {
+    typeMapping.forEach((k, v) {
+      doItSync(() {
+        Directory.systemTemp.createTempSync("${temp.path}/${v as String}")
+            .deleteSync();
+      });
+      Directory? directory;
+      doItSync(() => directory = new Directory("${temp.path}/${v as String}"));
+      if (directory == null) return;
+      final d = directory!;
+      doItSync(d.existsSync);
+      doItSync(d.createSync);
+      doItSync(d.deleteSync);
+      doItSync(d.listSync);
+      doItSync(() {
+        d.createTempSync('tempdir').deleteSync();
+      });
+      doItSync(() {
+        // Let's be a little careful. If the directory exists we don't
+        // want to delete it and all its contents.
+        if (!d.existsSync()) d.deleteSync(recursive: true);
+      });
+      typeMapping.forEach((k2, v2) {
+        doItSync(() => d.renameSync(v2 as String));
+        doItSync(() => d.listSync(recursive: v2 as bool));
+      });
     });
   });
 }
 
-fuzzAsyncMethods() {
+fuzzAsyncMethods() async {
   asyncStart();
-  var futures = <Future>[];
-  typeMapping.forEach((k, v) {
-    futures.add(doItAsync(() {
-      Directory.systemTemp.createTempSync(v as String?).deleteSync();
-    }));
-    if (v is! String) {
-      return;
-    }
-    var d = new Directory(v);
-    futures.add(doItAsync(d.exists));
-    futures.add(doItAsync(d.create));
-    futures.add(doItAsync(d.delete));
-    futures.add(doItAsync(() {
-      return d.createTemp('tempdir').then((temp) {
-        return temp.delete();
-      });
-    }));
-    futures.add(doItAsync(() {
-      return d.exists().then((res) {
-        if (!res) return d.delete(recursive: true);
-        return new Future.value(true);
-      });
-    }));
-    typeMapping.forEach((k2, v2) {
-      futures.add(doItAsync(() => d.rename(v2 as String)));
+  await withTempDir('dart_directory_fuzz', (temp) async {
+    final futures = <Future>[];
+    typeMapping.forEach((k, v) {
       futures.add(doItAsync(() {
-        d.list(recursive: v2 as bool).listen((_) {}, onError: (e) => null);
+        Directory.systemTemp.createTempSync("${temp.path}/${v as String}")
+            .deleteSync();
       }));
+      if (v is! String) {
+        return;
+      }
+      var d = new Directory("${temp.path}/$v");
+      futures.add(doItAsync(d.exists));
+      futures.add(doItAsync(d.create));
+      futures.add(doItAsync(d.delete));
+      futures.add(doItAsync(() {
+        return d.createTemp('tempdir').then((temp) {
+          return temp.delete();
+        });
+      }));
+      futures.add(doItAsync(() {
+        return d.exists().then((res) {
+          if (!res) return d.delete(recursive: true);
+          return new Future.value(true);
+        });
+      }));
+      typeMapping.forEach((k2, v2) {
+        futures.add(doItAsync(() => d.rename(v2 as String)));
+        futures.add(doItAsync(() {
+          d.list(recursive: v2 as bool).listen((_) {}, onError: (e) => null);
+        }));
+      });
     });
+    await Future.wait(futures).then((_) => asyncEnd());
   });
-  Future.wait(futures).then((_) => asyncEnd());
 }
 
 main() {
diff --git a/tests/standalone_2/io/directory_fuzz_test.dart b/tests/standalone_2/io/directory_fuzz_test.dart
index 227058d6..c3a8e6a 100644
--- a/tests/standalone_2/io/directory_fuzz_test.dart
+++ b/tests/standalone_2/io/directory_fuzz_test.dart
@@ -14,69 +14,74 @@
 import "package:expect/expect.dart";
 
 import 'fuzz_support.dart';
+import 'file_write_only_test.dart' show withTempDir, withTempDirSync;
 
 fuzzSyncMethods() {
-  typeMapping.forEach((k, v) {
-    doItSync(() {
-      Directory.systemTemp.createTempSync(v).deleteSync();
-    });
-    Directory d;
-    doItSync(() => d = new Directory(v));
-    if (d == null) return;
-    doItSync(d.existsSync);
-    doItSync(d.createSync);
-    doItSync(d.deleteSync);
-    doItSync(d.listSync);
-    doItSync(() {
-      d.createTempSync('tempdir').deleteSync();
-    });
-    doItSync(() {
-      // Let's be a little careful. If the directory exists we don't
-      // want to delete it and all its contents.
-      if (!d.existsSync()) d.deleteSync(recursive: true);
-    });
-    typeMapping.forEach((k2, v2) {
-      doItSync(() => d.renameSync(v2));
-      doItSync(() => d.listSync(recursive: v2));
+  withTempDirSync('dart_directory_fuzz', (temp) {
+    typeMapping.forEach((k, v) {
+      doItSync(() {
+        Directory.systemTemp.createTempSync("${temp.path}/$v").deleteSync();
+      });
+      Directory d;
+      doItSync(() => d = new Directory("${temp.path}/$v"));
+      if (d == null) return;
+      doItSync(d.existsSync);
+      doItSync(d.createSync);
+      doItSync(d.deleteSync);
+      doItSync(d.listSync);
+      doItSync(() {
+        d.createTempSync('tempdir').deleteSync();
+      });
+      doItSync(() {
+        // Let's be a little careful. If the directory exists we don't
+        // want to delete it and all its contents.
+        if (!d.existsSync()) d.deleteSync(recursive: true);
+      });
+      typeMapping.forEach((k2, v2) {
+        doItSync(() => d.renameSync(v2));
+        doItSync(() => d.listSync(recursive: v2));
+      });
     });
   });
 }
 
-fuzzAsyncMethods() {
+fuzzAsyncMethods() async {
   asyncStart();
-  var futures = <Future>[];
-  typeMapping.forEach((k, v) {
-    futures.add(doItAsync(() {
-      Directory.systemTemp.createTempSync(v).deleteSync();
-    }));
-    if (v is! String) {
-      Expect.throws(() => new Directory(v),
-                    (e) => e is ArgumentError || e is TypeError);
-      return;
-    }
-    var d = new Directory(v);
-    futures.add(doItAsync(d.exists));
-    futures.add(doItAsync(d.create));
-    futures.add(doItAsync(d.delete));
-    futures.add(doItAsync(() {
-      return d.createTemp('tempdir').then((temp) {
-        return temp.delete();
-      });
-    }));
-    futures.add(doItAsync(() {
-      return d.exists().then((res) {
-        if (!res) return d.delete(recursive: true);
-        return new Future.value(true);
-      });
-    }));
-    typeMapping.forEach((k2, v2) {
-      futures.add(doItAsync(() => d.rename(v2)));
+  await withTempDir('dart_directory_fuzz', (temp) async {
+    final futures = <Future>[];
+    typeMapping.forEach((k, v) {
       futures.add(doItAsync(() {
-        d.list(recursive: v2).listen((_) {}, onError: (e) => null);
+        Directory.systemTemp.createTempSync("${temp.path}/$v").deleteSync();
       }));
+      if (v is! String) {
+        Expect.throws(() => new Directory(v),
+                      (e) => e is ArgumentError || e is TypeError);
+        return;
+      }
+      var d = new Directory("${temp.path}/$v");
+      futures.add(doItAsync(d.exists));
+      futures.add(doItAsync(d.create));
+      futures.add(doItAsync(d.delete));
+      futures.add(doItAsync(() {
+        return d.createTemp('tempdir').then((temp) {
+          return temp.delete();
+        });
+      }));
+      futures.add(doItAsync(() {
+        return d.exists().then((res) {
+          if (!res) return d.delete(recursive: true);
+          return new Future.value(true);
+        });
+      }));
+      typeMapping.forEach((k2, v2) {
+        futures.add(doItAsync(() => d.rename(v2)));
+        futures.add(doItAsync(() {
+          d.list(recursive: v2).listen((_) {}, onError: (e) => null);
+        }));
+      });
     });
+    await Future.wait(futures).then((_) => asyncEnd());
   });
-  Future.wait(futures).then((_) => asyncEnd());
 }
 
 main() {
diff --git a/tools/VERSION b/tools/VERSION
index c9d32db..5b78760 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 386
+PRERELEASE 387
 PRERELEASE_PATCH 0
\ No newline at end of file