Version 2.14.0-340.0.dev

Merge commit 'f258c7fe62cdce70ef3c0a8d52505167cf433d76' into 'dev'
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
index ed17c2a..20c4d27 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/perform_refactor.dart
@@ -14,6 +14,8 @@
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/analysis/session.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
 
 final _manager = _RefactorManager();
 
@@ -173,6 +175,32 @@
             InlineMethodRefactoring(server.searchEngine, result, offset);
         return success(refactor);
 
+      case RefactoringKind.CONVERT_GETTER_TO_METHOD:
+        final node = NodeLocator(offset).searchWithin(result.unit);
+        final element = server.getElementOfNode(node);
+        if (element != null) {
+          if (element is PropertyAccessorElement) {
+            final refactor = ConvertGetterToMethodRefactoring(
+                server.searchEngine, result.session, element);
+            return success(refactor);
+          }
+        }
+        return error(ServerErrorCodes.InvalidCommandArguments,
+            'Location supplied to $commandName $kind is not longer valid');
+
+      case RefactoringKind.CONVERT_METHOD_TO_GETTER:
+        final node = NodeLocator(offset).searchWithin(result.unit);
+        final element = server.getElementOfNode(node);
+        if (element != null) {
+          if (element is ExecutableElement) {
+            final refactor = ConvertMethodToGetterRefactoring(
+                server.searchEngine, result.session, element);
+            return success(refactor);
+          }
+        }
+        return error(ServerErrorCodes.InvalidCommandArguments,
+            'Location supplied to $commandName $kind is not longer valid');
+
       default:
         return error(ServerErrorCodes.InvalidCommandArguments,
             'Unknown RefactoringKind $kind was supplied to $commandName');
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 0fb95ee..8ccb4bf 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -21,7 +21,9 @@
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/analysis/session.dart'
     show InconsistentAnalysisException;
+import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/error.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:collection/collection.dart' show groupBy;
 
@@ -428,6 +430,28 @@
         }
       }
 
+      // Converts/Rewrites
+      if (shouldIncludeKind(CodeActionKind.RefactorRewrite)) {
+        final node = NodeLocator(offset).searchWithin(unit.unit);
+        final element = server.getElementOfNode(node);
+        // Getter to Method
+        if (element is PropertyAccessorElement) {
+          refactorActions.add(createRefactor(
+              CodeActionKind.RefactorRewrite,
+              'Convert Getter to Method',
+              RefactoringKind.CONVERT_GETTER_TO_METHOD));
+        }
+
+        // Method to Getter
+        if (element is ExecutableElement &&
+            element is! PropertyAccessorElement) {
+          refactorActions.add(createRefactor(
+              CodeActionKind.RefactorRewrite,
+              'Convert Method to Getter',
+              RefactoringKind.CONVERT_METHOD_TO_GETTER));
+        }
+      }
+
       return refactorActions;
     } on InconsistentAnalysisException {
       // If an InconsistentAnalysisException occurs, it's likely the user modified
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart
index 1ccaff4..8a6b2c8 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_into_async_body.dart
@@ -17,8 +17,9 @@
     var body = getEnclosingFunctionBody();
     if (body == null ||
         body is EmptyFunctionBody ||
-        body.isAsynchronous ||
-        body.isGenerator) {
+        // Do not offer a correction if there is an `async`, `async*`, `sync*`,
+        // or the fictional `sync` keyword.
+        body.keyword != null) {
       return;
     }
 
diff --git a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
index 5ebc918..e8921f7 100644
--- a/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_refactor_test.dart
@@ -20,10 +20,76 @@
     defineReflectiveTests(ExtractVariableRefactorCodeActionsTest);
     defineReflectiveTests(InlineLocalVariableRefactorCodeActionsTest);
     defineReflectiveTests(InlineMethodRefactorCodeActionsTest);
+    defineReflectiveTests(ConvertGetterToMethodCodeActionsTest);
+    defineReflectiveTests(ConvertMethodToGetterCodeActionsTest);
   });
 }
 
 @reflectiveTest
+class ConvertGetterToMethodCodeActionsTest extends AbstractCodeActionsTest {
+  final refactorTitle = 'Convert Getter to Method';
+
+  Future<void> test_refactor() async {
+    const content = '''
+int get ^test => 42;
+main() {
+  var a = test;
+  var b = test;
+}
+''';
+    const expectedContent = '''
+int test() => 42;
+main() {
+  var a = test();
+  var b = test();
+}
+''';
+    newFile(mainFilePath, content: withoutMarkers(content));
+    await initialize();
+
+    final codeActions = await getCodeActions(mainFileUri.toString(),
+        position: positionFromMarker(content));
+    final codeAction =
+        findCommand(codeActions, Commands.performRefactor, refactorTitle)!;
+
+    await verifyCodeActionEdits(
+        codeAction, withoutMarkers(content), expectedContent);
+  }
+}
+
+@reflectiveTest
+class ConvertMethodToGetterCodeActionsTest extends AbstractCodeActionsTest {
+  final refactorTitle = 'Convert Method to Getter';
+
+  Future<void> test_refactor() async {
+    const content = '''
+int ^test() => 42;
+main() {
+  var a = test();
+  var b = test();
+}
+''';
+    const expectedContent = '''
+int get test => 42;
+main() {
+  var a = test;
+  var b = test;
+}
+''';
+    newFile(mainFilePath, content: withoutMarkers(content));
+    await initialize();
+
+    final codeActions = await getCodeActions(mainFileUri.toString(),
+        position: positionFromMarker(content));
+    final codeAction =
+        findCommand(codeActions, Commands.performRefactor, refactorTitle)!;
+
+    await verifyCodeActionEdits(
+        codeAction, withoutMarkers(content), expectedContent);
+  }
+}
+
+@reflectiveTest
 class ExtractMethodRefactorCodeActionsTest extends AbstractCodeActionsTest {
   final extractMethodTitle = 'Extract Method';
 
@@ -176,7 +242,12 @@
 }
     ''';
     newFile(mainFilePath, content: withoutMarkers(content));
-    await initialize();
+    await initialize(
+      textDocumentCapabilities: withCodeActionKinds(
+        emptyTextDocumentClientCapabilities,
+        [CodeActionKind.Empty], // Support everything (empty prefix matches all)
+      ),
+    );
 
     final ofKind = (CodeActionKind kind) => getCodeActions(
           mainFileUri.toString(),
@@ -184,13 +255,31 @@
           kinds: [kind],
         );
 
-    // The code above will return a RefactorExtract that should be included
-    // by both Refactor and RefactorExtract, but not RefactorExtractFoo or
-    // RefactorRewrite
-    expect(await ofKind(CodeActionKind.Refactor), isNotEmpty);
-    expect(await ofKind(CodeActionKind.RefactorExtract), isNotEmpty);
-    expect(await ofKind(CodeActionKind('refactor.extract.foo')), isEmpty);
-    expect(await ofKind(CodeActionKind.RefactorRewrite), isEmpty);
+    // Helper that requests CodeActions for [kind] and ensures all results
+    // returned have either an equal kind, or a kind that is prefixed with the
+    // requested kind followed by a dot.
+    Future<void> checkResults(CodeActionKind kind) async {
+      final results = await ofKind(kind);
+      for (final result in results) {
+        final resultKind = result.map(
+          (cmd) => throw 'Expected CodeAction, got Command: ${cmd.title}',
+          (action) => action.kind,
+        );
+        expect(
+          '$resultKind',
+          anyOf([
+            equals('$kind'),
+            startsWith('$kind.'),
+          ]),
+        );
+      }
+    }
+
+    // Check a few of each that will produces multiple matches and no matches.
+    await checkResults(CodeActionKind.Refactor);
+    await checkResults(CodeActionKind.RefactorExtract);
+    await checkResults(CodeActionKind('refactor.extract.foo'));
+    await checkResults(CodeActionKind.RefactorRewrite);
   }
 
   Future<void> test_generatesNames() async {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_into_async_body_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_into_async_body_test.dart
index 0120636..fc933c1 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_into_async_body_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_into_async_body_test.dart
@@ -136,6 +136,17 @@
 ''');
   }
 
+  Future<void> test_sync() async {
+    // This code is erroneous; the test ensures there is no error thrown when
+    // computing assists.
+    verifyNoTestUnitErrors = false;
+    await resolveTestCode('''
+Iterable<String> f() sync {}
+''');
+    await assertNoAssistAt('{}');
+  }
+
+
   Future<void> test_syncStar() async {
     await resolveTestCode('''
 Iterable<String> f() sync* {}
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index ab82e26..6c1563b 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -1061,7 +1061,7 @@
 /// [PostfixExpression] when the operator is an increment operator.
 ///
 /// Clients may not extend, implement or mix-in this class.
-abstract class CompoundAssignmentExpression {
+abstract class CompoundAssignmentExpression implements Expression {
   /// The element that is used to read the value.
   ///
   /// If this node is not a compound assignment, this element is `null`.
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 874c8f5..9256fa8 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -5892,8 +5892,7 @@
 
     final parent = this.parent;
     if (parent is CompoundAssignmentExpression) {
-      var assignment = parent as CompoundAssignmentExpression;
-      element = assignment.writeElement ?? assignment.readElement;
+      element = parent.writeElement ?? parent.readElement;
     }
 
     if (element is ExecutableElement) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
index 5dd33ec..80022ea 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 
@@ -25,13 +26,17 @@
   /// The resolver driving this participant.
   final ResolverVisitor _resolver;
 
+  /// Helper for extension method resolution.
+  final ExtensionMemberResolver _extensionResolver;
+
   final bool _isNonNullableByDefault;
 
   /// The type representing the type 'type'.
   final InterfaceType _typeType;
 
   FunctionReferenceResolver(this._resolver, this._isNonNullableByDefault)
-      : _typeType = _resolver.typeProvider.typeType;
+      : _extensionResolver = _resolver.extensionResolver,
+        _typeType = _resolver.typeProvider.typeType;
 
   ErrorReporter get _errorReporter => _resolver.errorReporter;
 
@@ -43,242 +48,16 @@
     node.typeArguments?.accept(_resolver);
 
     if (function is SimpleIdentifierImpl) {
-      var element = _resolver.nameScope.lookup(function.name).getter;
-
-      if (element == null) {
-        DartType receiverType;
-        var enclosingClass = _resolver.enclosingClass;
-        if (enclosingClass != null) {
-          receiverType = enclosingClass.thisType;
-        } else {
-          // TODO(srawlins): Check `_resolver.enclosingExtension`.
-          _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
-            function,
-            [function.name],
-          );
-          node.staticType = DynamicTypeImpl.instance;
-          return;
-        }
-
-        var result = _resolver.typePropertyResolver.resolve(
-          receiver: null,
-          receiverType: receiverType,
-          name: function.name,
-          propertyErrorEntity: function,
-          nameErrorEntity: function,
-        );
-
-        var method = result.getter;
-        if (method != null) {
-          function.staticElement = method;
-          _resolve(node: node, rawType: method.type, name: function.name);
-          return;
-        } else {
-          // TODO(srawlins): Report CompileTimeErrorCode.UNDEFINED_METHOD.
-          return;
-        }
-
-        // TODO(srawlins): If `target.isStatic`, report an error, something like
-        // [MethodInvocationResolver._reportInstanceAccessToStaticMember].
-
-        // TODO(srawlins): if `(target is PropertyAccessorElement)`, report an
-        // error.
-      }
-
-      // Classes and type aliases are checked first so as to include a
-      // PropertyAccess parent check, which does not need to be done for
-      // functions.
-      if (element is ClassElement || element is TypeAliasElement) {
-        // A type-instantiated constructor tearoff like `C<int>.name` or
-        // `prefix.C<int>.name` is initially represented as a [PropertyAccess]
-        // with a [FunctionReference] target.
-        if (node.parent is PropertyAccess) {
-          _resolveConstructorReference(node);
-          return;
-        } else if (element is ClassElement) {
-          function.staticElement = element;
-          _resolveDirectTypeLiteral(node, function, element);
-          return;
-        } else if (element is TypeAliasElement) {
-          function.staticElement = element;
-          _resolveTypeAlias(node: node, element: element, typeAlias: function);
-          return;
-        }
-      } else if (element is ExecutableElement) {
-        function.staticElement = element;
-        function.staticType = element.type;
-        _resolve(node: node, rawType: element.type, name: element.name);
-        return;
-      } else if (element is VariableElement) {
-        function.staticElement = element;
-        function.staticType = element.type;
-        _resolveDisallowedExpression(node, element.type);
-        return;
-      }
-
-      node.staticType = DynamicTypeImpl.instance;
-      return;
+      _resolveSimpleIdentifierFunction(node, function);
     } else if (function is PrefixedIdentifierImpl) {
-      var prefixElement =
-          _resolver.nameScope.lookup(function.prefix.name).getter;
-
-      if (prefixElement == null) {
-        _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
-          function.prefix,
-          [function.name],
-        );
-        node.staticType = DynamicTypeImpl.instance;
-        return;
-      }
-
-      function.prefix.staticElement = prefixElement;
-      if (prefixElement is PrefixElement) {
-        var functionName = function.identifier.name;
-        var functionElement = prefixElement.scope.lookup(functionName).getter;
-        if (functionElement == null) {
-          _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
-            function.identifier,
-            [function.identifier.name, function.prefix.name],
-          );
-          function.staticType = DynamicTypeImpl.instance;
-          node.staticType = DynamicTypeImpl.instance;
-          return;
-        } else {
-          functionElement = _resolver.toLegacyElement(functionElement);
-          _resolveReceiverPrefix(
-              node, prefixElement, function, functionElement);
-          return;
-        }
-      }
-
-      DartType? prefixType;
-      if (prefixElement is VariableElement) {
-        prefixType = prefixElement.type;
-      } else if (prefixElement is PropertyAccessorElement) {
-        prefixType = prefixElement.returnType;
-      }
-
-      function.prefix.staticType = prefixType;
-      if (prefixType != null && prefixType.isDynamic) {
-        // TODO(srawlins): Report error. See spec text: "We do not allow dynamic
-        // explicit instantiation."
-        node.staticType = DynamicTypeImpl.instance;
-        return;
-      }
-
-      var methodElement = _resolveTypeProperty(
-        receiver: function.prefix,
-        receiverElement: prefixElement,
-        name: function.identifier,
-        nameErrorEntity: function,
-      );
-
-      if (methodElement is MethodElement) {
-        function.identifier.staticElement = methodElement;
-        function.staticType = methodElement.type;
-        _resolve(
-          node: node,
-          rawType: methodElement.type,
-          name: function.identifier.name,
-        );
-        return;
-      }
-
-      // TODO(srawlins): Need to report cases where [methodElement] is not
-      // generic. The 'test_instanceGetter_explicitReceiver' test case needs to
-      // be updated to handle this.
-
-      function.accept(_resolver);
-      node.staticType = DynamicTypeImpl.instance;
-      return;
+      _resolvePrefixedIdentifierFunction(node, function);
     } else if (function is PropertyAccessImpl) {
-      function.accept(_resolver);
-      var target = function.target;
-      if (target == null) {
-        // TODO(srawlins): Can we get here? Perhaps as part of a cascade, but
-        // there is currently a parsing error with cascades.
-        // https://github.com/dart-lang/sdk/issues/46635
-        node.staticType = DynamicTypeImpl.instance;
-        return;
-      }
-
-      DartType targetType;
-      if (target is SuperExpressionImpl) {
-        targetType = target.typeOrThrow;
-      } else if (target is ThisExpressionImpl) {
-        targetType = target.typeOrThrow;
-      } else if (target is SimpleIdentifierImpl) {
-        var targetElement = _resolver.nameScope.lookup(target.name).getter;
-        if (targetElement is VariableElement) {
-          targetType = targetElement.type;
-        } else if (targetElement is PropertyAccessorElement) {
-          targetType = targetElement.returnType;
-        } else {
-          // TODO(srawlins): Can we get here?
-          node.staticType = DynamicTypeImpl.instance;
-          return;
-        }
-      } else if (target is PrefixedIdentifierImpl) {
-        var prefixElement =
-            _resolver.nameScope.lookup(target.prefix.name).getter;
-        if (prefixElement is PrefixElement) {
-          var prefixName = target.identifier.name;
-          var targetElement = prefixElement.scope.lookup(prefixName).getter;
-
-          var methodElement = _resolveTypeProperty(
-            receiver: target,
-            receiverElement: targetElement,
-            name: function.propertyName,
-            nameErrorEntity: function,
-          );
-
-          if (methodElement == null) {
-            // TODO(srawlins): Can we get here?
-            node.staticType = DynamicTypeImpl.instance;
-            return;
-          } else {
-            _resolveReceiverPrefix(node, prefixElement, target, methodElement);
-            return;
-          }
-        } else {
-          // TODO(srawlins): Can we get here?
-          node.staticType = DynamicTypeImpl.instance;
-          return;
-        }
-      } else {
-        targetType = target.typeOrThrow;
-      }
-
-      var propertyElement = _resolver.typePropertyResolver
-          .resolve(
-            receiver: function.realTarget,
-            receiverType: targetType,
-            name: function.propertyName.name,
-            propertyErrorEntity: function.propertyName,
-            nameErrorEntity: function,
-          )
-          .getter;
-
-      if (propertyElement is TypeParameterElement) {
-        _resolveDisallowedExpression(node, propertyElement!.type);
-        return;
-      }
-
-      _resolve(
-        node: node,
-        rawType: function.staticType,
-        name: propertyElement?.name,
-      );
-      return;
+      _resolvePropertyAccessFunction(node, function);
     } else {
       // TODO(srawlins): Handle `function` being a [SuperExpression].
 
       function.accept(_resolver);
       _resolveDisallowedExpression(node, node.function.staticType);
-      return;
     }
   }
 
@@ -315,6 +94,37 @@
     }
   }
 
+  void _reportInvalidAccessToStaticMember(
+    SimpleIdentifier nameNode,
+    ExecutableElement element, {
+    required bool implicitReceiver,
+  }) {
+    if (_resolver.enclosingExtension != null) {
+      _resolver.errorReporter.reportErrorForNode(
+        CompileTimeErrorCode
+            .UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
+        nameNode,
+        [element.enclosingElement.displayName],
+      );
+    } else if (implicitReceiver) {
+      _resolver.errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
+        nameNode,
+        [element.enclosingElement.displayName],
+      );
+    } else {
+      _resolver.errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
+        nameNode,
+        [
+          nameNode.name,
+          element.kind.displayName,
+          element.enclosingElement.displayName,
+        ],
+      );
+    }
+  }
+
   /// Resolves [node]'s static type, as an instantiated function type, and type
   /// argument types, using [rawType] as the uninstantiated function type.
   void _resolve({
@@ -384,6 +194,194 @@
     _resolve(node: node, rawType: rawType);
   }
 
+  void _resolveExtensionOverride(
+    FunctionReferenceImpl node,
+    PropertyAccessImpl function,
+    ExtensionOverride override,
+  ) {
+    var propertyName = function.propertyName;
+    var result =
+        _extensionResolver.getOverrideMember(override, propertyName.name);
+    var member = _resolver.toLegacyElement(result.getter);
+
+    if (member == null) {
+      node.staticType = DynamicTypeImpl.instance;
+      return;
+    }
+
+    if (member.isStatic) {
+      _resolver.errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
+        function.propertyName,
+      );
+      // Continue to resolve type.
+    }
+
+    if (function.isCascaded) {
+      _resolver.errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.EXTENSION_OVERRIDE_WITH_CASCADE,
+        override.extensionName,
+      );
+      // Continue to resolve type.
+    }
+
+    // TODO(srawlins): If PropertyAccessorElement, report error.
+
+    _resolve(node: node, rawType: member.type, name: propertyName.name);
+  }
+
+  void _resolvePrefixedIdentifierFunction(
+      FunctionReferenceImpl node, PrefixedIdentifierImpl function) {
+    var prefixElement = _resolver.nameScope.lookup(function.prefix.name).getter;
+
+    if (prefixElement == null) {
+      _errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
+        function.prefix,
+        [function.name],
+      );
+      function.staticType = DynamicTypeImpl.instance;
+      node.staticType = DynamicTypeImpl.instance;
+      return;
+    }
+
+    function.prefix.staticElement = prefixElement;
+    if (prefixElement is PrefixElement) {
+      var functionName = function.identifier.name;
+      var functionElement = prefixElement.scope.lookup(functionName).getter;
+      if (functionElement == null) {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
+          function.identifier,
+          [function.identifier.name, function.prefix.name],
+        );
+        function.staticType = DynamicTypeImpl.instance;
+        node.staticType = DynamicTypeImpl.instance;
+        return;
+      } else {
+        functionElement = _resolver.toLegacyElement(functionElement);
+        _resolveReceiverPrefix(node, prefixElement, function, functionElement);
+        return;
+      }
+    }
+
+    DartType? prefixType;
+    if (prefixElement is VariableElement) {
+      prefixType = prefixElement.type;
+    } else if (prefixElement is PropertyAccessorElement) {
+      prefixType = prefixElement.returnType;
+    }
+
+    function.prefix.staticType = prefixType;
+    if (prefixType != null && prefixType.isDynamic) {
+      // TODO(srawlins): Report error. See spec text: "We do not allow dynamic
+      // explicit instantiation."
+      node.staticType = DynamicTypeImpl.instance;
+      return;
+    }
+
+    var methodElement = _resolveTypeProperty(
+      receiver: function.prefix,
+      receiverElement: prefixElement,
+      name: function.identifier,
+      nameErrorEntity: function,
+    );
+
+    if (methodElement is MethodElement) {
+      function.identifier.staticElement = methodElement;
+      function.staticType = methodElement.type;
+      _resolve(
+        node: node,
+        rawType: methodElement.type,
+        name: function.identifier.name,
+      );
+      return;
+    }
+
+    // TODO(srawlins): Need to report cases where [methodElement] is not
+    // generic. The 'test_instanceGetter_explicitReceiver' test case needs to
+    // be updated to handle this.
+
+    function.accept(_resolver);
+    node.staticType = DynamicTypeImpl.instance;
+  }
+
+  void _resolvePropertyAccessFunction(
+      FunctionReferenceImpl node, PropertyAccessImpl function) {
+    function.accept(_resolver);
+    var target = function.realTarget;
+
+    DartType targetType;
+    if (target is SuperExpressionImpl) {
+      targetType = target.typeOrThrow;
+    } else if (target is ThisExpressionImpl) {
+      targetType = target.typeOrThrow;
+    } else if (target is SimpleIdentifierImpl) {
+      var targetElement = _resolver.nameScope.lookup(target.name).getter;
+      if (targetElement is VariableElement) {
+        targetType = targetElement.type;
+      } else if (targetElement is PropertyAccessorElement) {
+        targetType = targetElement.returnType;
+      } else {
+        // TODO(srawlins): Can we get here?
+        node.staticType = DynamicTypeImpl.instance;
+        return;
+      }
+    } else if (target is PrefixedIdentifierImpl) {
+      var prefixElement = _resolver.nameScope.lookup(target.prefix.name).getter;
+      if (prefixElement is PrefixElement) {
+        var prefixName = target.identifier.name;
+        var targetElement = prefixElement.scope.lookup(prefixName).getter;
+
+        var methodElement = _resolveTypeProperty(
+          receiver: target,
+          receiverElement: targetElement,
+          name: function.propertyName,
+          nameErrorEntity: function,
+        );
+
+        if (methodElement == null) {
+          // TODO(srawlins): Can we get here?
+          node.staticType = DynamicTypeImpl.instance;
+          return;
+        } else {
+          _resolveReceiverPrefix(node, prefixElement, target, methodElement);
+          return;
+        }
+      } else {
+        // TODO(srawlins): Can we get here?
+        node.staticType = DynamicTypeImpl.instance;
+        return;
+      }
+    } else if (target is ExtensionOverrideImpl) {
+      _resolveExtensionOverride(node, function, target);
+      return;
+    } else {
+      targetType = target.typeOrThrow;
+    }
+
+    var propertyElement = _resolver.typePropertyResolver
+        .resolve(
+          receiver: function.realTarget,
+          receiverType: targetType,
+          name: function.propertyName.name,
+          propertyErrorEntity: function.propertyName,
+          nameErrorEntity: function,
+        )
+        .getter;
+
+    if (propertyElement is TypeParameterElement) {
+      _resolveDisallowedExpression(node, propertyElement!.type);
+      return;
+    }
+
+    _resolve(
+      node: node,
+      rawType: function.staticType,
+      name: propertyElement?.name,
+    );
+  }
+
   void _resolveReceiverPrefix(
     FunctionReferenceImpl node,
     PrefixElement prefixElement,
@@ -433,6 +431,94 @@
     node.staticType = DynamicTypeImpl.instance;
   }
 
+  void _resolveSimpleIdentifierFunction(
+      FunctionReferenceImpl node, SimpleIdentifierImpl function) {
+    var element = _resolver.nameScope.lookup(function.name).getter;
+
+    if (element == null) {
+      DartType receiverType;
+      var enclosingClass = _resolver.enclosingClass;
+      if (enclosingClass != null) {
+        receiverType = enclosingClass.thisType;
+      } else {
+        var enclosingExtension = _resolver.enclosingExtension;
+        if (enclosingExtension != null) {
+          receiverType = enclosingExtension.extendedType;
+        } else {
+          _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
+            function,
+            [function.name],
+          );
+          function.staticType = DynamicTypeImpl.instance;
+          node.staticType = DynamicTypeImpl.instance;
+          return;
+        }
+      }
+
+      var result = _resolver.typePropertyResolver.resolve(
+        receiver: null,
+        receiverType: receiverType,
+        name: function.name,
+        propertyErrorEntity: function,
+        nameErrorEntity: function,
+      );
+
+      var method = result.getter;
+      if (method != null) {
+        if (method.isStatic) {
+          _reportInvalidAccessToStaticMember(function, method,
+              implicitReceiver: true);
+          // Continue to assign types.
+        }
+
+        function.staticElement = method;
+        function.staticType = method.type;
+        _resolve(node: node, rawType: method.type, name: function.name);
+        return;
+      } else {
+        // TODO(srawlins): Report CompileTimeErrorCode.UNDEFINED_METHOD.
+        return;
+      }
+
+      // TODO(srawlins): if `(target is PropertyAccessorElement)`, report an
+      // error.
+    }
+
+    // Classes and type aliases are checked first so as to include a
+    // PropertyAccess parent check, which does not need to be done for
+    // functions.
+    if (element is ClassElement || element is TypeAliasElement) {
+      // A type-instantiated constructor tearoff like `C<int>.name` or
+      // `prefix.C<int>.name` is initially represented as a [PropertyAccess]
+      // with a [FunctionReference] target.
+      if (node.parent is PropertyAccess) {
+        _resolveConstructorReference(node);
+        return;
+      } else if (element is ClassElement) {
+        function.staticElement = element;
+        _resolveDirectTypeLiteral(node, function, element);
+        return;
+      } else if (element is TypeAliasElement) {
+        function.staticElement = element;
+        _resolveTypeAlias(node: node, element: element, typeAlias: function);
+        return;
+      }
+    } else if (element is ExecutableElement) {
+      function.staticElement = element;
+      function.staticType = element.type;
+      _resolve(node: node, rawType: element.type, name: element.name);
+      return;
+    } else if (element is VariableElement) {
+      function.staticElement = element;
+      function.staticType = element.type;
+      _resolveDisallowedExpression(node, element.type);
+      return;
+    } else {
+      node.staticType = DynamicTypeImpl.instance;
+    }
+  }
+
   /// Returns the element that represents the property named [propertyName] on
   /// [classElement].
   ExecutableElement? _resolveStaticElement(
@@ -517,7 +603,7 @@
           'Unexpected receiverElement type: ${receiverElement.runtimeType}');
       return null;
     }
-    return _resolver.typePropertyResolver
+    var methodElement = _resolver.typePropertyResolver
         .resolve(
           receiver: receiver,
           receiverType: receiverType,
@@ -526,5 +612,10 @@
           nameErrorEntity: nameErrorEntity,
         )
         .getter;
+    if (methodElement != null && methodElement.isStatic) {
+      _reportInvalidAccessToStaticMember(name, methodElement,
+          implicitReceiver: false);
+    }
+    return methodElement;
   }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
index b53a4a1..21ffd13 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
@@ -41,6 +41,140 @@
     assertType(reference, 'dynamic');
   }
 
+  test_extensionMethod() async {
+    await assertNoErrorsInCode('''
+class A {}
+
+extension E on A {
+  void foo<T>(T a) {}
+
+  bar() {
+    foo<int>;
+  }
+}
+''');
+
+    var reference = findNode.functionReference('foo<int>;');
+    assertFunctionReference(
+        reference, findElement.method('foo'), 'void Function(int)');
+  }
+
+  test_extensionMethod_explicitReceiver_this() async {
+    await assertNoErrorsInCode('''
+class A {}
+
+extension E on A {
+  void foo<T>(T a) {}
+
+  bar() {
+    this.foo<int>;
+  }
+}
+''');
+
+    var reference = findNode.functionReference('foo<int>;');
+    assertFunctionReference(
+        reference, findElement.method('foo'), 'void Function(int)');
+  }
+
+  test_extensionMethod_extensionOverride() async {
+    await assertNoErrorsInCode('''
+class A {
+  int foo = 0;
+}
+
+extension E on A {
+  void foo<T>(T a) {}
+}
+
+bar(A a) {
+  E(a).foo<int>;
+}
+''');
+
+    var reference = findNode.functionReference('foo<int>;');
+    assertFunctionReference(
+        reference, findElement.method('foo'), 'void Function(int)');
+  }
+
+  test_extensionMethod_extensionOverride_cascade() async {
+    await assertErrorsInCode('''
+class A {
+  int foo = 0;
+}
+
+extension E on A {
+  void foo<T>(T a) {}
+}
+
+bar(A a) {
+  E(a)..foo<int>;
+}
+''', [
+      error(CompileTimeErrorCode.EXTENSION_OVERRIDE_WITH_CASCADE, 85, 1),
+    ]);
+
+    var reference = findNode.functionReference('foo<int>;');
+    assertFunctionReference(
+        reference, findElement.method('foo'), 'void Function(int)');
+  }
+
+  test_extensionMethod_extensionOverride_static() async {
+    await assertErrorsInCode('''
+class A {}
+
+extension E on A {
+  static void foo<T>(T a) {}
+}
+
+bar(A a) {
+  E(a).foo<int>;
+}
+''', [
+      error(CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER, 81,
+          3),
+    ]);
+
+    var reference = findNode.functionReference('foo<int>;');
+    assertFunctionReference(
+        reference, findElement.method('foo'), 'void Function(int)');
+  }
+
+  test_extensionMethod_extensionOverride_unknown() async {
+    await assertErrorsInCode('''
+class A {}
+
+extension E on A {}
+
+bar(A a) {
+  E(a).foo<int>;
+}
+''', [
+      error(CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER, 51, 3),
+    ]);
+
+    var reference = findNode.functionReference('foo<int>;');
+    assertType(reference, 'dynamic');
+  }
+
+  test_extensionMethod_fromClassDeclaration() async {
+    await assertNoErrorsInCode('''
+class A {
+  bar() {
+    foo<int>;
+  }
+}
+
+extension E on A {
+  void foo<T>(T a) {}
+}
+''');
+
+    var reference = findNode.functionReference('foo<int>;');
+    assertFunctionReference(
+        reference, findElement.method('foo'), 'void Function(int)');
+  }
+
   test_instanceGetter_explicitReceiver() async {
     // This test is here to assert that the resolver does not throw, but in the
     // future, an error should be reported here as well.
@@ -212,6 +346,27 @@
         'void Function(int)');
   }
 
+  test_instanceMethod_explicitReceiver_topLevelVariable_prefix_unknown() async {
+    newFile('$testPackageLibPath/a.dart', content: '''
+class A {}
+var a = A();
+''');
+    await assertErrorsInCode('''
+import 'a.dart' as prefix;
+
+bar() {
+  prefix.a.foo<int>;
+}
+''', [
+      error(CompileTimeErrorCode.UNDEFINED_GETTER, 47, 3),
+    ]);
+
+    assertImportPrefix(
+        findNode.simple('prefix.'), findElement.prefix('prefix'));
+    var reference = findNode.functionReference('foo<int>;');
+    assertType(reference, 'dynamic');
+  }
+
   test_instanceMethod_explicitReceiver_typeParameter() async {
     await assertErrorsInCode('''
 bar<T>() {
@@ -241,7 +396,6 @@
         reference, findElement.method('foo'), 'void Function(int)');
   }
 
-  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/46635')
   test_instanceMethod_explicitReceiver_variable_cascade() async {
     await assertNoErrorsInCode('''
 class A {
@@ -568,6 +722,24 @@
     );
   }
 
+  test_topLevelVariable_prefix_unknown() async {
+    newFile('$testPackageLibPath/a.dart', content: '');
+    await assertErrorsInCode('''
+import 'a.dart' as prefix;
+
+bar() {
+  prefix.a.foo<int>;
+}
+''', [
+      error(CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME, 45, 1),
+    ]);
+
+    assertImportPrefix(
+        findNode.simple('prefix.'), findElement.prefix('prefix'));
+    var reference = findNode.functionReference('foo<int>;');
+    assertType(reference, 'dynamic');
+  }
+
   test_typeAlias_function_unknownProperty() async {
     await assertErrorsInCode('''
 typedef Cb = void Function();
diff --git a/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart b/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
index aeaec55..ee423c8 100644
--- a/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
@@ -102,6 +102,19 @@
     ]);
   }
 
+  test_method_reference_typeInstantiation() async {
+    await assertErrorsInCode(r'''
+class A {
+  static m<T>() {}
+}
+f(A a) {
+  a.m<int>;
+}
+''', [
+      error(CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, 44, 1),
+    ]);
+  }
+
   test_propertyAccess_field() async {
     await assertErrorsInCode(r'''
 class A {
diff --git a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
index 9627043..79ab24a 100644
--- a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart
@@ -692,4 +692,32 @@
 A get foo => throw 0;
 ''');
   }
+
+  test_typeLiteral_class() async {
+    await assertErrorsInCode('''
+class C<T extends int> {}
+var t = C<String>;
+''', [
+      error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 36, 6),
+    ]);
+  }
+
+  test_typeLiteral_functionTypeAlias() async {
+    await assertErrorsInCode('''
+typedef Cb<T extends int> = void Function();
+var t = Cb<String>;
+''', [
+      error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 56, 6),
+    ]);
+  }
+
+  test_typeLiteral_typeAlias() async {
+    await assertErrorsInCode('''
+class C {}
+typedef D<T extends int> = C;
+var t = D<String>;
+''', [
+      error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 51, 6),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_non_local_static_member_test.dart b/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_non_local_static_member_test.dart
index 6551ffe..8e24064 100644
--- a/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_non_local_static_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_non_local_static_member_test.dart
@@ -50,6 +50,21 @@
     ]);
   }
 
+  test_methodTearoff() async {
+    await assertErrorsInCode('''
+class A {
+  static void a<T>() {}
+}
+class B extends A {
+  void b() {
+    a<int>;
+  }
+}
+''', [
+      error(_errorCode, 73, 1),
+    ]);
+  }
+
   test_readWrite() async {
     await assertErrorsInCode(r'''
 class A {
diff --git a/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_static_member_of_extended_type_test.dart b/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_static_member_of_extended_type_test.dart
index 8525aa2..1cf7168 100644
--- a/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_static_member_of_extended_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unqualified_reference_to_static_member_of_extended_type_test.dart
@@ -51,6 +51,21 @@
     ]);
   }
 
+  test_methodTearoff() async {
+    await assertErrorsInCode('''
+class MyClass {
+  static void sm<T>() {}
+}
+extension MyExtension on MyClass {
+  void m() {
+    sm<int>;
+  }
+}
+''', [
+      error(_errorCode, 95, 2),
+    ]);
+  }
+
   test_readWrite() async {
     await assertErrorsInCode('''
 class MyClass {
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index a3b5448..28e3590 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -382,7 +382,7 @@
   Iterable<io.File> _collectFiles(String filePath, AnalysisOptions options) {
     var files = <io.File>[];
     var file = io.File(filePath);
-    if (file.existsSync() && !pathFilter.ignored(filePath)) {
+    if (file.existsSync()) {
       files.add(file);
     } else {
       var directory = io.Directory(filePath);
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index 419aceb..19d778d 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -73,7 +73,9 @@
         path.join(testDirectory, options),
       ];
     }
-    cmd..addAll(sources.map(_adjustFileSpec))..addAll(args);
+    cmd
+      ..addAll(sources.map(_adjustFileSpec))
+      ..addAll(args);
 
     await driver.start(cmd);
   }
@@ -390,6 +392,20 @@
   ErrorProcessor processorFor(AnalysisError error) =>
       processors.firstWhere((p) => p.appliesTo(error));
 
+  /// If a file is specified explicitly, it should be analyzed, even if
+  /// it is excluded. Excludes work when an including directory is specified.
+  Future<void> test_analysisOptions_excluded_requested() async {
+    await drive(
+      'data/exclude_test_project/lib/excluded_error.dart',
+      options: 'data/exclude_test_project/$analysisOptionsYaml',
+    );
+    expect(
+      bulletToDash(outSink),
+      contains("error - Undefined class 'ExcludedUndefinedClass'"),
+    );
+    expect(outSink.toString(), contains('1 error found.'));
+  }
+
   Future<void> test_analysisOptions_excludes() async {
     await drive('data/exclude_test_project',
         options: 'data/exclude_test_project/$analysisOptionsYaml');
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index 5c4515c..acf8fb5 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -42,6 +42,8 @@
 
 import '../fasta_codes.dart';
 
+import '../kernel/kernel_target.dart';
+
 import '../loader.dart';
 
 import '../modifier.dart';
@@ -121,7 +123,8 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder library,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers);
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes);
 
   /// Registers a constructor redirection for this class and returns true if
   /// this redirection gives rise to a cycle that has not been reported before.
@@ -341,11 +344,13 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder library,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers) {
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes) {
     void build(String ignore, Builder declaration) {
       MemberBuilder member = declaration as MemberBuilder;
       member.buildOutlineExpressions(
-          library, coreTypes, delayedActionPerformers);
+          library, coreTypes, delayedActionPerformers,
+          clonedFunctionNodes);
     }
 
     MetadataBuilder.buildAnnotations(
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
index 505f29b..b0a984c 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
@@ -251,8 +251,10 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder library,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers) {
-    super.buildOutlineExpressions(library, coreTypes, delayedActionPerformers);
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes) {
+    super.buildOutlineExpressions(
+        library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
 
     // For modular compilation purposes we need to include initializers
     // for const constructors into the outline.
@@ -482,15 +484,16 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder libraryBuilder,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers) {
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes) {
     if (_origin != null) {
       // Ensure that default value expressions have been created for [_origin].
       LibraryBuilder originLibraryBuilder = _origin!.library;
       if (originLibraryBuilder is SourceLibraryBuilder) {
         // If [_origin] is from a source library, we need to build the default
         // values and initializers first.
-        _origin!.buildOutlineExpressions(
-            originLibraryBuilder, coreTypes, delayedActionPerformers);
+        _origin!.buildOutlineExpressions(originLibraryBuilder, coreTypes,
+            delayedActionPerformers, clonedFunctionNodes);
       }
       _clonedFunctionNode!.cloneDefaultValues();
       _clonedFunctionNode = null;
diff --git a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
index 8947531..6c173ef 100644
--- a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
@@ -42,6 +42,8 @@
         templateDuplicatedDeclarationSyntheticCause,
         templateEnumConstantSameNameAsEnclosing;
 
+import '../kernel/kernel_target.dart';
+
 import '../util/helpers.dart';
 
 import '../modifier.dart'
@@ -520,7 +522,8 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder libraryBuilder,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers) {
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes) {
     List<Expression> values = <Expression>[];
     if (enumConstantInfos != null) {
       for (EnumConstantInfo? enumConstantInfo in enumConstantInfos!) {
@@ -564,7 +567,8 @@
         }
       }
     }
-    super.buildOutlineExpressions(library, coreTypes, delayedActionPerformers);
+    super.buildOutlineExpressions(
+        library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
index 0ca4e45..d52ae6f 100644
--- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
@@ -7,6 +7,7 @@
 
 import '../fasta_codes.dart'
     show templateInternalProblemNotFoundIn, templateTypeArgumentMismatch;
+import '../kernel/kernel_target.dart';
 import '../scope.dart';
 import '../source/source_library_builder.dart';
 import '../problems.dart';
@@ -36,7 +37,8 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder library,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers);
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes);
 
   /// Looks up extension member by [name] taking privacy into account.
   ///
diff --git a/pkg/front_end/lib/src/fasta/builder/factory_builder.dart b/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
index e79afa3..4ca72bb 100644
--- a/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:kernel/ast.dart';
+import 'package:kernel/type_algebra.dart';
 
 import '../dill/dill_member_builder.dart';
 
@@ -11,6 +12,7 @@
 import '../kernel/forest.dart';
 import '../kernel/internal_ast.dart';
 import '../kernel/kernel_api.dart';
+import '../kernel/kernel_target.dart';
 import '../kernel/redirecting_factory_body.dart'
     show getRedirectingFactoryBody, RedirectingFactoryBody;
 
@@ -34,7 +36,6 @@
 import 'function_builder.dart';
 import 'member_builder.dart';
 import 'metadata_builder.dart';
-import 'library_builder.dart';
 import 'procedure_builder.dart';
 import 'type_builder.dart';
 import 'type_variable_builder.dart';
@@ -161,6 +162,21 @@
   }
 
   @override
+  VariableDeclaration? getTearOffParameter(int index) {
+    if (_factoryTearOff != null) {
+      if (index < _factoryTearOff!.function.positionalParameters.length) {
+        return _factoryTearOff!.function.positionalParameters[index];
+      } else {
+        index -= _factoryTearOff!.function.positionalParameters.length;
+        if (index < _factoryTearOff!.function.namedParameters.length) {
+          return _factoryTearOff!.function.namedParameters[index];
+        }
+      }
+    }
+    return null;
+  }
+
+  @override
   List<ClassMember> get localMembers =>
       throw new UnsupportedError('${runtimeType}.localMembers');
 
@@ -225,6 +241,8 @@
   final ConstructorReferenceBuilder redirectionTarget;
   List<DartType>? typeArguments;
 
+  FreshTypeParameters? _tearOffTypeParameters;
+
   RedirectingFactoryBuilder(
       List<MetadataBuilder>? metadata,
       int modifiers,
@@ -299,6 +317,9 @@
       SourceLibraryBuilder library, void Function(Member, BuiltMemberKind) f) {
     Member member = build(library);
     f(member, BuiltMemberKind.RedirectingFactory);
+    if (_factoryTearOff != null) {
+      f(_factoryTearOff!, BuiltMemberKind.Method);
+    }
   }
 
   @override
@@ -319,6 +340,12 @@
           growable: false);
     }
     updatePrivateMemberName(_procedureInternal, libraryBuilder);
+    if (_factoryTearOff != null) {
+      _tearOffTypeParameters = buildRedirectingFactoryTearOffProcedure(
+          _factoryTearOff!,
+          _procedure,
+          library as SourceLibraryBuilder);
+    }
     return _procedureInternal;
   }
 
@@ -326,72 +353,77 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder library,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers) {
-    super.buildOutlineExpressions(library, coreTypes, delayedActionPerformers);
-    LibraryBuilder thisLibrary = this.library;
-    if (thisLibrary is SourceLibraryBuilder) {
-      RedirectingFactoryBody redirectingFactoryBody =
-          _procedure.function.body as RedirectingFactoryBody;
-      if (redirectingFactoryBody.typeArguments != null &&
-          redirectingFactoryBody.typeArguments!.any((t) => t is UnknownType)) {
-        TypeInferrerImpl inferrer = thisLibrary.loader.typeInferenceEngine
-                .createLocalTypeInferrer(
-                    fileUri, classBuilder!.thisType, thisLibrary, null)
-            as TypeInferrerImpl;
-        inferrer.helper = thisLibrary.loader
-            .createBodyBuilderForOutlineExpression(
-                thisLibrary, classBuilder, this, classBuilder!.scope, fileUri);
-        Builder? targetBuilder = redirectionTarget.target;
-        Member target;
-        if (targetBuilder is FunctionBuilder) {
-          target = targetBuilder.member;
-        } else if (targetBuilder is DillMemberBuilder) {
-          target = targetBuilder.member;
-        } else {
-          unhandled("${targetBuilder.runtimeType}", "buildOutlineExpressions",
-              charOffset, fileUri);
-        }
-        Arguments targetInvocationArguments;
-        {
-          List<Expression> positionalArguments = <Expression>[];
-          for (VariableDeclaration parameter
-              in _procedure.function.positionalParameters) {
-            inferrer.flowAnalysis.declare(parameter, true);
-            positionalArguments.add(
-                new VariableGetImpl(parameter, forNullGuardedAccess: false));
-          }
-          List<NamedExpression> namedArguments = <NamedExpression>[];
-          for (VariableDeclaration parameter
-              in _procedure.function.namedParameters) {
-            inferrer.flowAnalysis.declare(parameter, true);
-            namedArguments.add(new NamedExpression(parameter.name!,
-                new VariableGetImpl(parameter, forNullGuardedAccess: false)));
-          }
-          // If arguments are created using [Forest.createArguments], and the
-          // type arguments are omitted, they are to be inferred.
-          targetInvocationArguments = const Forest().createArguments(
-              _procedure.fileOffset, positionalArguments,
-              named: namedArguments);
-        }
-        InvocationInferenceResult result = inferrer.inferInvocation(
-            function.returnType,
-            charOffset,
-            target.function!.computeFunctionType(Nullability.nonNullable),
-            targetInvocationArguments,
-            staticTarget: target);
-        List<DartType> typeArguments;
-        if (result.inferredType is InterfaceType) {
-          typeArguments = (result.inferredType as InterfaceType).typeArguments;
-        } else {
-          // Assume that the error is reported elsewhere, use 'dynamic' for
-          // recovery.
-          typeArguments = new List<DartType>.filled(
-              target.enclosingClass!.typeParameters.length, const DynamicType(),
-              growable: true);
-        }
-        member.function!.body =
-            new RedirectingFactoryBody(target, typeArguments);
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes) {
+    super.buildOutlineExpressions(
+        library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
+    RedirectingFactoryBody redirectingFactoryBody =
+        _procedure.function.body as RedirectingFactoryBody;
+    List<DartType>? typeArguments = redirectingFactoryBody.typeArguments;
+    Member? target = redirectingFactoryBody.target;
+    if (typeArguments != null && typeArguments.any((t) => t is UnknownType)) {
+      TypeInferrerImpl inferrer = library.loader.typeInferenceEngine
+              .createLocalTypeInferrer(
+                  fileUri, classBuilder!.thisType, library, null)
+          as TypeInferrerImpl;
+      inferrer.helper = library.loader.createBodyBuilderForOutlineExpression(
+          library, classBuilder, this, classBuilder!.scope, fileUri);
+      Builder? targetBuilder = redirectionTarget.target;
+      if (targetBuilder is FunctionBuilder) {
+        target = targetBuilder.member;
+      } else if (targetBuilder is DillMemberBuilder) {
+        target = targetBuilder.member;
+      } else {
+        unhandled("${targetBuilder.runtimeType}", "buildOutlineExpressions",
+            charOffset, fileUri);
       }
+      Arguments targetInvocationArguments;
+      {
+        List<Expression> positionalArguments = <Expression>[];
+        for (VariableDeclaration parameter
+            in _procedure.function.positionalParameters) {
+          inferrer.flowAnalysis.declare(parameter, true);
+          positionalArguments
+              .add(new VariableGetImpl(parameter, forNullGuardedAccess: false));
+        }
+        List<NamedExpression> namedArguments = <NamedExpression>[];
+        for (VariableDeclaration parameter
+            in _procedure.function.namedParameters) {
+          inferrer.flowAnalysis.declare(parameter, true);
+          namedArguments.add(new NamedExpression(parameter.name!,
+              new VariableGetImpl(parameter, forNullGuardedAccess: false)));
+        }
+        // If arguments are created using [Forest.createArguments], and the
+        // type arguments are omitted, they are to be inferred.
+        targetInvocationArguments = const Forest().createArguments(
+            _procedure.fileOffset, positionalArguments,
+            named: namedArguments);
+      }
+      InvocationInferenceResult result = inferrer.inferInvocation(
+          function.returnType,
+          charOffset,
+          target.function!.computeFunctionType(Nullability.nonNullable),
+          targetInvocationArguments,
+          staticTarget: target);
+      if (result.inferredType is InterfaceType) {
+        typeArguments = (result.inferredType as InterfaceType).typeArguments;
+      } else {
+        // Assume that the error is reported elsewhere, use 'dynamic' for
+        // recovery.
+        typeArguments = new List<DartType>.filled(
+            target.enclosingClass!.typeParameters.length, const DynamicType(),
+            growable: true);
+      }
+      member.function!.body = new RedirectingFactoryBody(target, typeArguments);
+    }
+    if (_factoryTearOff != null) {
+      clonedFunctionNodes.add(buildRedirectingFactoryTearOffBody(
+          _factoryTearOff!,
+          target as Constructor,
+          typeArguments ?? [],
+          _tearOffTypeParameters!));
+      delayedActionPerformers.add(new _CopyDefaultValues(
+          _factoryTearOff!, redirectingFactoryBody.target!.function!));
     }
   }
 
@@ -413,3 +445,18 @@
     return getRedirectingFactoryBody(_procedure)!.typeArguments;
   }
 }
+
+class _CopyDefaultValues implements DelayedActionPerformer {
+  final Procedure _tearOff;
+  final FunctionNode _function;
+
+  _CopyDefaultValues(this._tearOff, this._function);
+
+  @override
+  bool get hasDelayedActions => true;
+
+  @override
+  void performDelayedActions() {
+    copyTearOffDefaultValues(_tearOff, _function);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index 12b9103..b1ae35f 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -17,6 +17,7 @@
 import '../kernel/body_builder.dart' show BodyBuilder;
 import '../kernel/class_hierarchy_builder.dart';
 import '../kernel/kernel_builder.dart' show ImplicitFieldType;
+import '../kernel/kernel_target.dart';
 import '../kernel/late_lowering.dart' as late_lowering;
 import '../kernel/member_covariance.dart';
 
@@ -398,7 +399,8 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder library,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers) {
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes) {
     _fieldEncoding.completeSignature(coreTypes);
 
     for (Annotatable annotatable in _fieldEncoding.annotatables) {
diff --git a/pkg/front_end/lib/src/fasta/builder/function_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
index d74aa66..638c80f 100644
--- a/pkg/front_end/lib/src/fasta/builder/function_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
@@ -4,8 +4,8 @@
 
 library fasta.procedure_builder;
 
-import 'package:front_end/src/fasta/kernel/kernel_api.dart';
 import 'package:kernel/ast.dart';
+import 'package:kernel/core_types.dart';
 
 import 'package:kernel/type_algebra.dart' show containsTypeVariable, substitute;
 
@@ -13,6 +13,7 @@
 import '../scope.dart';
 
 import '../kernel/internal_ast.dart' show VariableDeclarationImpl;
+import '../kernel/kernel_target.dart';
 
 import '../loader.dart' show Loader;
 
@@ -478,7 +479,8 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder library,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers) {
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes) {
     if (!_hasBuiltOutlineExpressions) {
       DeclarationBuilder? classOrExtensionBuilder =
           isClassMember || isExtensionMember
diff --git a/pkg/front_end/lib/src/fasta/builder/member_builder.dart b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
index 14ae7c9..c7d1f9d 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -10,6 +10,7 @@
 import '../../base/common.dart';
 
 import '../kernel/class_hierarchy_builder.dart';
+import '../kernel/kernel_target.dart';
 import '../modifier.dart';
 import '../problems.dart' show unsupported;
 import '../source/source_library_builder.dart';
@@ -78,7 +79,8 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder library,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers);
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes);
 
   /// Returns the [ClassMember]s for the non-setter members created for this
   /// member builder.
@@ -184,7 +186,8 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder library,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers) {}
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes) {}
 
   /// Builds the core AST structures for this member as needed for the outline.
   void buildMembers(
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
index 94e7b8c..0c5d28f 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
@@ -11,6 +11,8 @@
 import '../builder/type_builder.dart';
 import '../builder/type_variable_builder.dart';
 
+import '../kernel/kernel_target.dart';
+
 import '../scope.dart';
 
 import '../util/helpers.dart';
@@ -103,8 +105,11 @@
   }
 
   @override
-  void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers) {
+  void buildOutlineExpressions(
+      LibraryBuilder library,
+      CoreTypes coreTypes,
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes) {
     // TODO(johnniwinther): Remove the need for this.
   }
 }
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 a1f4efa..f7603ef 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
@@ -2,11 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:front_end/src/fasta/kernel/kernel_api.dart';
 import 'package:kernel/ast.dart';
 import 'package:kernel/type_algebra.dart';
 import '../builder/member_builder.dart';
 import '../source/source_library_builder.dart';
+import 'kernel_api.dart';
+import 'kernel_target.dart';
 
 const String _tearOffNamePrefix = '_#';
 const String _tearOffNameSuffix = '#tearOff';
@@ -47,13 +48,11 @@
   if (!forAbstractClassOrEnum &&
       compilationUnit
           .loader.target.backendTarget.isConstructorTearOffLoweringEnabled) {
-    return new Procedure(constructorTearOffName(name, compilationUnit.library),
-        ProcedureKind.Method, new FunctionNode(null),
-        fileUri: fileUri, isStatic: true)
-      ..startFileOffset = fileOffset
-      ..fileOffset = fileOffset
-      ..fileEndOffset = fileOffset
-      ..isNonNullableByDefault = compilationUnit.isNonNullableByDefault;
+    return _createTearOffProcedure(
+        compilationUnit,
+        constructorTearOffName(name, compilationUnit.library),
+        fileUri,
+        fileOffset);
   }
   return null;
 }
@@ -78,55 +77,14 @@
     classTypeParameters = function.typeParameters;
   }
 
-  List<TypeParameter> typeParameters;
-  List<DartType> typeArguments;
-  Substitution substitution = Substitution.empty;
-  if (classTypeParameters.isNotEmpty) {
-    FreshTypeParameters freshTypeParameters =
-        getFreshTypeParameters(classTypeParameters);
-    typeParameters = freshTypeParameters.freshTypeParameters;
-    typeArguments = freshTypeParameters.freshTypeArguments;
-    substitution = freshTypeParameters.substitution;
-    tearOff.function.typeParameters.addAll(typeParameters);
-    setParents(typeParameters, tearOff.function);
-  } else {
-    typeParameters = [];
-    typeArguments = [];
-    substitution = Substitution.empty;
-  }
+  FreshTypeParameters freshTypeParameters =
+      _createFreshTypeParameters(classTypeParameters, tearOff.function);
 
-  List<Expression> positionalArguments = [];
-  for (VariableDeclaration constructorParameter
-      in function.positionalParameters) {
-    VariableDeclaration tearOffParameter = new VariableDeclaration(
-        constructorParameter.name,
-        type: substitution.substituteType(constructorParameter.type))
-      ..fileOffset = constructorParameter.fileOffset;
-    tearOff.function.positionalParameters.add(tearOffParameter);
-    positionalArguments
-        .add(new VariableGet(tearOffParameter)..fileOffset = fileOffset);
-    tearOffParameter.parent = tearOff.function;
-  }
-  List<NamedExpression> namedArguments = [];
-  for (VariableDeclaration constructorParameter in function.namedParameters) {
-    VariableDeclaration tearOffParameter = new VariableDeclaration(
-        constructorParameter.name,
-        type: substitution.substituteType(constructorParameter.type),
-        isRequired: constructorParameter.isRequired)
-      ..fileOffset = constructorParameter.fileOffset;
-    tearOff.function.namedParameters.add(tearOffParameter);
-    tearOffParameter.parent = tearOff.function;
-    namedArguments.add(new NamedExpression(tearOffParameter.name!,
-        new VariableGet(tearOffParameter)..fileOffset = fileOffset)
-      ..fileOffset = fileOffset);
-  }
-  tearOff.function.returnType =
-      substitution.substituteType(function.returnType);
-  tearOff.function.requiredParameterCount = function.requiredParameterCount;
+  List<DartType> typeArguments = freshTypeParameters.freshTypeArguments;
+  Substitution substitution = freshTypeParameters.substitution;
+  _createParameters(tearOff, function, substitution);
+  Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
 
-  Arguments arguments = new Arguments(positionalArguments,
-      named: namedArguments, types: typeArguments)
-    ..fileOffset = tearOff.fileOffset;
   Expression constructorInvocation;
   if (constructor is Constructor) {
     constructorInvocation = new ConstructorInvocation(constructor, arguments)
@@ -178,28 +136,80 @@
   }
 }
 
-void buildConstructorTearOffDefaultValues(
-    Procedure tearOff, Constructor constructor, Class enclosingClass) {
+void copyTearOffDefaultValues(Procedure tearOff, FunctionNode function) {
   CloneVisitorNotMembers cloner = new CloneVisitorNotMembers();
-  for (int i = 0; i < constructor.function.positionalParameters.length; i++) {
+  for (int i = 0; i < function.positionalParameters.length; i++) {
     VariableDeclaration tearOffParameter =
         tearOff.function.positionalParameters[i];
-    VariableDeclaration constructorParameter =
-        constructor.function.positionalParameters[i];
+    VariableDeclaration constructorParameter = function.positionalParameters[i];
     tearOffParameter.initializer =
         cloner.cloneOptional(constructorParameter.initializer);
     tearOffParameter.initializer?.parent = tearOffParameter;
   }
-  for (int i = 0; i < constructor.function.namedParameters.length; i++) {
+  for (int i = 0; i < function.namedParameters.length; i++) {
     VariableDeclaration tearOffParameter = tearOff.function.namedParameters[i];
-    VariableDeclaration constructorParameter =
-        constructor.function.namedParameters[i];
+    VariableDeclaration constructorParameter = function.namedParameters[i];
     tearOffParameter.initializer =
         cloner.cloneOptional(constructorParameter.initializer);
     tearOffParameter.initializer?.parent = tearOffParameter;
   }
 }
 
+/// Creates the parameters for the redirecting factory [tearOff] based on the
+/// [redirectingConstructor] declaration.
+FreshTypeParameters buildRedirectingFactoryTearOffProcedure(
+    Procedure tearOff,
+    Procedure redirectingConstructor,
+    SourceLibraryBuilder libraryBuilder) {
+  assert(redirectingConstructor.isRedirectingFactory);
+  FunctionNode function = redirectingConstructor.function;
+  FreshTypeParameters freshTypeParameters =
+      _createFreshTypeParameters(function.typeParameters, tearOff.function);
+  Substitution substitution = freshTypeParameters.substitution;
+  _createParameters(tearOff, function, substitution);
+  tearOff.function.fileOffset = tearOff.fileOffset;
+  tearOff.function.fileEndOffset = tearOff.fileOffset;
+  updatePrivateMemberName(tearOff, libraryBuilder);
+  return freshTypeParameters;
+}
+
+/// Creates the body for the redirecting factory [tearOff] with the target
+/// [constructor] and [typeArguments].
+///
+/// Returns the [ClonedFunctionNode] object need to perform default value
+/// computation.
+ClonedFunctionNode buildRedirectingFactoryTearOffBody(
+    Procedure tearOff,
+    Constructor constructor,
+    List<DartType> typeArguments,
+    FreshTypeParameters freshTypeParameters) {
+  int fileOffset = tearOff.fileOffset;
+
+  if (!freshTypeParameters.substitution.isEmpty) {
+    if (typeArguments.isNotEmpty) {
+      // Translate [typeArgument] into the context of the synthesized procedure.
+      typeArguments = new List<DartType>.generate(
+          typeArguments.length,
+          (int index) => freshTypeParameters.substitution
+              .substituteType(typeArguments[index]));
+    }
+  }
+
+  Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
+  Expression constructorInvocation =
+      new ConstructorInvocation(constructor, arguments)
+        ..fileOffset = tearOff.fileOffset;
+  tearOff.function.body = new ReturnStatement(constructorInvocation)
+    ..fileOffset = tearOff.fileOffset
+    ..parent = tearOff.function;
+
+  return new ClonedFunctionNode(
+      new Map<TypeParameter, DartType>.fromIterables(
+          constructor.enclosingClass.typeParameters, typeArguments),
+      constructor.function,
+      tearOff.function);
+}
+
 /// Creates the synthesized name to use for the lowering of the tear off of a
 /// typedef in [library] using [index] for a unique name within the library.
 Name typedefTearOffName(int index, Library library) {
@@ -218,54 +228,35 @@
 Procedure createTypedefTearOffLowering(SourceLibraryBuilder libraryBuilder,
     TypedefTearOff node, FunctionType targetType, Uri fileUri, int index) {
   int fileOffset = node.fileOffset;
-  Procedure tearOff = new Procedure(
+  Procedure tearOff = _createTearOffProcedure(
+      libraryBuilder,
       typedefTearOffName(index, libraryBuilder.library),
-      ProcedureKind.Method,
-      new FunctionNode(null),
-      fileUri: fileUri,
-      isStatic: true)
-    ..startFileOffset = fileOffset
-    ..fileOffset = fileOffset
-    ..fileEndOffset = fileOffset
-    ..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault;
-  List<TypeParameter> typedefTypeParameters = node.typeParameters;
-  List<TypeParameter> typeParameters;
+      fileUri,
+      node.fileOffset);
+  FreshTypeParameters freshTypeParameters =
+      _createFreshTypeParameters(node.typeParameters, tearOff.function);
+  Substitution substitution = freshTypeParameters.substitution;
+
   List<DartType> typeArguments = node.typeArguments;
-  Substitution substitution = Substitution.empty;
-  if (typedefTypeParameters.isNotEmpty) {
-    FreshTypeParameters freshTypeParameters =
-        getFreshTypeParameters(typedefTypeParameters);
-    typeParameters = freshTypeParameters.freshTypeParameters;
-    substitution = freshTypeParameters.substitution;
-    tearOff.function.typeParameters.addAll(typeParameters);
-    setParents(typeParameters, tearOff.function);
-    if (typeArguments.isNotEmpty) {
+  if (typeArguments.isNotEmpty) {
+    if (!substitution.isEmpty) {
       // Translate [typeArgument] into the context of the synthesized procedure.
       typeArguments = new List<DartType>.generate(typeArguments.length,
           (int index) => substitution.substituteType(typeArguments[index]));
     }
-  } else {
-    typeParameters = [];
-    substitution = Substitution.empty;
-  }
-  if (typeArguments.isNotEmpty) {
     // Instantiate [targetType] with [typeArguments].
     targetType =
         Substitution.fromPairs(targetType.typeParameters, typeArguments)
             .substituteType(targetType.withoutTypeParameters) as FunctionType;
   }
 
-  List<Expression> positionalArguments = [];
   for (DartType constructorParameter in targetType.positionalParameters) {
     VariableDeclaration tearOffParameter = new VariableDeclaration(null,
         type: substitution.substituteType(constructorParameter))
       ..fileOffset = fileOffset;
     tearOff.function.positionalParameters.add(tearOffParameter);
-    positionalArguments
-        .add(new VariableGet(tearOffParameter)..fileOffset = fileOffset);
     tearOffParameter.parent = tearOff.function;
   }
-  List<NamedExpression> namedArguments = [];
   for (NamedType constructorParameter in targetType.namedParameters) {
     VariableDeclaration tearOffParameter = new VariableDeclaration(
         constructorParameter.name,
@@ -274,17 +265,12 @@
       ..fileOffset = fileOffset;
     tearOff.function.namedParameters.add(tearOffParameter);
     tearOffParameter.parent = tearOff.function;
-    namedArguments.add(new NamedExpression(tearOffParameter.name!,
-        new VariableGet(tearOffParameter)..fileOffset = fileOffset)
-      ..fileOffset = fileOffset);
   }
   tearOff.function.returnType =
       substitution.substituteType(targetType.returnType);
   tearOff.function.requiredParameterCount = targetType.requiredParameterCount;
 
-  Arguments arguments = new Arguments(positionalArguments,
-      named: namedArguments, types: typeArguments)
-    ..fileOffset = tearOff.fileOffset;
+  Arguments arguments = _createArguments(tearOff, typeArguments, fileOffset);
   Expression constructorInvocation = new FunctionInvocation(
       FunctionAccessKind.FunctionType, node.expression, arguments,
       functionType: targetType)
@@ -296,3 +282,84 @@
   tearOff.function.fileEndOffset = tearOff.fileOffset;
   return tearOff;
 }
+
+/// Creates the synthesized [Procedure] node for a tear off lowering by the
+/// given [name].
+Procedure _createTearOffProcedure(SourceLibraryBuilder libraryBuilder,
+    Name name, Uri fileUri, int fileOffset) {
+  return new Procedure(name, ProcedureKind.Method, new FunctionNode(null),
+      fileUri: fileUri, isStatic: true)
+    ..startFileOffset = fileOffset
+    ..fileOffset = fileOffset
+    ..fileEndOffset = fileOffset
+    ..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault;
+}
+
+/// Creates the synthesized type parameters for a tear off lowering. The type
+/// parameters are based [originalTypeParameters] and are inserted into
+/// [newFunctionNode]. The created [FreshTypeParameters] is returned.
+FreshTypeParameters _createFreshTypeParameters(
+    List<TypeParameter> originalTypeParameters, FunctionNode newFunctionNode) {
+  FreshTypeParameters freshTypeParameters;
+  if (originalTypeParameters.isNotEmpty) {
+    freshTypeParameters = getFreshTypeParameters(originalTypeParameters);
+    List<TypeParameter> typeParameters =
+        freshTypeParameters.freshTypeParameters;
+    newFunctionNode.typeParameters.addAll(typeParameters);
+    setParents(typeParameters, newFunctionNode);
+  } else {
+    freshTypeParameters = new FreshTypeParameters([], [], Substitution.empty);
+  }
+  return freshTypeParameters;
+}
+
+/// Creates the parameters for the [tearOff] lowering based of the parameters
+/// in [function] and using the [substitution] to compute the parameter and
+/// return types.
+void _createParameters(
+    Procedure tearOff, FunctionNode function, Substitution substitution) {
+  for (VariableDeclaration constructorParameter
+      in function.positionalParameters) {
+    VariableDeclaration tearOffParameter = new VariableDeclaration(
+        constructorParameter.name,
+        type: substitution.substituteType(constructorParameter.type))
+      ..fileOffset = constructorParameter.fileOffset;
+    tearOff.function.positionalParameters.add(tearOffParameter);
+    tearOffParameter.parent = tearOff.function;
+  }
+  for (VariableDeclaration constructorParameter in function.namedParameters) {
+    VariableDeclaration tearOffParameter = new VariableDeclaration(
+        constructorParameter.name,
+        type: substitution.substituteType(constructorParameter.type),
+        isRequired: constructorParameter.isRequired)
+      ..fileOffset = constructorParameter.fileOffset;
+    tearOff.function.namedParameters.add(tearOffParameter);
+    tearOffParameter.parent = tearOff.function;
+  }
+  tearOff.function.returnType =
+      substitution.substituteType(function.returnType);
+  tearOff.function.requiredParameterCount = function.requiredParameterCount;
+}
+
+/// Creates the [Arguments] for passing the parameters from [tearOff] to its
+/// target, using [typeArguments] as the passed type arguments.
+Arguments _createArguments(
+    Procedure tearOff, List<DartType> typeArguments, int fileOffset) {
+  List<Expression> positionalArguments = [];
+  for (VariableDeclaration tearOffParameter
+      in tearOff.function.positionalParameters) {
+    positionalArguments
+        .add(new VariableGet(tearOffParameter)..fileOffset = fileOffset);
+  }
+  List<NamedExpression> namedArguments = [];
+  for (VariableDeclaration tearOffParameter
+      in tearOff.function.namedParameters) {
+    namedArguments.add(new NamedExpression(tearOffParameter.name!,
+        new VariableGet(tearOffParameter)..fileOffset = fileOffset)
+      ..fileOffset = fileOffset);
+  }
+  Arguments arguments = new Arguments(positionalArguments,
+      named: namedArguments, types: typeArguments)
+    ..fileOffset = tearOff.fileOffset;
+  return arguments;
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index c3a5e4e..a49ae77 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -336,7 +336,7 @@
       loader.checkAbstractMembers(myClasses);
       loader.addNoSuchMethodForwarders(myClasses);
       loader.checkMixins(myClasses);
-      loader.buildOutlineExpressions(loader.coreTypes);
+      loader.buildOutlineExpressions(loader.coreTypes, clonedFunctionNodes);
       loader.checkTypes();
       loader.checkRedirectingFactories(myClasses);
       loader.checkMainMethods();
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index 76daac6..9427c99 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -15,6 +15,7 @@
 import 'builder/type_variable_builder.dart';
 import 'kernel/body_builder.dart' show JumpTarget;
 import 'kernel/class_hierarchy_builder.dart' show ClassMember;
+import 'kernel/kernel_target.dart';
 import 'util/helpers.dart' show DelayedActionPerformer;
 
 import 'fasta_codes.dart'
@@ -806,8 +807,11 @@
   ProcedureKind? get kind => null;
 
   @override
-  void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers) {
+  void buildOutlineExpressions(
+      LibraryBuilder library,
+      CoreTypes coreTypes,
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes) {
     throw new UnsupportedError(
         'AmbiguousMemberBuilder.buildOutlineExpressions');
   }
diff --git a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
index a6774b6..30f4fff 100644
--- a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
@@ -26,6 +26,8 @@
         noLength,
         templateExtensionMemberConflictsWithObjectMember;
 
+import '../kernel/kernel_target.dart';
+
 import '../problems.dart';
 
 import '../scope.dart';
@@ -273,7 +275,8 @@
   void buildOutlineExpressions(
       SourceLibraryBuilder library,
       CoreTypes coreTypes,
-      List<DelayedActionPerformer> delayedActionPerformers) {
+      List<DelayedActionPerformer> delayedActionPerformers,
+      List<ClonedFunctionNode> clonedFunctionNodes) {
     MetadataBuilder.buildAnnotations(isPatch ? origin.extension : extension,
         metadata, library, this, null, fileUri);
     if (typeParameters != null) {
@@ -286,7 +289,7 @@
     void build(String ignore, Builder declaration) {
       MemberBuilder member = declaration as MemberBuilder;
       member.buildOutlineExpressions(
-          library, coreTypes, delayedActionPerformers);
+          library, coreTypes, delayedActionPerformers, clonedFunctionNodes);
     }
 
     scope.forEach(build);
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 51b2dd8..843754e 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -92,7 +92,7 @@
 import '../kernel/kernel_builder.dart'
     show ClassHierarchyBuilder, ClassMember, DelayedCheck;
 
-import '../kernel/kernel_target.dart' show KernelTarget;
+import '../kernel/kernel_target.dart' show ClonedFunctionNode, KernelTarget;
 
 import '../kernel/body_builder.dart' show BodyBuilder;
 
@@ -1182,7 +1182,8 @@
     ticker.logMs("Checked mixin declaration applications");
   }
 
-  void buildOutlineExpressions(CoreTypes coreTypes) {
+  void buildOutlineExpressions(
+      CoreTypes coreTypes, List<ClonedFunctionNode> clonedFunctionNodes) {
     List<DelayedActionPerformer> delayedActionPerformers =
         <DelayedActionPerformer>[];
     for (LibraryBuilder library in builders.values) {
@@ -1192,14 +1193,14 @@
         while (iterator.moveNext()) {
           Builder declaration = iterator.current;
           if (declaration is ClassBuilder) {
-            declaration.buildOutlineExpressions(
-                library, coreTypes, delayedActionPerformers);
+            declaration.buildOutlineExpressions(library, coreTypes,
+                delayedActionPerformers, clonedFunctionNodes);
           } else if (declaration is ExtensionBuilder) {
-            declaration.buildOutlineExpressions(
-                library, coreTypes, delayedActionPerformers);
+            declaration.buildOutlineExpressions(library, coreTypes,
+                delayedActionPerformers, clonedFunctionNodes);
           } else if (declaration is MemberBuilder) {
-            declaration.buildOutlineExpressions(
-                library, coreTypes, delayedActionPerformers);
+            declaration.buildOutlineExpressions(library, coreTypes,
+                delayedActionPerformers, clonedFunctionNodes);
           } else if (declaration is TypeAliasBuilder) {
             declaration.buildOutlineExpressions(
                 library, coreTypes, delayedActionPerformers);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart
index 80b72e45..dda860c 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart
@@ -15,6 +15,12 @@
   Class1([this.field = 42]);
 }
 
+class Class2 {
+  final int field;
+
+  Class2({this.field: 42});
+}
+
 void testDefaultValues() {
   var f1a = Class1.new;
   var c1a = f1a();
@@ -31,6 +37,22 @@
   var c1d = f1b(87);
   expect(87, c1d.field);
   throws(() => f1b(42, 87));
+
+  var f2a = Class2.new;
+  var c2a = f2a();
+  expect(42, c2a.field);
+  var c2b = f2a(field: 87);
+  expect(87, c2b.field);
+  () {
+    f2a(87); // error
+  };
+
+  dynamic f2b = Class2.new;
+  var c2c = f2b();
+  expect(42, c2c.field);
+  var c2d = f2b(field: 87);
+  expect(87, c2d.field);
+  throws(() => f2b(87));
 }
 
 expect(expected, actual) {
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.expect
index b41e8e2..066aa724 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.expect
@@ -2,11 +2,16 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f1a(42, 87); // error
 //        ^
 //
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
 import self as self;
 import "dart:core" as core;
 
@@ -18,6 +23,14 @@
   static method _#new#tearOff([core::int field = #C1]) → self::Class1
     return new self::Class1::•(field);
 }
+class Class2 extends core::Object {
+  final field core::int field;
+  constructor •({core::int field = #C1}) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::•(field: field);
+}
 static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
 static method main() → dynamic {
   core::print("inSoundMode: ${self::inSoundMode}");
@@ -30,7 +43,7 @@
   self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
   self::expect(87, c1b.{self::Class1::field}{core::int});
   () → Null {
-    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f1a(42, 87); // error
        ^" in f1a{<inapplicable>}.(42, 87);
@@ -41,12 +54,29 @@
   dynamic c1d = f1b{dynamic}.call(87);
   self::expect(87, c1d{dynamic}.field);
   self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C3;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
 }
 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 = #C3}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
   try {
     f(){() → dynamic};
   }
@@ -63,5 +93,6 @@
 constants  {
   #C1 = 42
   #C2 = static-tearoff self::Class1::_#new#tearOff
-  #C3 = false
+  #C3 = static-tearoff self::Class2::_#new#tearOff
+  #C4 = false
 }
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.transformed.expect
index ac558cd..c76d239 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.strong.transformed.expect
@@ -2,11 +2,16 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f1a(42, 87); // error
 //        ^
 //
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
 import self as self;
 import "dart:core" as core;
 
@@ -18,6 +23,14 @@
   static method _#new#tearOff([core::int field = #C1]) → self::Class1
     return new self::Class1::•(field);
 }
+class Class2 extends core::Object {
+  final field core::int field;
+  constructor •({core::int field = #C1}) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::•(field: field);
+}
 static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
 static method main() → dynamic {
   core::print("inSoundMode: ${self::inSoundMode}");
@@ -30,7 +43,7 @@
   self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
   self::expect(87, c1b.{self::Class1::field}{core::int});
   () → Null {
-    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f1a(42, 87); // error
        ^" in f1a{<inapplicable>}.(42, 87);
@@ -41,12 +54,29 @@
   dynamic c1d = f1b{dynamic}.call(87);
   self::expect(87, c1d{dynamic}.field);
   self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C3;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
 }
 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 = #C3}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
   try {
     f(){() → dynamic};
   }
@@ -63,5 +93,6 @@
 constants  {
   #C1 = 42
   #C2 = static-tearoff self::Class1::_#new#tearOff
-  #C3 = false
+  #C3 = static-tearoff self::Class2::_#new#tearOff
+  #C4 = false
 }
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline.expect
index cd95744..8aff8da 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline.expect
@@ -6,6 +6,11 @@
   Class1([this.field = 42]);
 }
 
+class Class2 {
+  final int field;
+  Class2({this.field: 42});
+}
+
 void testDefaultValues() {}
 expect(expected, actual) {}
 throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline_modelled.expect
index 0426153..ecb692c 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.textual_outline_modelled.expect
@@ -3,6 +3,11 @@
   final int field;
 }
 
+class Class2 {
+  Class2({this.field: 42});
+  final int field;
+}
+
 expect(expected, actual) {}
 final bool inSoundMode = <int?>[] is! List<int>;
 main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.expect
index b41e8e2..066aa724 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.expect
@@ -2,11 +2,16 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f1a(42, 87); // error
 //        ^
 //
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
 import self as self;
 import "dart:core" as core;
 
@@ -18,6 +23,14 @@
   static method _#new#tearOff([core::int field = #C1]) → self::Class1
     return new self::Class1::•(field);
 }
+class Class2 extends core::Object {
+  final field core::int field;
+  constructor •({core::int field = #C1}) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::•(field: field);
+}
 static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
 static method main() → dynamic {
   core::print("inSoundMode: ${self::inSoundMode}");
@@ -30,7 +43,7 @@
   self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
   self::expect(87, c1b.{self::Class1::field}{core::int});
   () → Null {
-    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f1a(42, 87); // error
        ^" in f1a{<inapplicable>}.(42, 87);
@@ -41,12 +54,29 @@
   dynamic c1d = f1b{dynamic}.call(87);
   self::expect(87, c1d{dynamic}.field);
   self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C3;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
 }
 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 = #C3}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
   try {
     f(){() → dynamic};
   }
@@ -63,5 +93,6 @@
 constants  {
   #C1 = 42
   #C2 = static-tearoff self::Class1::_#new#tearOff
-  #C3 = false
+  #C3 = static-tearoff self::Class2::_#new#tearOff
+  #C4 = false
 }
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.outline.expect
index 7554ec1..128018d 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.outline.expect
@@ -9,6 +9,13 @@
   static method _#new#tearOff([core::int field]) → self::Class1
     return new self::Class1::•(field);
 }
+class Class2 extends core::Object {
+  final field core::int field;
+  constructor •({core::int field}) → self::Class2
+    ;
+  static method _#new#tearOff({core::int field}) → self::Class2
+    return new self::Class2::•(field: field);
+}
 static final field core::bool inSoundMode;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.transformed.expect
index ac558cd..c76d239 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart.weak.transformed.expect
@@ -2,11 +2,16 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 // Try removing the extra positional arguments.
 //     f1a(42, 87); // error
 //        ^
 //
+// pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
 import self as self;
 import "dart:core" as core;
 
@@ -18,6 +23,14 @@
   static method _#new#tearOff([core::int field = #C1]) → self::Class1
     return new self::Class1::•(field);
 }
+class Class2 extends core::Object {
+  final field core::int field;
+  constructor •({core::int field = #C1}) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::•(field: field);
+}
 static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
 static method main() → dynamic {
   core::print("inSoundMode: ${self::inSoundMode}");
@@ -30,7 +43,7 @@
   self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
   self::expect(87, c1b.{self::Class1::field}{core::int});
   () → Null {
-    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:25:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:31:8: Error: Too many positional arguments: 1 allowed, but 2 found.
 Try removing the extra positional arguments.
     f1a(42, 87); // error
        ^" in f1a{<inapplicable>}.(42, 87);
@@ -41,12 +54,29 @@
   dynamic c1d = f1b{dynamic}.call(87);
   self::expect(87, c1d{dynamic}.field);
   self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/constructor_tear_off_default_values.dart:47:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C3;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
 }
 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 = #C3}) → dynamic {
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C4}) → dynamic {
   try {
     f(){() → dynamic};
   }
@@ -63,5 +93,6 @@
 constants  {
   #C1 = 42
   #C2 = static-tearoff self::Class1::_#new#tearOff
-  #C3 = false
+  #C3 = static-tearoff self::Class2::_#new#tearOff
+  #C4 = false
 }
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect
index 1411efa..7c14634 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect
@@ -88,7 +88,7 @@
     return new self::Class4::_(field);
   static factory •([core::int? field = #C1]) → self::Class4
     return new self::Class4::_(field);
-  static method _#new#tearOff([core::int? field]) → self::Class4
+  static method _#new#tearOff([core::int? field = #C1]) → self::Class4
     return self::Class4::•(field);
 }
 class Class5 extends core::Object {
@@ -101,7 +101,7 @@
     return new self::Class5::_(field1, field2);
   static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
     return new self::Class5::_(field1, field2);
-  static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+  static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
     return self::Class5::•(field1, field2);
 }
 class Class6 extends core::Object {
@@ -115,7 +115,7 @@
     return new self::Class6::_(field1, field2: field2, field3: field3);
   static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
     return new self::Class6::_(field1, field2: field2, field3: field3);
-  static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+  static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
     return self::Class6::•(field1, field2: field2, field3: field3);
 }
 static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.transformed.expect
index afcbd72..ebe5432 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.transformed.expect
@@ -88,7 +88,7 @@
     return new self::Class4::_(field);
   static factory •([core::int? field = #C1]) → self::Class4
     return new self::Class4::_(field);
-  static method _#new#tearOff([core::int? field]) → self::Class4
+  static method _#new#tearOff([core::int? field = #C1]) → self::Class4
     return self::Class4::•(field);
 }
 class Class5 extends core::Object {
@@ -101,7 +101,7 @@
     return new self::Class5::_(field1, field2);
   static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
     return new self::Class5::_(field1, field2);
-  static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+  static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
     return self::Class5::•(field1, field2);
 }
 class Class6 extends core::Object {
@@ -115,7 +115,7 @@
     return new self::Class6::_(field1, field2: field2, field3: field3);
   static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
     return new self::Class6::_(field1, field2: field2, field3: field3);
-  static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+  static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
     return self::Class6::•(field1, field2: field2, field3: field3);
 }
 static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect
index 1411efa..7c14634 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect
@@ -88,7 +88,7 @@
     return new self::Class4::_(field);
   static factory •([core::int? field = #C1]) → self::Class4
     return new self::Class4::_(field);
-  static method _#new#tearOff([core::int? field]) → self::Class4
+  static method _#new#tearOff([core::int? field = #C1]) → self::Class4
     return self::Class4::•(field);
 }
 class Class5 extends core::Object {
@@ -101,7 +101,7 @@
     return new self::Class5::_(field1, field2);
   static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
     return new self::Class5::_(field1, field2);
-  static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+  static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
     return self::Class5::•(field1, field2);
 }
 class Class6 extends core::Object {
@@ -115,7 +115,7 @@
     return new self::Class6::_(field1, field2: field2, field3: field3);
   static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
     return new self::Class6::_(field1, field2: field2, field3: field3);
-  static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+  static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
     return self::Class6::•(field1, field2: field2, field3: field3);
 }
 static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect
index afcbd72..ebe5432 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect
@@ -88,7 +88,7 @@
     return new self::Class4::_(field);
   static factory •([core::int? field = #C1]) → self::Class4
     return new self::Class4::_(field);
-  static method _#new#tearOff([core::int? field]) → self::Class4
+  static method _#new#tearOff([core::int? field = #C1]) → self::Class4
     return self::Class4::•(field);
 }
 class Class5 extends core::Object {
@@ -101,7 +101,7 @@
     return new self::Class5::_(field1, field2);
   static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
     return new self::Class5::_(field1, field2);
-  static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+  static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
     return self::Class5::•(field1, field2);
 }
 class Class6 extends core::Object {
@@ -115,7 +115,7 @@
     return new self::Class6::_(field1, field2: field2, field3: field3);
   static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
     return new self::Class6::_(field1, field2: field2, field3: field3);
-  static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+  static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
     return self::Class6::•(field1, field2: field2, field3: field3);
 }
 static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart
new file mode 100644
index 0000000..f966b5b
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart
@@ -0,0 +1,75 @@
+// 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.
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+  print('inSoundMode: $inSoundMode');
+  testDefaultValues();
+}
+
+class Class1 {
+  final int field;
+
+  Class1._(this.field);
+  factory Class1([int field = 42]) => new Class1._(field);
+}
+
+class Class2 {
+  final int field;
+
+  Class2._(this.field);
+  factory Class2({int field: 42}) => new Class2._(field);
+}
+
+void testDefaultValues() {
+  var f1a = Class1.new;
+  var c1a = f1a();
+  expect(42, c1a.field);
+  var c1b = f1a(87);
+  expect(87, c1b.field);
+  () {
+    f1a(42, 87); // error
+  };
+
+  dynamic f1b = Class1.new;
+  var c1c = f1b();
+  expect(42, c1c.field);
+  var c1d = f1b(87);
+  expect(87, c1d.field);
+  throws(() => f1b(42, 87));
+
+  var f2a = Class2.new;
+  var c2a = f2a();
+  expect(42, c2a.field);
+  var c2b = f2a(field: 87);
+  expect(87, c2b.field);
+  () {
+    f2a(87); // error
+  };
+
+  dynamic f2b = Class2.new;
+  var c2c = f2b();
+  expect(42, c2c.field);
+  var c2d = f2b(field: 87);
+  expect(87, c2d.field);
+  throws(() => f2b(87));
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(Function() f, {bool inSoundModeOnly: false}) {
+  try {
+    f();
+  } catch (e) {
+    print('Thrown: $e');
+    return;
+  }
+  if (!inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw 'Expected exception';
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.expect
new file mode 100644
index 0000000..bcc5942
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.expect
@@ -0,0 +1,106 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f1a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  final field core::int field;
+  constructor _(core::int field) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class1
+    return new self::Class1::_(field);
+  static factory •([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+  static method _#new#tearOff([core::int field = #C1]) → self::Class1
+    return self::Class1::•(field);
+}
+class Class2 extends core::Object {
+  final field core::int field;
+  constructor _(core::int field) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class2
+    return new self::Class2::_(field);
+  static factory •({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field);
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return self::Class2::•(field: field);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+  ([core::int]) → self::Class1 f1a = #C2;
+  self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+  self::expect(42, c1a.{self::Class1::field}{core::int});
+  self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+  self::expect(87, c1b.{self::Class1::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f1a(42, 87); // error
+       ^" in f1a{<inapplicable>}.(42, 87);
+  };
+  dynamic f1b = #C2;
+  dynamic c1c = f1b{dynamic}.call();
+  self::expect(42, c1c{dynamic}.field);
+  dynamic c1d = f1b{dynamic}.call(87);
+  self::expect(87, c1d{dynamic}.field);
+  self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C3;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+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 = #C4}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = static-tearoff self::Class1::_#new#tearOff
+  #C3 = static-tearoff self::Class2::_#new#tearOff
+  #C4 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.transformed.expect
new file mode 100644
index 0000000..db9b0fa
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.strong.transformed.expect
@@ -0,0 +1,106 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f1a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  final field core::int field;
+  constructor _(core::int field) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class1
+    return new self::Class1::_(field);
+  static factory •([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+  static method _#new#tearOff([core::int field = #C1]) → self::Class1
+    return self::Class1::•(field);
+}
+class Class2 extends core::Object {
+  final field core::int field;
+  constructor _(core::int field) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class2
+    return new self::Class2::_(field);
+  static factory •({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field);
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return self::Class2::•(field: field);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+  ([core::int]) → self::Class1 f1a = #C2;
+  self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+  self::expect(42, c1a.{self::Class1::field}{core::int});
+  self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+  self::expect(87, c1b.{self::Class1::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f1a(42, 87); // error
+       ^" in f1a{<inapplicable>}.(42, 87);
+  };
+  dynamic f1b = #C2;
+  dynamic c1c = f1b{dynamic}.call();
+  self::expect(42, c1c{dynamic}.field);
+  dynamic c1d = f1b{dynamic}.call(87);
+  self::expect(87, c1d{dynamic}.field);
+  self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C3;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+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 = #C4}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = static-tearoff self::Class1::_#new#tearOff
+  #C3 = static-tearoff self::Class2::_#new#tearOff
+  #C4 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline.expect
new file mode 100644
index 0000000..99a80f2
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline.expect
@@ -0,0 +1,18 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1 {
+  final int field;
+  Class1._(this.field);
+  factory Class1([int field = 42]) => new Class1._(field);
+}
+
+class Class2 {
+  final int field;
+  Class2._(this.field);
+  factory Class2({int field: 42}) => new Class2._(field);
+}
+
+void testDefaultValues() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..4f18568
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.textual_outline_modelled.expect
@@ -0,0 +1,17 @@
+class Class1 {
+  Class1._(this.field);
+  factory Class1([int field = 42]) => new Class1._(field);
+  final int field;
+}
+
+class Class2 {
+  Class2._(this.field);
+  factory Class2({int field: 42}) => new Class2._(field);
+  final int field;
+}
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
+void testDefaultValues() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.expect
new file mode 100644
index 0000000..bcc5942
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.expect
@@ -0,0 +1,106 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f1a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  final field core::int field;
+  constructor _(core::int field) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class1
+    return new self::Class1::_(field);
+  static factory •([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+  static method _#new#tearOff([core::int field = #C1]) → self::Class1
+    return self::Class1::•(field);
+}
+class Class2 extends core::Object {
+  final field core::int field;
+  constructor _(core::int field) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class2
+    return new self::Class2::_(field);
+  static factory •({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field);
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return self::Class2::•(field: field);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+  ([core::int]) → self::Class1 f1a = #C2;
+  self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+  self::expect(42, c1a.{self::Class1::field}{core::int});
+  self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+  self::expect(87, c1b.{self::Class1::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f1a(42, 87); // error
+       ^" in f1a{<inapplicable>}.(42, 87);
+  };
+  dynamic f1b = #C2;
+  dynamic c1c = f1b{dynamic}.call();
+  self::expect(42, c1c{dynamic}.field);
+  dynamic c1d = f1b{dynamic}.call(87);
+  self::expect(87, c1d{dynamic}.field);
+  self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C3;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+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 = #C4}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = static-tearoff self::Class1::_#new#tearOff
+  #C3 = static-tearoff self::Class2::_#new#tearOff
+  #C4 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.outline.expect
new file mode 100644
index 0000000..da300f3
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.outline.expect
@@ -0,0 +1,35 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  final field core::int field;
+  constructor _(core::int field) → self::Class1
+    ;
+  static method _#_#tearOff(core::int field) → self::Class1
+    return new self::Class1::_(field);
+  static factory •([core::int field]) → self::Class1
+    ;
+  static method _#new#tearOff([core::int field]) → self::Class1
+    return self::Class1::•(field);
+}
+class Class2 extends core::Object {
+  final field core::int field;
+  constructor _(core::int field) → self::Class2
+    ;
+  static method _#_#tearOff(core::int field) → self::Class2
+    return new self::Class2::_(field);
+  static factory •({core::int field}) → self::Class2
+    ;
+  static method _#new#tearOff({core::int field}) → self::Class2
+    return self::Class2::•(field: field);
+}
+static final field core::bool inSoundMode;
+static method main() → dynamic
+  ;
+static method testDefaultValues() → void
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, {core::bool inSoundModeOnly}) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.transformed.expect
new file mode 100644
index 0000000..db9b0fa
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart.weak.transformed.expect
@@ -0,0 +1,106 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f1a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  final field core::int field;
+  constructor _(core::int field) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class1
+    return new self::Class1::_(field);
+  static factory •([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+  static method _#new#tearOff([core::int field = #C1]) → self::Class1
+    return self::Class1::•(field);
+}
+class Class2 extends core::Object {
+  final field core::int field;
+  constructor _(core::int field) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class2
+    return new self::Class2::_(field);
+  static factory •({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field);
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return self::Class2::•(field: field);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+  ([core::int]) → self::Class1 f1a = #C2;
+  self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+  self::expect(42, c1a.{self::Class1::field}{core::int});
+  self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+  self::expect(87, c1b.{self::Class1::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f1a(42, 87); // error
+       ^" in f1a{<inapplicable>}.(42, 87);
+  };
+  dynamic f1b = #C2;
+  dynamic c1c = f1b{dynamic}.call();
+  self::expect(42, c1c{dynamic}.field);
+  dynamic c1d = f1b{dynamic}.call(87);
+  self::expect(87, c1d{dynamic}.field);
+  self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C3;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+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 = #C4}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = static-tearoff self::Class1::_#new#tearOff
+  #C3 = static-tearoff self::Class2::_#new#tearOff
+  #C4 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart
new file mode 100644
index 0000000..302f380
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart
@@ -0,0 +1,134 @@
+// 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.
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+  print('inSoundMode: $inSoundMode');
+  testGeneric();
+  testBounded();
+}
+
+class Class1<T> {
+  Class1._();
+  factory Class1() = Class1<T>._;
+}
+
+testGeneric() {
+  var f1a = Class1.new;
+  var c1a = f1a();
+  expect(true, c1a is Class1<dynamic>);
+  expect(false, c1a is Class1<int>);
+  var c1b = f1a<int>();
+  expect(true, c1b is Class1<int>);
+  expect(false, c1b is Class1<String>);
+  () {
+    f1a<int, String>(); // error
+  };
+
+  var f1b = f1a<int>;
+  var c1c = f1b();
+  expect(true, c1c is Class1<int>);
+  expect(false, c1c is Class1<String>);
+  () {
+    f1b<int>(); // error
+  };
+
+  dynamic f1c = Class1.new;
+  var c1d = f1c();
+  expect(true, c1a is Class1<dynamic>);
+  expect(false, c1a is Class1<int>);
+  throws(() => f1c<int, String>());
+}
+
+class Class2<T extends num> {
+  Class2._();
+  factory Class2() = Class2<T>._;
+}
+
+class Class3<T extends S, S> {
+  Class3._();
+  factory Class3() = Class3<T, S>._;
+}
+
+class Class4<T extends Class4<T>> {
+  Class4._();
+  factory Class4() = Class4<T>._;
+}
+
+class Class4int extends Class4<Class4int> {
+  Class4int._() : super._();
+  factory Class4int() = Class4int._;
+}
+
+testBounded() {
+  var f2a = Class2.new;
+  var c2a = f2a();
+  expect(true, c2a is Class2<num>);
+  expect(false, c2a is Class2<int>);
+  var c2b = f2a<int>();
+  expect(true, c2b is Class2<int>);
+  expect(false, c2b is Class2<double>);
+  () {
+    f2a<String>(); // error
+    f2a<int, String>(); // error
+  };
+
+  dynamic f2b = Class2.new;
+  var c2c = f2b();
+  expect(true, c2c is Class2<num>);
+  expect(false, c2c is Class2<int>);
+  var c2d = f2b<int>();
+  expect(true, c2d is Class2<int>);
+  expect(false, c2d is Class2<double>);
+  throws(() => f2b<String>());
+  throws(() => f2b<int, String>());
+
+  var f3a = Class3.new;
+  var c3a = f3a();
+  expect(true, c3a is Class3<dynamic, dynamic>);
+  expect(false, c3a is Class3<int, num>);
+  var c3b = f3a<int, num>();
+  expect(true, c3b is Class3<int, num>);
+  expect(false, c3b is Class3<double, num>);
+  () {
+    f3a<num, int>(); // error
+  };
+
+  dynamic f3b = Class3.new;
+  var c3c = f3b();
+  expect(true, c3c is Class3<dynamic, dynamic>);
+  expect(false, c3c is Class3<int, num>);
+  var c3d = f3b<int, num>();
+  expect(true, c3d is Class3<int, num>);
+  expect(false, c3d is Class3<double, num>);
+  throws(() => f3b<num, int>());
+
+  var f4a = Class4.new;
+  () {
+    var c4a = f4a(); // error
+  };
+
+  dynamic f4b = Class4.new;
+  throws(() => f4b());
+  var c4b = f4b<Class4int>();
+  expect(true, c4b is Class4<Class4int>);
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(Function() f, {bool inSoundModeOnly: false}) {
+  try {
+    f();
+  } catch (e) {
+    print('Thrown: $e');
+    return;
+  }
+  if (!inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw 'Expected exception';
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.expect
new file mode 100644
index 0000000..14303b7
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.expect
@@ -0,0 +1,205 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+//     f1a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+//     f1b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:74:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+//     f2a<String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+//     f2a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:96:8: Error: Type argument 'num' doesn't conform to the bound 'S' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+//     f3a<num, int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:110:18: Error: Inferred type argument 'Class4<Object?>' doesn't conform to the bound 'Class4<T>' of the type variable 'T' on 'call'.
+//  - 'Class4' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//     var c4a = f4a(); // error
+//                  ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1<self::Class1::T%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#_#tearOff::T%>
+    return new self::Class1::_<self::Class1::_#_#tearOff::T%>();
+  static factory •<T extends core::Object? = dynamic>() → self::Class1<self::Class1::•::T%>
+    let dynamic #redirecting_factory = self::Class1::_ in let self::Class1::•::T% #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+    return new self::Class1::_<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+  constructor _() → self::Class2<self::Class2::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::num>() → self::Class2<self::Class2::_#_#tearOff::T>
+    return new self::Class2::_<self::Class2::_#_#tearOff::T>();
+  static factory •<T extends core::num>() → self::Class2<self::Class2::•::T>
+    let dynamic #redirecting_factory = self::Class2::_ in let self::Class2::•::T #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+    return new self::Class2::_<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _() → self::Class3<self::Class3::T%, self::Class3::S%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends self::Class3::_#_#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>
+    return new self::Class3::_<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>();
+  static factory •<T extends self::Class3::•::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::•::T%, self::Class3::•::S%>
+    let dynamic #redirecting_factory = self::Class3::_ in let self::Class3::•::T% #typeArg0 = null in let self::Class3::•::S% #typeArg1 = null in invalid-expression;
+  static method _#new#tearOff<T extends self::Class3::_#new#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>
+    return new self::Class3::_<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>();
+}
+class Class4<T extends self::Class4<self::Class4::T> = self::Class4<dynamic>> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _() → self::Class4<self::Class4::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends self::Class4<self::Class4::_#_#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#_#tearOff::T>
+    return new self::Class4::_<self::Class4::_#_#tearOff::T>();
+  static factory •<T extends self::Class4<self::Class4::•::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::•::T>
+    let dynamic #redirecting_factory = self::Class4::_ in let self::Class4::•::T #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+    return new self::Class4::_<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+  static final field dynamic _redirecting# = <dynamic>[self::Class4int::•]/*isLegacy*/;
+  constructor _() → self::Class4int
+    : super self::Class4::_()
+    ;
+  static method _#_#tearOff() → self::Class4int
+    return new self::Class4int::_();
+  static factory •() → self::Class4int
+    let dynamic #redirecting_factory = self::Class4int::_ in invalid-expression;
+  static method _#new#tearOff() → self::Class4int
+    return new self::Class4int::_();
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testGeneric();
+  self::testBounded();
+}
+static method testGeneric() → dynamic {
+  <T extends core::Object? = dynamic>() → self::Class1<T%> f1a = #C1;
+  self::Class1<dynamic> c1a = f1a<dynamic>(){() → self::Class1<dynamic>};
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+  self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::Class1<core::int> c1b = f1a<core::int>(){() → self::Class1<core::int>};
+  self::expect(true, c1b is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::expect(false, c1b is{ForNonNullableByDefault} self::Class1<core::String>);
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+    f1a<int, String>(); // error
+       ^" in f1a{<inapplicable>}.<core::int, core::String>();
+  };
+  () → self::Class1<core::int> f1b = f1a<core::int>;
+  self::Class1<core::int> c1c = f1b(){() → self::Class1<core::int>};
+  self::expect(true, c1c is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::expect(false, c1c is{ForNonNullableByDefault} self::Class1<core::String>);
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+    f1b<int>(); // error
+       ^" in f1b{<inapplicable>}.<core::int>();
+  };
+  dynamic f1c = #C1;
+  dynamic c1d = f1c{dynamic}.call();
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+  self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::throws(() → dynamic => f1c{dynamic}.call<core::int, core::String>());
+}
+static method testBounded() → dynamic {
+  <T extends core::num>() → self::Class2<T> f2a = #C2;
+  self::Class2<core::num> c2a = f2a<core::num>(){() → self::Class2<core::num>};
+  self::expect(true, c2a is{ForNonNullableByDefault} self::Class2<core::num>);
+  self::expect(false, c2a is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::Class2<core::int> c2b = f2a<core::int>(){() → self::Class2<core::int>};
+  self::expect(true, c2b is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::expect(false, c2b is{ForNonNullableByDefault} self::Class2<core::double>);
+  () → Null {
+    f2a<core::String>(){() → self::Class2<core::String>};
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+    f2a<int, String>(); // error
+       ^" in f2a{<inapplicable>}.<core::int, core::String>();
+  };
+  dynamic f2b = #C2;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(true, c2c is{ForNonNullableByDefault} self::Class2<core::num>);
+  self::expect(false, c2c is{ForNonNullableByDefault} self::Class2<core::int>);
+  dynamic c2d = f2b{dynamic}.call<core::int>();
+  self::expect(true, c2d is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::expect(false, c2d is{ForNonNullableByDefault} self::Class2<core::double>);
+  self::throws(() → dynamic => f2b{dynamic}.call<core::String>());
+  self::throws(() → dynamic => f2b{dynamic}.call<core::int, core::String>());
+  <T extends S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<T%, S%> f3a = #C3;
+  self::Class3<dynamic, dynamic> c3a = f3a<dynamic, dynamic>(){() → self::Class3<dynamic, dynamic>};
+  self::expect(true, c3a is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+  self::expect(false, c3a is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::Class3<core::int, core::num> c3b = f3a<core::int, core::num>(){() → self::Class3<core::int, core::num>};
+  self::expect(true, c3b is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::expect(false, c3b is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+  () → Null {
+    f3a<core::num, core::int>(){() → self::Class3<core::num, core::int>};
+  };
+  dynamic f3b = #C3;
+  dynamic c3c = f3b{dynamic}.call();
+  self::expect(true, c3c is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+  self::expect(false, c3c is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  dynamic c3d = f3b{dynamic}.call<core::int, core::num>();
+  self::expect(true, c3d is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::expect(false, c3d is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+  self::throws(() → dynamic => f3b{dynamic}.call<core::num, core::int>());
+  <T extends self::Class4<T> = self::Class4<dynamic>>() → self::Class4<T> f4a = #C4;
+  () → Null {
+    self::Class4<self::Class4<core::Object?>> c4a = f4a<self::Class4<core::Object?>>(){() → self::Class4<self::Class4<core::Object?>>};
+  };
+  dynamic f4b = #C4;
+  self::throws(() → dynamic => f4b{dynamic}.call());
+  dynamic c4b = f4b{dynamic}.call<self::Class4int>();
+  self::expect(true, c4b is{ForNonNullableByDefault} self::Class4<self::Class4int>);
+}
+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 = #C5}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = static-tearoff self::Class1::_#new#tearOff
+  #C2 = static-tearoff self::Class2::_#new#tearOff
+  #C3 = static-tearoff self::Class3::_#new#tearOff
+  #C4 = static-tearoff self::Class4::_#new#tearOff
+  #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.transformed.expect
new file mode 100644
index 0000000..2ede93c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.strong.transformed.expect
@@ -0,0 +1,205 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+//     f1a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+//     f1b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:74:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+//     f2a<String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+//     f2a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:96:8: Error: Type argument 'num' doesn't conform to the bound 'S' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+//     f3a<num, int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:110:18: Error: Inferred type argument 'Class4<Object?>' doesn't conform to the bound 'Class4<T>' of the type variable 'T' on 'call'.
+//  - 'Class4' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//     var c4a = f4a(); // error
+//                  ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1<self::Class1::T%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#_#tearOff::T%>
+    return new self::Class1::_<self::Class1::_#_#tearOff::T%>();
+  static factory •<T extends core::Object? = dynamic>() → self::Class1<self::Class1::•::T%>
+    let Never #redirecting_factory = self::Class1::_ in let self::Class1::•::T% #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+    return new self::Class1::_<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+  constructor _() → self::Class2<self::Class2::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::num>() → self::Class2<self::Class2::_#_#tearOff::T>
+    return new self::Class2::_<self::Class2::_#_#tearOff::T>();
+  static factory •<T extends core::num>() → self::Class2<self::Class2::•::T>
+    let Never #redirecting_factory = self::Class2::_ in let self::Class2::•::T #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+    return new self::Class2::_<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _() → self::Class3<self::Class3::T%, self::Class3::S%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends self::Class3::_#_#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>
+    return new self::Class3::_<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>();
+  static factory •<T extends self::Class3::•::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::•::T%, self::Class3::•::S%>
+    let Never #redirecting_factory = self::Class3::_ in let self::Class3::•::T% #typeArg0 = null in let self::Class3::•::S% #typeArg1 = null in invalid-expression;
+  static method _#new#tearOff<T extends self::Class3::_#new#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>
+    return new self::Class3::_<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>();
+}
+class Class4<T extends self::Class4<self::Class4::T> = self::Class4<dynamic>> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _() → self::Class4<self::Class4::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends self::Class4<self::Class4::_#_#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#_#tearOff::T>
+    return new self::Class4::_<self::Class4::_#_#tearOff::T>();
+  static factory •<T extends self::Class4<self::Class4::•::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::•::T>
+    let Never #redirecting_factory = self::Class4::_ in let self::Class4::•::T #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+    return new self::Class4::_<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+  static final field dynamic _redirecting# = <dynamic>[self::Class4int::•]/*isLegacy*/;
+  constructor _() → self::Class4int
+    : super self::Class4::_()
+    ;
+  static method _#_#tearOff() → self::Class4int
+    return new self::Class4int::_();
+  static factory •() → self::Class4int
+    let Never #redirecting_factory = self::Class4int::_ in invalid-expression;
+  static method _#new#tearOff() → self::Class4int
+    return new self::Class4int::_();
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testGeneric();
+  self::testBounded();
+}
+static method testGeneric() → dynamic {
+  <T extends core::Object? = dynamic>() → self::Class1<T%> f1a = #C1;
+  self::Class1<dynamic> c1a = f1a<dynamic>(){() → self::Class1<dynamic>};
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+  self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::Class1<core::int> c1b = f1a<core::int>(){() → self::Class1<core::int>};
+  self::expect(true, c1b is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::expect(false, c1b is{ForNonNullableByDefault} self::Class1<core::String>);
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+    f1a<int, String>(); // error
+       ^" in f1a{<inapplicable>}.<core::int, core::String>();
+  };
+  () → self::Class1<core::int> f1b = f1a<core::int>;
+  self::Class1<core::int> c1c = f1b(){() → self::Class1<core::int>};
+  self::expect(true, c1c is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::expect(false, c1c is{ForNonNullableByDefault} self::Class1<core::String>);
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+    f1b<int>(); // error
+       ^" in f1b{<inapplicable>}.<core::int>();
+  };
+  dynamic f1c = #C1;
+  dynamic c1d = f1c{dynamic}.call();
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+  self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::throws(() → dynamic => f1c{dynamic}.call<core::int, core::String>());
+}
+static method testBounded() → dynamic {
+  <T extends core::num>() → self::Class2<T> f2a = #C2;
+  self::Class2<core::num> c2a = f2a<core::num>(){() → self::Class2<core::num>};
+  self::expect(true, c2a is{ForNonNullableByDefault} self::Class2<core::num>);
+  self::expect(false, c2a is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::Class2<core::int> c2b = f2a<core::int>(){() → self::Class2<core::int>};
+  self::expect(true, c2b is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::expect(false, c2b is{ForNonNullableByDefault} self::Class2<core::double>);
+  () → Null {
+    f2a<core::String>(){() → self::Class2<core::String>};
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+    f2a<int, String>(); // error
+       ^" in f2a{<inapplicable>}.<core::int, core::String>();
+  };
+  dynamic f2b = #C2;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(true, c2c is{ForNonNullableByDefault} self::Class2<core::num>);
+  self::expect(false, c2c is{ForNonNullableByDefault} self::Class2<core::int>);
+  dynamic c2d = f2b{dynamic}.call<core::int>();
+  self::expect(true, c2d is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::expect(false, c2d is{ForNonNullableByDefault} self::Class2<core::double>);
+  self::throws(() → dynamic => f2b{dynamic}.call<core::String>());
+  self::throws(() → dynamic => f2b{dynamic}.call<core::int, core::String>());
+  <T extends S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<T%, S%> f3a = #C3;
+  self::Class3<dynamic, dynamic> c3a = f3a<dynamic, dynamic>(){() → self::Class3<dynamic, dynamic>};
+  self::expect(true, c3a is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+  self::expect(false, c3a is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::Class3<core::int, core::num> c3b = f3a<core::int, core::num>(){() → self::Class3<core::int, core::num>};
+  self::expect(true, c3b is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::expect(false, c3b is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+  () → Null {
+    f3a<core::num, core::int>(){() → self::Class3<core::num, core::int>};
+  };
+  dynamic f3b = #C3;
+  dynamic c3c = f3b{dynamic}.call();
+  self::expect(true, c3c is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+  self::expect(false, c3c is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  dynamic c3d = f3b{dynamic}.call<core::int, core::num>();
+  self::expect(true, c3d is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::expect(false, c3d is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+  self::throws(() → dynamic => f3b{dynamic}.call<core::num, core::int>());
+  <T extends self::Class4<T> = self::Class4<dynamic>>() → self::Class4<T> f4a = #C4;
+  () → Null {
+    self::Class4<self::Class4<core::Object?>> c4a = f4a<self::Class4<core::Object?>>(){() → self::Class4<self::Class4<core::Object?>>};
+  };
+  dynamic f4b = #C4;
+  self::throws(() → dynamic => f4b{dynamic}.call());
+  dynamic c4b = f4b{dynamic}.call<self::Class4int>();
+  self::expect(true, c4b is{ForNonNullableByDefault} self::Class4<self::Class4int>);
+}
+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 = #C5}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = static-tearoff self::Class1::_#new#tearOff
+  #C2 = static-tearoff self::Class2::_#new#tearOff
+  #C3 = static-tearoff self::Class3::_#new#tearOff
+  #C4 = static-tearoff self::Class4::_#new#tearOff
+  #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline.expect
new file mode 100644
index 0000000..ad86735
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline.expect
@@ -0,0 +1,33 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1<T> {
+  Class1._();
+  factory Class1() = Class1<T>._;
+}
+
+testGeneric() {}
+
+class Class2<T extends num> {
+  Class2._();
+  factory Class2() = Class2<T>._;
+}
+
+class Class3<T extends S, S> {
+  Class3._();
+  factory Class3() = Class3<T, S>._;
+}
+
+class Class4<T extends Class4<T>> {
+  Class4._();
+  factory Class4() = Class4<T>._;
+}
+
+class Class4int extends Class4<Class4int> {
+  Class4int._() : super._();
+  factory Class4int() = Class4int._;
+}
+
+testBounded() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..24223f7
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.textual_outline_modelled.expect
@@ -0,0 +1,31 @@
+class Class1<T> {
+  Class1._();
+  factory Class1() = Class1<T>._;
+}
+
+class Class2<T extends num> {
+  Class2._();
+  factory Class2() = Class2<T>._;
+}
+
+class Class3<T extends S, S> {
+  Class3._();
+  factory Class3() = Class3<T, S>._;
+}
+
+class Class4<T extends Class4<T>> {
+  Class4._();
+  factory Class4() = Class4<T>._;
+}
+
+class Class4int extends Class4<Class4int> {
+  Class4int._() : super._();
+  factory Class4int() = Class4int._;
+}
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+testBounded() {}
+testGeneric() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.expect
new file mode 100644
index 0000000..14303b7
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.expect
@@ -0,0 +1,205 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+//     f1a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+//     f1b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:74:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+//     f2a<String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+//     f2a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:96:8: Error: Type argument 'num' doesn't conform to the bound 'S' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+//     f3a<num, int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:110:18: Error: Inferred type argument 'Class4<Object?>' doesn't conform to the bound 'Class4<T>' of the type variable 'T' on 'call'.
+//  - 'Class4' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//     var c4a = f4a(); // error
+//                  ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1<self::Class1::T%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#_#tearOff::T%>
+    return new self::Class1::_<self::Class1::_#_#tearOff::T%>();
+  static factory •<T extends core::Object? = dynamic>() → self::Class1<self::Class1::•::T%>
+    let dynamic #redirecting_factory = self::Class1::_ in let self::Class1::•::T% #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+    return new self::Class1::_<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+  constructor _() → self::Class2<self::Class2::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::num>() → self::Class2<self::Class2::_#_#tearOff::T>
+    return new self::Class2::_<self::Class2::_#_#tearOff::T>();
+  static factory •<T extends core::num>() → self::Class2<self::Class2::•::T>
+    let dynamic #redirecting_factory = self::Class2::_ in let self::Class2::•::T #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+    return new self::Class2::_<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _() → self::Class3<self::Class3::T%, self::Class3::S%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends self::Class3::_#_#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>
+    return new self::Class3::_<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>();
+  static factory •<T extends self::Class3::•::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::•::T%, self::Class3::•::S%>
+    let dynamic #redirecting_factory = self::Class3::_ in let self::Class3::•::T% #typeArg0 = null in let self::Class3::•::S% #typeArg1 = null in invalid-expression;
+  static method _#new#tearOff<T extends self::Class3::_#new#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>
+    return new self::Class3::_<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>();
+}
+class Class4<T extends self::Class4<self::Class4::T> = self::Class4<dynamic>> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _() → self::Class4<self::Class4::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends self::Class4<self::Class4::_#_#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#_#tearOff::T>
+    return new self::Class4::_<self::Class4::_#_#tearOff::T>();
+  static factory •<T extends self::Class4<self::Class4::•::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::•::T>
+    let dynamic #redirecting_factory = self::Class4::_ in let self::Class4::•::T #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+    return new self::Class4::_<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+  static final field dynamic _redirecting# = <dynamic>[self::Class4int::•]/*isLegacy*/;
+  constructor _() → self::Class4int
+    : super self::Class4::_()
+    ;
+  static method _#_#tearOff() → self::Class4int
+    return new self::Class4int::_();
+  static factory •() → self::Class4int
+    let dynamic #redirecting_factory = self::Class4int::_ in invalid-expression;
+  static method _#new#tearOff() → self::Class4int
+    return new self::Class4int::_();
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testGeneric();
+  self::testBounded();
+}
+static method testGeneric() → dynamic {
+  <T extends core::Object? = dynamic>() → self::Class1<T%> f1a = #C1;
+  self::Class1<dynamic> c1a = f1a<dynamic>(){() → self::Class1<dynamic>};
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+  self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::Class1<core::int> c1b = f1a<core::int>(){() → self::Class1<core::int>};
+  self::expect(true, c1b is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::expect(false, c1b is{ForNonNullableByDefault} self::Class1<core::String>);
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+    f1a<int, String>(); // error
+       ^" in f1a{<inapplicable>}.<core::int, core::String>();
+  };
+  () → self::Class1<core::int> f1b = f1a<core::int>;
+  self::Class1<core::int> c1c = f1b(){() → self::Class1<core::int>};
+  self::expect(true, c1c is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::expect(false, c1c is{ForNonNullableByDefault} self::Class1<core::String>);
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+    f1b<int>(); // error
+       ^" in f1b{<inapplicable>}.<core::int>();
+  };
+  dynamic f1c = #C1;
+  dynamic c1d = f1c{dynamic}.call();
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+  self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::throws(() → dynamic => f1c{dynamic}.call<core::int, core::String>());
+}
+static method testBounded() → dynamic {
+  <T extends core::num>() → self::Class2<T> f2a = #C2;
+  self::Class2<core::num> c2a = f2a<core::num>(){() → self::Class2<core::num>};
+  self::expect(true, c2a is{ForNonNullableByDefault} self::Class2<core::num>);
+  self::expect(false, c2a is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::Class2<core::int> c2b = f2a<core::int>(){() → self::Class2<core::int>};
+  self::expect(true, c2b is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::expect(false, c2b is{ForNonNullableByDefault} self::Class2<core::double>);
+  () → Null {
+    f2a<core::String>(){() → self::Class2<core::String>};
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+    f2a<int, String>(); // error
+       ^" in f2a{<inapplicable>}.<core::int, core::String>();
+  };
+  dynamic f2b = #C2;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(true, c2c is{ForNonNullableByDefault} self::Class2<core::num>);
+  self::expect(false, c2c is{ForNonNullableByDefault} self::Class2<core::int>);
+  dynamic c2d = f2b{dynamic}.call<core::int>();
+  self::expect(true, c2d is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::expect(false, c2d is{ForNonNullableByDefault} self::Class2<core::double>);
+  self::throws(() → dynamic => f2b{dynamic}.call<core::String>());
+  self::throws(() → dynamic => f2b{dynamic}.call<core::int, core::String>());
+  <T extends S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<T%, S%> f3a = #C3;
+  self::Class3<dynamic, dynamic> c3a = f3a<dynamic, dynamic>(){() → self::Class3<dynamic, dynamic>};
+  self::expect(true, c3a is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+  self::expect(false, c3a is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::Class3<core::int, core::num> c3b = f3a<core::int, core::num>(){() → self::Class3<core::int, core::num>};
+  self::expect(true, c3b is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::expect(false, c3b is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+  () → Null {
+    f3a<core::num, core::int>(){() → self::Class3<core::num, core::int>};
+  };
+  dynamic f3b = #C3;
+  dynamic c3c = f3b{dynamic}.call();
+  self::expect(true, c3c is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+  self::expect(false, c3c is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  dynamic c3d = f3b{dynamic}.call<core::int, core::num>();
+  self::expect(true, c3d is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::expect(false, c3d is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+  self::throws(() → dynamic => f3b{dynamic}.call<core::num, core::int>());
+  <T extends self::Class4<T> = self::Class4<dynamic>>() → self::Class4<T> f4a = #C4;
+  () → Null {
+    self::Class4<self::Class4<core::Object?>> c4a = f4a<self::Class4<core::Object?>>(){() → self::Class4<self::Class4<core::Object?>>};
+  };
+  dynamic f4b = #C4;
+  self::throws(() → dynamic => f4b{dynamic}.call());
+  dynamic c4b = f4b{dynamic}.call<self::Class4int>();
+  self::expect(true, c4b is{ForNonNullableByDefault} self::Class4<self::Class4int>);
+}
+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 = #C5}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = static-tearoff self::Class1::_#new#tearOff
+  #C2 = static-tearoff self::Class2::_#new#tearOff
+  #C3 = static-tearoff self::Class3::_#new#tearOff
+  #C4 = static-tearoff self::Class4::_#new#tearOff
+  #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.outline.expect
new file mode 100644
index 0000000..26553e6
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.outline.expect
@@ -0,0 +1,70 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1<self::Class1::T%>
+    ;
+  static method _#_#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#_#tearOff::T%>
+    return new self::Class1::_<self::Class1::_#_#tearOff::T%>();
+  static factory •<T extends core::Object? = dynamic>() → self::Class1<self::Class1::•::T%>
+    let dynamic #redirecting_factory = self::Class1::_ in let self::Class1::•::T% #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+    return new self::Class1::_<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+  constructor _() → self::Class2<self::Class2::T>
+    ;
+  static method _#_#tearOff<T extends core::num>() → self::Class2<self::Class2::_#_#tearOff::T>
+    return new self::Class2::_<self::Class2::_#_#tearOff::T>();
+  static factory •<T extends core::num>() → self::Class2<self::Class2::•::T>
+    let dynamic #redirecting_factory = self::Class2::_ in let self::Class2::•::T #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+    return new self::Class2::_<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _() → self::Class3<self::Class3::T%, self::Class3::S%>
+    ;
+  static method _#_#tearOff<T extends self::Class3::_#_#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>
+    return new self::Class3::_<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>();
+  static factory •<T extends self::Class3::•::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::•::T%, self::Class3::•::S%>
+    let dynamic #redirecting_factory = self::Class3::_ in let self::Class3::•::T% #typeArg0 = null in let self::Class3::•::S% #typeArg1 = null in invalid-expression;
+  static method _#new#tearOff<T extends self::Class3::_#new#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>
+    return new self::Class3::_<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>();
+}
+class Class4<T extends self::Class4<self::Class4::T> = self::Class4<dynamic>> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _() → self::Class4<self::Class4::T>
+    ;
+  static method _#_#tearOff<T extends self::Class4<self::Class4::_#_#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#_#tearOff::T>
+    return new self::Class4::_<self::Class4::_#_#tearOff::T>();
+  static factory •<T extends self::Class4<self::Class4::•::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::•::T>
+    let dynamic #redirecting_factory = self::Class4::_ in let self::Class4::•::T #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+    return new self::Class4::_<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+  static final field dynamic _redirecting# = <dynamic>[self::Class4int::•]/*isLegacy*/;
+  constructor _() → self::Class4int
+    ;
+  static method _#_#tearOff() → self::Class4int
+    return new self::Class4int::_();
+  static factory •() → self::Class4int
+    let dynamic #redirecting_factory = self::Class4int::_ in invalid-expression;
+  static method _#new#tearOff() → self::Class4int
+    return new self::Class4int::_();
+}
+static final field core::bool inSoundMode;
+static method main() → dynamic
+  ;
+static method testGeneric() → dynamic
+  ;
+static method testBounded() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, {core::bool inSoundModeOnly}) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.transformed.expect
new file mode 100644
index 0000000..2ede93c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart.weak.transformed.expect
@@ -0,0 +1,205 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+//     f1a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+//     f1b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:74:8: Error: Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+//     f2a<String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+//     f2a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:96:8: Error: Type argument 'num' doesn't conform to the bound 'S' of the type variable 'T' on 'call'.
+// Try changing type arguments so that they conform to the bounds.
+//     f3a<num, int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:110:18: Error: Inferred type argument 'Class4<Object?>' doesn't conform to the bound 'Class4<T>' of the type variable 'T' on 'call'.
+//  - 'Class4' is from 'pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart'.
+//  - 'Object' is from 'dart:core'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//     var c4a = f4a(); // error
+//                  ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1<self::Class1::T%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#_#tearOff::T%>
+    return new self::Class1::_<self::Class1::_#_#tearOff::T%>();
+  static factory •<T extends core::Object? = dynamic>() → self::Class1<self::Class1::•::T%>
+    let Never #redirecting_factory = self::Class1::_ in let self::Class1::•::T% #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+    return new self::Class1::_<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+  constructor _() → self::Class2<self::Class2::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::num>() → self::Class2<self::Class2::_#_#tearOff::T>
+    return new self::Class2::_<self::Class2::_#_#tearOff::T>();
+  static factory •<T extends core::num>() → self::Class2<self::Class2::•::T>
+    let Never #redirecting_factory = self::Class2::_ in let self::Class2::•::T #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+    return new self::Class2::_<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _() → self::Class3<self::Class3::T%, self::Class3::S%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends self::Class3::_#_#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>
+    return new self::Class3::_<self::Class3::_#_#tearOff::T%, self::Class3::_#_#tearOff::S%>();
+  static factory •<T extends self::Class3::•::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::•::T%, self::Class3::•::S%>
+    let Never #redirecting_factory = self::Class3::_ in let self::Class3::•::T% #typeArg0 = null in let self::Class3::•::S% #typeArg1 = null in invalid-expression;
+  static method _#new#tearOff<T extends self::Class3::_#new#tearOff::S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>
+    return new self::Class3::_<self::Class3::_#new#tearOff::T%, self::Class3::_#new#tearOff::S%>();
+}
+class Class4<T extends self::Class4<self::Class4::T> = self::Class4<dynamic>> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _() → self::Class4<self::Class4::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends self::Class4<self::Class4::_#_#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#_#tearOff::T>
+    return new self::Class4::_<self::Class4::_#_#tearOff::T>();
+  static factory •<T extends self::Class4<self::Class4::•::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::•::T>
+    let Never #redirecting_factory = self::Class4::_ in let self::Class4::•::T #typeArg0 = null in invalid-expression;
+  static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+    return new self::Class4::_<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+  static final field dynamic _redirecting# = <dynamic>[self::Class4int::•]/*isLegacy*/;
+  constructor _() → self::Class4int
+    : super self::Class4::_()
+    ;
+  static method _#_#tearOff() → self::Class4int
+    return new self::Class4int::_();
+  static factory •() → self::Class4int
+    let Never #redirecting_factory = self::Class4int::_ in invalid-expression;
+  static method _#new#tearOff() → self::Class4int
+    return new self::Class4int::_();
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testGeneric();
+  self::testBounded();
+}
+static method testGeneric() → dynamic {
+  <T extends core::Object? = dynamic>() → self::Class1<T%> f1a = #C1;
+  self::Class1<dynamic> c1a = f1a<dynamic>(){() → self::Class1<dynamic>};
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+  self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::Class1<core::int> c1b = f1a<core::int>(){() → self::Class1<core::int>};
+  self::expect(true, c1b is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::expect(false, c1b is{ForNonNullableByDefault} self::Class1<core::String>);
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+    f1a<int, String>(); // error
+       ^" in f1a{<inapplicable>}.<core::int, core::String>();
+  };
+  () → self::Class1<core::int> f1b = f1a<core::int>;
+  self::Class1<core::int> c1c = f1b(){() → self::Class1<core::int>};
+  self::expect(true, c1c is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::expect(false, c1c is{ForNonNullableByDefault} self::Class1<core::String>);
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+    f1b<int>(); // error
+       ^" in f1b{<inapplicable>}.<core::int>();
+  };
+  dynamic f1c = #C1;
+  dynamic c1d = f1c{dynamic}.call();
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1<dynamic>);
+  self::expect(false, c1a is{ForNonNullableByDefault} self::Class1<core::int>);
+  self::throws(() → dynamic => f1c{dynamic}.call<core::int, core::String>());
+}
+static method testBounded() → dynamic {
+  <T extends core::num>() → self::Class2<T> f2a = #C2;
+  self::Class2<core::num> c2a = f2a<core::num>(){() → self::Class2<core::num>};
+  self::expect(true, c2a is{ForNonNullableByDefault} self::Class2<core::num>);
+  self::expect(false, c2a is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::Class2<core::int> c2b = f2a<core::int>(){() → self::Class2<core::int>};
+  self::expect(true, c2b is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::expect(false, c2b is{ForNonNullableByDefault} self::Class2<core::double>);
+  () → Null {
+    f2a<core::String>(){() → self::Class2<core::String>};
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/generic_redirecting_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+    f2a<int, String>(); // error
+       ^" in f2a{<inapplicable>}.<core::int, core::String>();
+  };
+  dynamic f2b = #C2;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(true, c2c is{ForNonNullableByDefault} self::Class2<core::num>);
+  self::expect(false, c2c is{ForNonNullableByDefault} self::Class2<core::int>);
+  dynamic c2d = f2b{dynamic}.call<core::int>();
+  self::expect(true, c2d is{ForNonNullableByDefault} self::Class2<core::int>);
+  self::expect(false, c2d is{ForNonNullableByDefault} self::Class2<core::double>);
+  self::throws(() → dynamic => f2b{dynamic}.call<core::String>());
+  self::throws(() → dynamic => f2b{dynamic}.call<core::int, core::String>());
+  <T extends S% = dynamic, S extends core::Object? = dynamic>() → self::Class3<T%, S%> f3a = #C3;
+  self::Class3<dynamic, dynamic> c3a = f3a<dynamic, dynamic>(){() → self::Class3<dynamic, dynamic>};
+  self::expect(true, c3a is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+  self::expect(false, c3a is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::Class3<core::int, core::num> c3b = f3a<core::int, core::num>(){() → self::Class3<core::int, core::num>};
+  self::expect(true, c3b is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::expect(false, c3b is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+  () → Null {
+    f3a<core::num, core::int>(){() → self::Class3<core::num, core::int>};
+  };
+  dynamic f3b = #C3;
+  dynamic c3c = f3b{dynamic}.call();
+  self::expect(true, c3c is{ForNonNullableByDefault} self::Class3<dynamic, dynamic>);
+  self::expect(false, c3c is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  dynamic c3d = f3b{dynamic}.call<core::int, core::num>();
+  self::expect(true, c3d is{ForNonNullableByDefault} self::Class3<core::int, core::num>);
+  self::expect(false, c3d is{ForNonNullableByDefault} self::Class3<core::double, core::num>);
+  self::throws(() → dynamic => f3b{dynamic}.call<core::num, core::int>());
+  <T extends self::Class4<T> = self::Class4<dynamic>>() → self::Class4<T> f4a = #C4;
+  () → Null {
+    self::Class4<self::Class4<core::Object?>> c4a = f4a<self::Class4<core::Object?>>(){() → self::Class4<self::Class4<core::Object?>>};
+  };
+  dynamic f4b = #C4;
+  self::throws(() → dynamic => f4b{dynamic}.call());
+  dynamic c4b = f4b{dynamic}.call<self::Class4int>();
+  self::expect(true, c4b is{ForNonNullableByDefault} self::Class4<self::Class4int>);
+}
+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 = #C5}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = static-tearoff self::Class1::_#new#tearOff
+  #C2 = static-tearoff self::Class2::_#new#tearOff
+  #C3 = static-tearoff self::Class3::_#new#tearOff
+  #C4 = static-tearoff self::Class4::_#new#tearOff
+  #C5 = false
+}
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
new file mode 100644
index 0000000..75d63fa
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart
@@ -0,0 +1,163 @@
+// 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.
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+  print('inSoundMode: $inSoundMode');
+  testNoArgs();
+  testArgs();
+}
+
+class Class1 {
+  Class1._();
+  factory Class1() = Class1._;
+}
+
+class Class2 {
+  Class2._();
+  factory Class2.named() = Class2._;
+}
+
+testNoArgs() {
+  var f1a = Class1.new;
+  var c1a = f1a();
+  expect(true, c1a is Class1);
+
+  dynamic f1b = Class1.new;
+  var c1b = f1b();
+  expect(true, c1b is Class1);
+
+  expect(true, identical(f1a, f1b));
+
+  var f2a = Class2.named;
+  var c2a = f2a();
+  expect(true, c2a is Class2);
+
+  dynamic f2b = Class2.named;
+  var c2b = f2b();
+  expect(true, c2b is Class2);
+
+  expect(true, identical(f2a, f2b));
+}
+
+class Class3 {
+  final int field;
+
+  Class3._(this.field);
+  factory Class3(int field) = Class3._;
+}
+
+class Class4 {
+  final int? field;
+
+  Class4._([this.field]);
+  factory Class4([int? field]) = Class4._;
+}
+
+class Class5 {
+  final int field1;
+  final int? field2;
+
+  Class5._(this.field1, [this.field2]);
+  factory Class5(int field1, [int? field2]) = Class5._;
+}
+
+class Class6 {
+  final int field1;
+  final int? field2;
+  final int field3;
+
+  Class6._(this.field1, {this.field2, required this.field3});
+  factory Class6(int field1, {int? field2, required int field3}) =
+      Class6._;
+}
+
+testArgs() {
+  var f3a = Class3.new;
+  var c3a = f3a(42);
+  expect(42, c3a.field);
+  () {
+    f3a(); // error
+    f3a(42, 87); // error
+  };
+
+  dynamic f3b = Class3.new;
+  var c3b = f3b(87);
+  expect(87, c3b.field);
+  throws(() => f3b());
+  throws(() => f3b(42, 87));
+
+  var f4a = Class4.new;
+  var c4a = f4a();
+  expect(null, c4a.field);
+  var c4b = f4a(42);
+  expect(42, c4b.field);
+  () {
+    f4a(42, 87); // error
+  };
+  dynamic f4b = Class4.new;
+  throws(() => f4b(42, 87));
+
+
+  var f5a = Class5.new;
+  var c5a = f5a(42);
+  expect(42, c5a.field1);
+  expect(null, c5a.field2);
+  var c5b = f5a(87, 42);
+  expect(87, c5b.field1);
+  expect(42, c5b.field2);
+  () {
+    f5a(); // error
+    f5a(42, 87, 123); // error
+  };
+  dynamic f5b = Class5.new;
+  throws(() => f5b());
+  throws(() => f5b(42, 87, 123));
+
+  var f6a = Class6.new;
+  var c6a = f6a(42, field3: 87);
+  expect(42, c6a.field1);
+  expect(null, c6a.field2);
+  expect(87, c6a.field3);
+  () {
+    f6a(); // error
+    f6a(42); // error
+    f6a(42, 87); // error
+    f6a(field1: 87, field2: 87); // error
+  };
+
+  var c6b = f6a(42, field2: 123, field3: 87);
+  expect(42, c6b.field1);
+  expect(123, c6b.field2);
+  expect(87, c6b.field3);
+
+  var c6c = f6a(87, field3: 42, field2: 123);
+  expect(87, c6c.field1);
+  expect(123, c6c.field2);
+  expect(42, c6c.field3);
+
+  dynamic f6b = Class6.new;
+  throws(() => f6b());
+  throws(() => f6b(42), inSoundModeOnly: true);
+  throws(() => f6b(42, 87), inSoundModeOnly: true);
+  throws(() => f6b(field1: 87, field2: 87));
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(Function() f, {bool inSoundModeOnly: false}) {
+  try {
+    f();
+  } catch (e) {
+    print('Thrown: $e');
+    return;
+  }
+  if (!inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw 'Expected exception';
+}
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
new file mode 100644
index 0000000..f5b0f3e
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.expect
@@ -0,0 +1,260 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83: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:98: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:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113: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:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127: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:128:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(field1: 87, field2: 87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class1
+    return new self::Class1::_();
+  static factory •() → self::Class1
+    let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+  static method _#new#tearOff() → self::Class1
+    return new self::Class1::_();
+}
+class Class2 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class2
+    return new self::Class2::_();
+  static factory named() → self::Class2
+    let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+  static method _#named#tearOff() → self::Class2
+    return new self::Class2::_();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _(core::int field) → self::Class3
+    : self::Class3::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class3
+    return new self::Class3::_(field);
+  static factory •(core::int field) → self::Class3
+    let dynamic #redirecting_factory = self::Class3::_ in invalid-expression;
+  static method _#new#tearOff(core::int field) → self::Class3
+    return new self::Class3::_(field);
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _([core::int? field = #C1]) → self::Class4
+    : self::Class4::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff([core::int? field = #C1]) → self::Class4
+    return new self::Class4::_(field);
+  static factory •([core::int? field = #C1]) → self::Class4
+    let dynamic #redirecting_factory = self::Class4::_ in invalid-expression;
+  static method _#new#tearOff([core::int? field = #C1]) → self::Class4
+    return new self::Class4::_(field);
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+  constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    return new self::Class5::_(field1, field2);
+  static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    let dynamic #redirecting_factory = self::Class5::_ in invalid-expression;
+  static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    return new self::Class5::_(field1, field2);
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+  constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    return new self::Class6::_(field1, field2: field2, field3: field3);
+  static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
+  static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    return new self::Class6::_(field1, field2: field2, field3: field3);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testNoArgs();
+  self::testArgs();
+}
+static method testNoArgs() → dynamic {
+  () → self::Class1 f1a = #C2;
+  self::Class1 c1a = f1a(){() → self::Class1};
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+  dynamic f1b = #C2;
+  dynamic c1b = f1b{dynamic}.call();
+  self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+  self::expect(true, core::identical(f1a, f1b));
+  () → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){() → self::Class2};
+  self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+  dynamic f2b = #C3;
+  dynamic c2b = f2b{dynamic}.call();
+  self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+  self::expect(true, core::identical(f2a, f2b));
+}
+static method testArgs() → dynamic {
+  (core::int) → self::Class3 f3a = #C4;
+  self::Class3 c3a = f3a(42){(core::int) → self::Class3};
+  self::expect(42, c3a.{self::Class3::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+    f3a(); // error
+       ^" in f3a{<inapplicable>}.();
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83: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);
+  };
+  dynamic f3b = #C4;
+  dynamic c3b = f3b{dynamic}.call(87);
+  self::expect(87, c3b{dynamic}.field);
+  self::throws(() → dynamic => f3b{dynamic}.call());
+  self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+  ([core::int?]) → self::Class4 f4a = #C5;
+  self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+  self::expect(null, c4a.{self::Class4::field}{core::int?});
+  self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+  self::expect(42, c4b.{self::Class4::field}{core::int?});
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98: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);
+  };
+  dynamic f4b = #C5;
+  self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+  (core::int, [core::int?]) → self::Class5 f5a = #C6;
+  self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+  self::expect(42, c5a.{self::Class5::field1}{core::int});
+  self::expect(null, c5a.{self::Class5::field2}{core::int?});
+  self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+  self::expect(87, c5b.{self::Class5::field1}{core::int});
+  self::expect(42, c5b.{self::Class5::field2}{core::int?});
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+    f5a(); // error
+       ^" in f5a{<inapplicable>}.();
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113: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);
+  };
+  dynamic f5b = #C6;
+  self::throws(() → dynamic => f5b{dynamic}.call());
+  self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+  (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+  self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6a.{self::Class6::field1}{core::int});
+  self::expect(null, c6a.{self::Class6::field2}{core::int?});
+  self::expect(87, c6a.{self::Class6::field3}{core::int});
+  () → Null {
+    let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(); // error
+       ^" in f6a{<inapplicable>}.();
+    let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+    f6a(42); // error
+       ^" in f6a{<inapplicable>}.(42);
+    let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127: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);
+    let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(field1: 87, field2: 87); // error
+       ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+  };
+  self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6b.{self::Class6::field1}{core::int});
+  self::expect(123, c6b.{self::Class6::field2}{core::int?});
+  self::expect(87, c6b.{self::Class6::field3}{core::int});
+  self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(87, c6c.{self::Class6::field1}{core::int});
+  self::expect(123, c6c.{self::Class6::field2}{core::int?});
+  self::expect(42, c6c.{self::Class6::field3}{core::int});
+  dynamic f6b = #C7;
+  self::throws(() → dynamic => f6b{dynamic}.call());
+  self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+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 = #C8}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = null
+  #C2 = static-tearoff self::Class1::_#new#tearOff
+  #C3 = static-tearoff self::Class2::_#named#tearOff
+  #C4 = static-tearoff self::Class3::_#new#tearOff
+  #C5 = static-tearoff self::Class4::_#new#tearOff
+  #C6 = static-tearoff self::Class5::_#new#tearOff
+  #C7 = static-tearoff self::Class6::_#new#tearOff
+  #C8 = 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
new file mode 100644
index 0000000..59fb725
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.strong.transformed.expect
@@ -0,0 +1,260 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83: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:98: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:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113: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:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127: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:128:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(field1: 87, field2: 87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class1
+    return new self::Class1::_();
+  static factory •() → self::Class1
+    let Never #redirecting_factory = self::Class1::_ in invalid-expression;
+  static method _#new#tearOff() → self::Class1
+    return new self::Class1::_();
+}
+class Class2 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class2
+    return new self::Class2::_();
+  static factory named() → self::Class2
+    let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+  static method _#named#tearOff() → self::Class2
+    return new self::Class2::_();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _(core::int field) → self::Class3
+    : self::Class3::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class3
+    return new self::Class3::_(field);
+  static factory •(core::int field) → self::Class3
+    let Never #redirecting_factory = self::Class3::_ in invalid-expression;
+  static method _#new#tearOff(core::int field) → self::Class3
+    return new self::Class3::_(field);
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _([core::int? field = #C1]) → self::Class4
+    : self::Class4::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff([core::int? field = #C1]) → self::Class4
+    return new self::Class4::_(field);
+  static factory •([core::int? field = #C1]) → self::Class4
+    let Never #redirecting_factory = self::Class4::_ in invalid-expression;
+  static method _#new#tearOff([core::int? field = #C1]) → self::Class4
+    return new self::Class4::_(field);
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+  constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    return new self::Class5::_(field1, field2);
+  static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    let Never #redirecting_factory = self::Class5::_ in invalid-expression;
+  static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    return new self::Class5::_(field1, field2);
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+  constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    return new self::Class6::_(field1, field2: field2, field3: field3);
+  static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    let Never #redirecting_factory = self::Class6::_ in invalid-expression;
+  static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    return new self::Class6::_(field1, field2: field2, field3: field3);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testNoArgs();
+  self::testArgs();
+}
+static method testNoArgs() → dynamic {
+  () → self::Class1 f1a = #C2;
+  self::Class1 c1a = f1a(){() → self::Class1};
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+  dynamic f1b = #C2;
+  dynamic c1b = f1b{dynamic}.call();
+  self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+  self::expect(true, core::identical(f1a, f1b));
+  () → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){() → self::Class2};
+  self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+  dynamic f2b = #C3;
+  dynamic c2b = f2b{dynamic}.call();
+  self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+  self::expect(true, core::identical(f2a, f2b));
+}
+static method testArgs() → dynamic {
+  (core::int) → self::Class3 f3a = #C4;
+  self::Class3 c3a = f3a(42){(core::int) → self::Class3};
+  self::expect(42, c3a.{self::Class3::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+    f3a(); // error
+       ^" in f3a{<inapplicable>}.();
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83: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);
+  };
+  dynamic f3b = #C4;
+  dynamic c3b = f3b{dynamic}.call(87);
+  self::expect(87, c3b{dynamic}.field);
+  self::throws(() → dynamic => f3b{dynamic}.call());
+  self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+  ([core::int?]) → self::Class4 f4a = #C5;
+  self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+  self::expect(null, c4a.{self::Class4::field}{core::int?});
+  self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+  self::expect(42, c4b.{self::Class4::field}{core::int?});
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98: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);
+  };
+  dynamic f4b = #C5;
+  self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+  (core::int, [core::int?]) → self::Class5 f5a = #C6;
+  self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+  self::expect(42, c5a.{self::Class5::field1}{core::int});
+  self::expect(null, c5a.{self::Class5::field2}{core::int?});
+  self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+  self::expect(87, c5b.{self::Class5::field1}{core::int});
+  self::expect(42, c5b.{self::Class5::field2}{core::int?});
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+    f5a(); // error
+       ^" in f5a{<inapplicable>}.();
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113: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);
+  };
+  dynamic f5b = #C6;
+  self::throws(() → dynamic => f5b{dynamic}.call());
+  self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+  (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+  self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6a.{self::Class6::field1}{core::int});
+  self::expect(null, c6a.{self::Class6::field2}{core::int?});
+  self::expect(87, c6a.{self::Class6::field3}{core::int});
+  () → Null {
+    let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(); // error
+       ^" in f6a{<inapplicable>}.();
+    let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+    f6a(42); // error
+       ^" in f6a{<inapplicable>}.(42);
+    let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127: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);
+    let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(field1: 87, field2: 87); // error
+       ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+  };
+  self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6b.{self::Class6::field1}{core::int});
+  self::expect(123, c6b.{self::Class6::field2}{core::int?});
+  self::expect(87, c6b.{self::Class6::field3}{core::int});
+  self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(87, c6c.{self::Class6::field1}{core::int});
+  self::expect(123, c6c.{self::Class6::field2}{core::int?});
+  self::expect(42, c6c.{self::Class6::field3}{core::int});
+  dynamic f6b = #C7;
+  self::throws(() → dynamic => f6b{dynamic}.call());
+  self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+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 = #C8}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = null
+  #C2 = static-tearoff self::Class1::_#new#tearOff
+  #C3 = static-tearoff self::Class2::_#named#tearOff
+  #C4 = static-tearoff self::Class3::_#new#tearOff
+  #C5 = static-tearoff self::Class4::_#new#tearOff
+  #C6 = static-tearoff self::Class5::_#new#tearOff
+  #C7 = static-tearoff self::Class6::_#new#tearOff
+  #C8 = 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
new file mode 100644
index 0000000..999b5d2
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline.expect
@@ -0,0 +1,45 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1 {
+  Class1._();
+  factory Class1() = Class1._;
+}
+
+class Class2 {
+  Class2._();
+  factory Class2.named() = Class2._;
+}
+
+testNoArgs() {}
+
+class Class3 {
+  final int field;
+  Class3._(this.field);
+  factory Class3(int field) = Class3._;
+}
+
+class Class4 {
+  final int? field;
+  Class4._([this.field]);
+  factory Class4([int? field]) = Class4._;
+}
+
+class Class5 {
+  final int field1;
+  final int? field2;
+  Class5._(this.field1, [this.field2]);
+  factory Class5(int field1, [int? field2]) = Class5._;
+}
+
+class Class6 {
+  final int field1;
+  final int? field2;
+  final int field3;
+  Class6._(this.field1, {this.field2, required this.field3});
+  factory Class6(int field1, {int? field2, required int field3}) = Class6._;
+}
+
+testArgs() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
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
new file mode 100644
index 0000000..edb4f68
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
@@ -0,0 +1,43 @@
+class Class1 {
+  Class1._();
+  factory Class1() = Class1._;
+}
+
+class Class2 {
+  Class2._();
+  factory Class2.named() = Class2._;
+}
+
+class Class3 {
+  Class3._(this.field);
+  factory Class3(int field) = Class3._;
+  final int field;
+}
+
+class Class4 {
+  Class4._([this.field]);
+  factory Class4([int? field]) = Class4._;
+  final int? field;
+}
+
+class Class5 {
+  Class5._(this.field1, [this.field2]);
+  factory Class5(int field1, [int? field2]) = Class5._;
+  final int? field2;
+  final int field1;
+}
+
+class Class6 {
+  Class6._(this.field1, {this.field2, required this.field3});
+  factory Class6(int field1, {int? field2, required int field3}) = Class6._;
+  final int? field2;
+  final int field1;
+  final int field3;
+}
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+testArgs() {}
+testNoArgs() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
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
new file mode 100644
index 0000000..f5b0f3e
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.expect
@@ -0,0 +1,260 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83: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:98: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:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113: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:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127: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:128:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(field1: 87, field2: 87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class1
+    return new self::Class1::_();
+  static factory •() → self::Class1
+    let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+  static method _#new#tearOff() → self::Class1
+    return new self::Class1::_();
+}
+class Class2 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class2
+    return new self::Class2::_();
+  static factory named() → self::Class2
+    let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+  static method _#named#tearOff() → self::Class2
+    return new self::Class2::_();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _(core::int field) → self::Class3
+    : self::Class3::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class3
+    return new self::Class3::_(field);
+  static factory •(core::int field) → self::Class3
+    let dynamic #redirecting_factory = self::Class3::_ in invalid-expression;
+  static method _#new#tearOff(core::int field) → self::Class3
+    return new self::Class3::_(field);
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _([core::int? field = #C1]) → self::Class4
+    : self::Class4::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff([core::int? field = #C1]) → self::Class4
+    return new self::Class4::_(field);
+  static factory •([core::int? field = #C1]) → self::Class4
+    let dynamic #redirecting_factory = self::Class4::_ in invalid-expression;
+  static method _#new#tearOff([core::int? field = #C1]) → self::Class4
+    return new self::Class4::_(field);
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+  constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    return new self::Class5::_(field1, field2);
+  static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    let dynamic #redirecting_factory = self::Class5::_ in invalid-expression;
+  static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    return new self::Class5::_(field1, field2);
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+  constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    return new self::Class6::_(field1, field2: field2, field3: field3);
+  static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
+  static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    return new self::Class6::_(field1, field2: field2, field3: field3);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testNoArgs();
+  self::testArgs();
+}
+static method testNoArgs() → dynamic {
+  () → self::Class1 f1a = #C2;
+  self::Class1 c1a = f1a(){() → self::Class1};
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+  dynamic f1b = #C2;
+  dynamic c1b = f1b{dynamic}.call();
+  self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+  self::expect(true, core::identical(f1a, f1b));
+  () → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){() → self::Class2};
+  self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+  dynamic f2b = #C3;
+  dynamic c2b = f2b{dynamic}.call();
+  self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+  self::expect(true, core::identical(f2a, f2b));
+}
+static method testArgs() → dynamic {
+  (core::int) → self::Class3 f3a = #C4;
+  self::Class3 c3a = f3a(42){(core::int) → self::Class3};
+  self::expect(42, c3a.{self::Class3::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+    f3a(); // error
+       ^" in f3a{<inapplicable>}.();
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83: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);
+  };
+  dynamic f3b = #C4;
+  dynamic c3b = f3b{dynamic}.call(87);
+  self::expect(87, c3b{dynamic}.field);
+  self::throws(() → dynamic => f3b{dynamic}.call());
+  self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+  ([core::int?]) → self::Class4 f4a = #C5;
+  self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+  self::expect(null, c4a.{self::Class4::field}{core::int?});
+  self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+  self::expect(42, c4b.{self::Class4::field}{core::int?});
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98: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);
+  };
+  dynamic f4b = #C5;
+  self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+  (core::int, [core::int?]) → self::Class5 f5a = #C6;
+  self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+  self::expect(42, c5a.{self::Class5::field1}{core::int});
+  self::expect(null, c5a.{self::Class5::field2}{core::int?});
+  self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+  self::expect(87, c5b.{self::Class5::field1}{core::int});
+  self::expect(42, c5b.{self::Class5::field2}{core::int?});
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+    f5a(); // error
+       ^" in f5a{<inapplicable>}.();
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113: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);
+  };
+  dynamic f5b = #C6;
+  self::throws(() → dynamic => f5b{dynamic}.call());
+  self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+  (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+  self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6a.{self::Class6::field1}{core::int});
+  self::expect(null, c6a.{self::Class6::field2}{core::int?});
+  self::expect(87, c6a.{self::Class6::field3}{core::int});
+  () → Null {
+    let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(); // error
+       ^" in f6a{<inapplicable>}.();
+    let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+    f6a(42); // error
+       ^" in f6a{<inapplicable>}.(42);
+    let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127: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);
+    let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(field1: 87, field2: 87); // error
+       ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+  };
+  self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6b.{self::Class6::field1}{core::int});
+  self::expect(123, c6b.{self::Class6::field2}{core::int?});
+  self::expect(87, c6b.{self::Class6::field3}{core::int});
+  self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(87, c6c.{self::Class6::field1}{core::int});
+  self::expect(123, c6c.{self::Class6::field2}{core::int?});
+  self::expect(42, c6c.{self::Class6::field3}{core::int});
+  dynamic f6b = #C7;
+  self::throws(() → dynamic => f6b{dynamic}.call());
+  self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+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 = #C8}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = null
+  #C2 = static-tearoff self::Class1::_#new#tearOff
+  #C3 = static-tearoff self::Class2::_#named#tearOff
+  #C4 = static-tearoff self::Class3::_#new#tearOff
+  #C5 = static-tearoff self::Class4::_#new#tearOff
+  #C6 = static-tearoff self::Class5::_#new#tearOff
+  #C7 = static-tearoff self::Class6::_#new#tearOff
+  #C8 = 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
new file mode 100644
index 0000000..f5e4544
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.outline.expect
@@ -0,0 +1,88 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1
+    ;
+  static method _#_#tearOff() → self::Class1
+    return new self::Class1::_();
+  static factory •() → self::Class1
+    let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+  static method _#new#tearOff() → self::Class1
+    return new self::Class1::_();
+}
+class Class2 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+  constructor _() → self::Class2
+    ;
+  static method _#_#tearOff() → self::Class2
+    return new self::Class2::_();
+  static factory named() → self::Class2
+    let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+  static method _#named#tearOff() → self::Class2
+    return new self::Class2::_();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _(core::int field) → self::Class3
+    ;
+  static method _#_#tearOff(core::int field) → self::Class3
+    return new self::Class3::_(field);
+  static factory •(core::int field) → self::Class3
+    let dynamic #redirecting_factory = self::Class3::_ in invalid-expression;
+  static method _#new#tearOff(core::int field) → self::Class3
+    return new self::Class3::_(field);
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _([core::int? field]) → self::Class4
+    ;
+  static method _#_#tearOff([core::int? field]) → self::Class4
+    return new self::Class4::_(field);
+  static factory •([core::int? field]) → self::Class4
+    let dynamic #redirecting_factory = self::Class4::_ in invalid-expression;
+  static method _#new#tearOff([core::int? field]) → self::Class4
+    return new self::Class4::_(field);
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+  constructor _(core::int field1, [core::int? field2]) → self::Class5
+    ;
+  static method _#_#tearOff(core::int field1, [core::int? field2]) → self::Class5
+    return new self::Class5::_(field1, field2);
+  static factory •(core::int field1, [core::int? field2]) → self::Class5
+    let dynamic #redirecting_factory = self::Class5::_ in invalid-expression;
+  static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+    return new self::Class5::_(field1, field2);
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+  constructor _(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+    ;
+  static method _#_#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+    return new self::Class6::_(field1, field2: field2, field3: field3);
+  static factory •(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+    let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
+  static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+    return new self::Class6::_(field1, field2: field2, field3: field3);
+}
+static final field core::bool inSoundMode;
+static method main() → dynamic
+  ;
+static method testNoArgs() → dynamic
+  ;
+static method testArgs() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, {core::bool inSoundModeOnly}) → 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
new file mode 100644
index 0000000..59fb725
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart.weak.transformed.expect
@@ -0,0 +1,260 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83: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:98: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:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113: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:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127: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:128:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(field1: 87, field2: 87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class1
+    return new self::Class1::_();
+  static factory •() → self::Class1
+    let Never #redirecting_factory = self::Class1::_ in invalid-expression;
+  static method _#new#tearOff() → self::Class1
+    return new self::Class1::_();
+}
+class Class2 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class2
+    return new self::Class2::_();
+  static factory named() → self::Class2
+    let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+  static method _#named#tearOff() → self::Class2
+    return new self::Class2::_();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _(core::int field) → self::Class3
+    : self::Class3::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field) → self::Class3
+    return new self::Class3::_(field);
+  static factory •(core::int field) → self::Class3
+    let Never #redirecting_factory = self::Class3::_ in invalid-expression;
+  static method _#new#tearOff(core::int field) → self::Class3
+    return new self::Class3::_(field);
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _([core::int? field = #C1]) → self::Class4
+    : self::Class4::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff([core::int? field = #C1]) → self::Class4
+    return new self::Class4::_(field);
+  static factory •([core::int? field = #C1]) → self::Class4
+    let Never #redirecting_factory = self::Class4::_ in invalid-expression;
+  static method _#new#tearOff([core::int? field = #C1]) → self::Class4
+    return new self::Class4::_(field);
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+  constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    return new self::Class5::_(field1, field2);
+  static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    let Never #redirecting_factory = self::Class5::_ in invalid-expression;
+  static method _#new#tearOff(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    return new self::Class5::_(field1, field2);
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+  constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+    ;
+  static method _#_#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    return new self::Class6::_(field1, field2: field2, field3: field3);
+  static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    let Never #redirecting_factory = self::Class6::_ in invalid-expression;
+  static method _#new#tearOff(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    return new self::Class6::_(field1, field2: field2, field3: field3);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testNoArgs();
+  self::testArgs();
+}
+static method testNoArgs() → dynamic {
+  () → self::Class1 f1a = #C2;
+  self::Class1 c1a = f1a(){() → self::Class1};
+  self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+  dynamic f1b = #C2;
+  dynamic c1b = f1b{dynamic}.call();
+  self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+  self::expect(true, core::identical(f1a, f1b));
+  () → self::Class2 f2a = #C3;
+  self::Class2 c2a = f2a(){() → self::Class2};
+  self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+  dynamic f2b = #C3;
+  dynamic c2b = f2b{dynamic}.call();
+  self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+  self::expect(true, core::identical(f2a, f2b));
+}
+static method testArgs() → dynamic {
+  (core::int) → self::Class3 f3a = #C4;
+  self::Class3 c3a = f3a(42){(core::int) → self::Class3};
+  self::expect(42, c3a.{self::Class3::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+    f3a(); // error
+       ^" in f3a{<inapplicable>}.();
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:83: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);
+  };
+  dynamic f3b = #C4;
+  dynamic c3b = f3b{dynamic}.call(87);
+  self::expect(87, c3b{dynamic}.field);
+  self::throws(() → dynamic => f3b{dynamic}.call());
+  self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+  ([core::int?]) → self::Class4 f4a = #C5;
+  self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+  self::expect(null, c4a.{self::Class4::field}{core::int?});
+  self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+  self::expect(42, c4b.{self::Class4::field}{core::int?});
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:98: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);
+  };
+  dynamic f4b = #C5;
+  self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+  (core::int, [core::int?]) → self::Class5 f5a = #C6;
+  self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+  self::expect(42, c5a.{self::Class5::field1}{core::int});
+  self::expect(null, c5a.{self::Class5::field2}{core::int?});
+  self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+  self::expect(87, c5b.{self::Class5::field1}{core::int});
+  self::expect(42, c5b.{self::Class5::field2}{core::int?});
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+    f5a(); // error
+       ^" in f5a{<inapplicable>}.();
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:113: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);
+  };
+  dynamic f5b = #C6;
+  self::throws(() → dynamic => f5b{dynamic}.call());
+  self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+  (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+  self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6a.{self::Class6::field1}{core::int});
+  self::expect(null, c6a.{self::Class6::field2}{core::int?});
+  self::expect(87, c6a.{self::Class6::field3}{core::int});
+  () → Null {
+    let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(); // error
+       ^" in f6a{<inapplicable>}.();
+    let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+    f6a(42); // error
+       ^" in f6a{<inapplicable>}.(42);
+    let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:127: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);
+    let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(field1: 87, field2: 87); // error
+       ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+  };
+  self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6b.{self::Class6::field1}{core::int});
+  self::expect(123, c6b.{self::Class6::field2}{core::int?});
+  self::expect(87, c6b.{self::Class6::field3}{core::int});
+  self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(87, c6c.{self::Class6::field1}{core::int});
+  self::expect(123, c6c.{self::Class6::field2}{core::int?});
+  self::expect(42, c6c.{self::Class6::field3}{core::int});
+  dynamic f6b = #C7;
+  self::throws(() → dynamic => f6b{dynamic}.call());
+  self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+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 = #C8}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = null
+  #C2 = static-tearoff self::Class1::_#new#tearOff
+  #C3 = static-tearoff self::Class2::_#named#tearOff
+  #C4 = static-tearoff self::Class3::_#new#tearOff
+  #C5 = static-tearoff self::Class4::_#new#tearOff
+  #C6 = static-tearoff self::Class5::_#new#tearOff
+  #C7 = static-tearoff self::Class6::_#new#tearOff
+  #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart
new file mode 100644
index 0000000..ef380c5
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart
@@ -0,0 +1,75 @@
+// 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.
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+  print('inSoundMode: $inSoundMode');
+  testDefaultValues();
+}
+
+class Class1 {
+  final int field;
+
+  Class1._([this.field = 42]);
+  factory Class1([int field]) = Class1._;
+}
+
+class Class2 {
+  final int field;
+
+  Class2._({this.field: 42});
+  factory Class2({int field}) = Class2._;
+}
+
+void testDefaultValues() {
+  var f1a = Class1.new;
+  var c1a = f1a();
+  expect(42, c1a.field);
+  var c1b = f1a(87);
+  expect(87, c1b.field);
+  () {
+    f1a(42, 87); // error
+  };
+
+  dynamic f1b = Class1.new;
+  var c1c = f1b();
+  expect(42, c1c.field);
+  var c1d = f1b(87);
+  expect(87, c1d.field);
+  throws(() => f1b(42, 87));
+
+  var f2a = Class2.new;
+  var c2a = f2a();
+  expect(42, c2a.field);
+  var c2b = f2a(field: 87);
+  expect(87, c2b.field);
+  () {
+    f2a(87); // error
+  };
+
+  dynamic f2b = Class2.new;
+  var c2c = f2b();
+  expect(42, c2c.field);
+  var c2d = f2b(field: 87);
+  expect(87, c2d.field);
+  throws(() => f2b(87));
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(Function() f, {bool inSoundModeOnly: false}) {
+  try {
+    f();
+  } catch (e) {
+    print('Thrown: $e');
+    return;
+  }
+  if (!inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw 'Expected exception';
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.expect
new file mode 100644
index 0000000..873e7a9
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.expect
@@ -0,0 +1,109 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f1a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _([core::int field = #C1]) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+  static factory •([core::int field = #C2]) → self::Class1
+    let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+  static method _#new#tearOff([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+}
+class Class2 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+  constructor _({core::int field = #C1}) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field: field);
+  static factory •({core::int field = #C2}) → self::Class2
+    let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field: field);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+  ([core::int]) → self::Class1 f1a = #C3;
+  self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+  self::expect(42, c1a.{self::Class1::field}{core::int});
+  self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+  self::expect(87, c1b.{self::Class1::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f1a(42, 87); // error
+       ^" in f1a{<inapplicable>}.(42, 87);
+  };
+  dynamic f1b = #C3;
+  dynamic c1c = f1b{dynamic}.call();
+  self::expect(42, c1c{dynamic}.field);
+  dynamic c1d = f1b{dynamic}.call(87);
+  self::expect(87, c1d{dynamic}.field);
+  self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C4;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C4;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+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 = #C5}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = null
+  #C3 = static-tearoff self::Class1::_#new#tearOff
+  #C4 = static-tearoff self::Class2::_#new#tearOff
+  #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.transformed.expect
new file mode 100644
index 0000000..fe92fac
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.strong.transformed.expect
@@ -0,0 +1,109 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f1a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _([core::int field = #C1]) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+  static factory •([core::int field = #C2]) → self::Class1
+    let Never #redirecting_factory = self::Class1::_ in invalid-expression;
+  static method _#new#tearOff([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+}
+class Class2 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+  constructor _({core::int field = #C1}) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field: field);
+  static factory •({core::int field = #C2}) → self::Class2
+    let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field: field);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+  ([core::int]) → self::Class1 f1a = #C3;
+  self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+  self::expect(42, c1a.{self::Class1::field}{core::int});
+  self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+  self::expect(87, c1b.{self::Class1::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f1a(42, 87); // error
+       ^" in f1a{<inapplicable>}.(42, 87);
+  };
+  dynamic f1b = #C3;
+  dynamic c1c = f1b{dynamic}.call();
+  self::expect(42, c1c{dynamic}.field);
+  dynamic c1d = f1b{dynamic}.call(87);
+  self::expect(87, c1d{dynamic}.field);
+  self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C4;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C4;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+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 = #C5}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = null
+  #C3 = static-tearoff self::Class1::_#new#tearOff
+  #C4 = static-tearoff self::Class2::_#new#tearOff
+  #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline.expect
new file mode 100644
index 0000000..1194776
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline.expect
@@ -0,0 +1,18 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1 {
+  final int field;
+  Class1._([this.field = 42]);
+  factory Class1([int field]) = Class1._;
+}
+
+class Class2 {
+  final int field;
+  Class2._({this.field: 42});
+  factory Class2({int field}) = Class2._;
+}
+
+void testDefaultValues() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..c51e203
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.textual_outline_modelled.expect
@@ -0,0 +1,17 @@
+class Class1 {
+  Class1._([this.field = 42]);
+  factory Class1([int field]) = Class1._;
+  final int field;
+}
+
+class Class2 {
+  Class2._({this.field: 42});
+  factory Class2({int field}) = Class2._;
+  final int field;
+}
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
+void testDefaultValues() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.expect
new file mode 100644
index 0000000..873e7a9
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.expect
@@ -0,0 +1,109 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f1a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _([core::int field = #C1]) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+  static factory •([core::int field = #C2]) → self::Class1
+    let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+  static method _#new#tearOff([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+}
+class Class2 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+  constructor _({core::int field = #C1}) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field: field);
+  static factory •({core::int field = #C2}) → self::Class2
+    let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field: field);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+  ([core::int]) → self::Class1 f1a = #C3;
+  self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+  self::expect(42, c1a.{self::Class1::field}{core::int});
+  self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+  self::expect(87, c1b.{self::Class1::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f1a(42, 87); // error
+       ^" in f1a{<inapplicable>}.(42, 87);
+  };
+  dynamic f1b = #C3;
+  dynamic c1c = f1b{dynamic}.call();
+  self::expect(42, c1c{dynamic}.field);
+  dynamic c1d = f1b{dynamic}.call(87);
+  self::expect(87, c1d{dynamic}.field);
+  self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C4;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C4;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+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 = #C5}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = null
+  #C3 = static-tearoff self::Class1::_#new#tearOff
+  #C4 = static-tearoff self::Class2::_#new#tearOff
+  #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.outline.expect
new file mode 100644
index 0000000..e6fbbd5
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.outline.expect
@@ -0,0 +1,37 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _([core::int field]) → self::Class1
+    ;
+  static method _#_#tearOff([core::int field]) → self::Class1
+    return new self::Class1::_(field);
+  static factory •([core::int field]) → self::Class1
+    let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+  static method _#new#tearOff([core::int field]) → self::Class1
+    return new self::Class1::_(field);
+}
+class Class2 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+  constructor _({core::int field}) → self::Class2
+    ;
+  static method _#_#tearOff({core::int field}) → self::Class2
+    return new self::Class2::_(field: field);
+  static factory •({core::int field}) → self::Class2
+    let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+  static method _#new#tearOff({core::int field}) → self::Class2
+    return new self::Class2::_(field: field);
+}
+static final field core::bool inSoundMode;
+static method main() → dynamic
+  ;
+static method testDefaultValues() → void
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, {core::bool inSoundModeOnly}) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.transformed.expect
new file mode 100644
index 0000000..fe92fac
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart.weak.transformed.expect
@@ -0,0 +1,109 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f1a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//     f2a(87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _([core::int field = #C1]) → self::Class1
+    : self::Class1::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+  static factory •([core::int field = #C2]) → self::Class1
+    let Never #redirecting_factory = self::Class1::_ in invalid-expression;
+  static method _#new#tearOff([core::int field = #C1]) → self::Class1
+    return new self::Class1::_(field);
+}
+class Class2 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::•]/*isLegacy*/;
+  constructor _({core::int field = #C1}) → self::Class2
+    : self::Class2::field = field, super core::Object::•()
+    ;
+  static method _#_#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field: field);
+  static factory •({core::int field = #C2}) → self::Class2
+    let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+  static method _#new#tearOff({core::int field = #C1}) → self::Class2
+    return new self::Class2::_(field: field);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  core::print("inSoundMode: ${self::inSoundMode}");
+  self::testDefaultValues();
+}
+static method testDefaultValues() → void {
+  ([core::int]) → self::Class1 f1a = #C3;
+  self::Class1 c1a = f1a(){([core::int]) → self::Class1};
+  self::expect(42, c1a.{self::Class1::field}{core::int});
+  self::Class1 c1b = f1a(87){([core::int]) → self::Class1};
+  self::expect(87, c1b.{self::Class1::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:33:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f1a(42, 87); // error
+       ^" in f1a{<inapplicable>}.(42, 87);
+  };
+  dynamic f1b = #C3;
+  dynamic c1c = f1b{dynamic}.call();
+  self::expect(42, c1c{dynamic}.field);
+  dynamic c1d = f1b{dynamic}.call(87);
+  self::expect(87, c1d{dynamic}.field);
+  self::throws(() → dynamic => f1b{dynamic}.call(42, 87));
+  ({field: core::int}) → self::Class2 f2a = #C4;
+  self::Class2 c2a = f2a(){({field: core::int}) → self::Class2};
+  self::expect(42, c2a.{self::Class2::field}{core::int});
+  self::Class2 c2b = f2a(field: 87){({field: core::int}) → self::Class2};
+  self::expect(87, c2b.{self::Class2::field}{core::int});
+  () → Null {
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/redirecting_factory_tear_off_default_values.dart:49:8: Error: Too many positional arguments: 0 allowed, but 1 found.
+Try removing the extra positional arguments.
+    f2a(87); // error
+       ^" in f2a{<inapplicable>}.(87);
+  };
+  dynamic f2b = #C4;
+  dynamic c2c = f2b{dynamic}.call();
+  self::expect(42, c2c{dynamic}.field);
+  dynamic c2d = f2b{dynamic}.call(field: 87);
+  self::expect(87, c2d{dynamic}.field);
+  self::throws(() → dynamic => f2b{dynamic}.call(87));
+}
+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 = #C5}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = null
+  #C3 = static-tearoff self::Class1::_#new#tearOff
+  #C4 = static-tearoff self::Class2::_#new#tearOff
+  #C5 = false
+}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart
new file mode 100644
index 0000000..9a68b87
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart
@@ -0,0 +1,22 @@
+// 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 {
+  final int field;
+
+  A([this.field = 42]);
+
+  factory A.redirect([int field = 87]) = A;
+}
+
+main() {
+  expect(42, new A().field);
+  expect(123, new A(123).field);
+  expect(42, new A.redirect().field);
+  expect(123, new A.redirect(123).field);
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline.expect b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline.expect
new file mode 100644
index 0000000..6351dd7
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+class A {
+  final int field;
+  A([this.field = 42]);
+  factory A.redirect([int field = 87]) = A;
+}
+
+main() {}
+expect(expected, actual) {}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..23adf6f
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.textual_outline_modelled.expect
@@ -0,0 +1,8 @@
+class A {
+  A([this.field = 42]);
+  factory A.redirect([int field = 87]) = A;
+  final int field;
+}
+
+expect(expected, actual) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.expect b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.expect
new file mode 100644
index 0000000..1e7a7cc4
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.expect
@@ -0,0 +1,35 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/redirecting_factory_default_value.dart:10:35: Error: Can't have a default value here because any default values of 'A' would be used instead.
+// Try removing the default value.
+//   factory A.redirect([int field = 87]) = A;
+//                                   ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::A::redirect]/*isLegacy*/;
+  constructor •([core::int field = #C1]) → self::A
+    : self::A::field = field, super core::Object::•()
+    ;
+  static factory redirect([core::int field]) → self::A
+    let dynamic #redirecting_factory = self::A::• in invalid-expression;
+}
+static method main() → dynamic {
+  self::expect(42, new self::A::•().{self::A::field}{core::int});
+  self::expect(123, new self::A::•(123).{self::A::field}{core::int});
+  self::expect(42, new self::A::•().{self::A::field}{core::int});
+  self::expect(123, new self::A::•(123).{self::A::field}{core::int});
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = 42
+}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.outline.expect b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.outline.expect
new file mode 100644
index 0000000..352e5d1
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.outline.expect
@@ -0,0 +1,16 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::A::redirect]/*isLegacy*/;
+  constructor •([core::int field]) → self::A
+    ;
+  static factory redirect([core::int field]) → self::A
+    let dynamic #redirecting_factory = self::A::• in invalid-expression;
+}
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.transformed.expect b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.transformed.expect
new file mode 100644
index 0000000..6b1dd68
--- /dev/null
+++ b/pkg/front_end/testcases/general/redirecting_factory_default_value.dart.weak.transformed.expect
@@ -0,0 +1,35 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/redirecting_factory_default_value.dart:10:35: Error: Can't have a default value here because any default values of 'A' would be used instead.
+// Try removing the default value.
+//   factory A.redirect([int field = 87]) = A;
+//                                   ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::A::redirect]/*isLegacy*/;
+  constructor •([core::int field = #C1]) → self::A
+    : self::A::field = field, super core::Object::•()
+    ;
+  static factory redirect([core::int field]) → self::A
+    let Never #redirecting_factory = self::A::• in invalid-expression;
+}
+static method main() → dynamic {
+  self::expect(42, new self::A::•().{self::A::field}{core::int});
+  self::expect(123, new self::A::•(123).{self::A::field}{core::int});
+  self::expect(42, new self::A::•().{self::A::field}{core::int});
+  self::expect(123, new self::A::•(123).{self::A::field}{core::int});
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = 42
+}
diff --git a/pkg/front_end/testcases/general/redirecting_factory_metadata.dart b/pkg/front_end/testcases/general/redirecting_factory_metadata.dart
index da569e7..d25c571 100644
--- a/pkg/front_end/testcases/general/redirecting_factory_metadata.dart
+++ b/pkg/front_end/testcases/general/redirecting_factory_metadata.dart
@@ -1,7 +1,9 @@
 // Copyright (c) 2018, 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.
+
 // @dart=2.9
+
 // This test checks that annotations on redirecting factories and their formals
 // aren't skipped by the compiler and are observable in its output.
 
diff --git a/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.weak.outline.expect b/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.weak.outline.expect
index 31008cf..a83d25d 100644
--- a/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/general/redirecting_factory_metadata.dart.weak.outline.expect
@@ -28,5 +28,5 @@
 
 
 Extra constant evaluation status:
-Evaluated: StaticGet @ org-dartlang-testcase:///redirecting_factory_metadata.dart:13:4 -> IntConstant(2)
+Evaluated: StaticGet @ org-dartlang-testcase:///redirecting_factory_metadata.dart:15:4 -> IntConstant(2)
 Extra constant evaluation: evaluated: 5, effectively constant: 1
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 81314ea..2fdf4fb 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -6,16 +6,8 @@
 # the round trip for Kernel textual serialization where the initial binary
 # Kernel files are produced by compiling Dart code via Fasta.
 
-constructor_tearoffs/abstract_class_constructor_tear_off: TextSerializationFailure
-constructor_tearoffs/generic_tearoff_with_context: TextSerializationFailure
-constructor_tearoffs/generic_tearoff_without_context: TextSerializationFailure
-constructor_tearoffs/instantiation: TextSerializationFailure
-constructor_tearoffs/nongeneric_tearoff_with_context: TextSerializationFailure
-constructor_tearoffs/nongeneric_tearoff_without_context: TextSerializationFailure
-constructor_tearoffs/redirecting_constructors: TextSerializationFailure
-constructor_tearoffs/redirecting_factory_tear_off: TextSerializationFailure
-constructor_tearoffs/typedef_tearoffs: TextSerializationFailure
-constructor_tearoffs/unnamed_constructor: TextSerializationFailure
+constructor_tearoffs/redirecting_constructors: RuntimeError
+constructor_tearoffs/redirecting_factory_tear_off: RuntimeError
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
 extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart
index 7b2c1ef..0232a67 100644
--- a/pkg/kernel/lib/text/text_serializer.dart
+++ b/pkg/kernel/lib/text/text_serializer.dart
@@ -97,6 +97,10 @@
   String visitStaticGet(StaticGet _) => "get-static";
   String visitStaticSet(StaticSet _) => "set-static";
   String visitStaticTearOff(StaticTearOff _) => "tearoff-static";
+  String visitConstructorTearOff(ConstructorTearOff _) => "tearoff-constructor";
+  String visitRedirectingFactoryTearOff(RedirectingFactoryTearOff _) =>
+      "tearoff-redirecting-factory";
+  String visitTypedefTearOff(TypedefTearOff _) => "tearoff-typedef";
   String visitStaticInvocation(StaticInvocation expression) {
     return expression.isConst ? "invoke-const-static" : "invoke-static";
   }
@@ -931,6 +935,55 @@
   return new StaticTearOff.byReference(name.reference);
 }
 
+const TextSerializer<ConstructorTearOff> constructorTearOffSerializer =
+    const Wrapped(unwrapConstructorTearOff, wrapConstructorTearOff,
+        canonicalNameSerializer);
+
+CanonicalName unwrapConstructorTearOff(ConstructorTearOff expression) {
+  return expression.targetReference.canonicalName!;
+}
+
+ConstructorTearOff wrapConstructorTearOff(CanonicalName name) {
+  return new ConstructorTearOff.byReference(name.reference);
+}
+
+const TextSerializer<RedirectingFactoryTearOff>
+    redirectingFactoryTearOffSerializer = const Wrapped(
+        unwrapRedirectingFactoryTearOff,
+        wrapRedirectingFactoryTearOff,
+        canonicalNameSerializer);
+
+CanonicalName unwrapRedirectingFactoryTearOff(
+    RedirectingFactoryTearOff expression) {
+  return expression.targetReference.canonicalName!;
+}
+
+RedirectingFactoryTearOff wrapRedirectingFactoryTearOff(CanonicalName name) {
+  return new RedirectingFactoryTearOff.byReference(name.reference);
+}
+
+final TextSerializer<TypedefTearOff> typedefTearOffSerializer = new Wrapped<
+        Tuple2<List<TypeParameter>, Tuple2<Expression, List<DartType>>>,
+        TypedefTearOff>(
+    unwrapTypedefTearOff,
+    wrapTypedefTearOff,
+    Bind(
+        typeParametersSerializer,
+        Tuple2Serializer(
+            expressionSerializer, ListSerializer(dartTypeSerializer))));
+
+Tuple2<List<TypeParameter>, Tuple2<Expression, List<DartType>>>
+    unwrapTypedefTearOff(TypedefTearOff node) {
+  return new Tuple2(
+      node.typeParameters, new Tuple2(node.expression, node.typeArguments));
+}
+
+TypedefTearOff wrapTypedefTearOff(
+    Tuple2<List<TypeParameter>, Tuple2<Expression, List<DartType>>> tuple) {
+  return new TypedefTearOff(
+      tuple.first, tuple.second.first, tuple.second.second);
+}
+
 TextSerializer<StaticSet> staticSetSerializer = new Wrapped(
     unwrapStaticSet,
     wrapStaticSet,
@@ -2175,7 +2228,14 @@
   String visitStringConstant(StringConstant node) => "const-string";
   String visitSymbolConstant(SymbolConstant node) => "const-symbol";
   String visitStaticTearOffConstant(StaticTearOffConstant node) =>
-      "const-tearoff";
+      "const-tearoff-static";
+  String visitConstructorTearOffConstant(ConstructorTearOffConstant node) =>
+      "const-tearoff-constructor";
+  String visitRedirectingFactoryTearOffConstant(
+          RedirectingFactoryTearOffConstant node) =>
+      "const-tearoff-redirecting-factory";
+  String visitTypedefTearOffConstant(TypedefTearOffConstant node) =>
+      "const-tearoff-typedef";
   String visitTypeLiteralConstant(TypeLiteralConstant node) => "const-type";
   String visitUnevaluatedConstant(UnevaluatedConstant node) => "const-expr";
 
@@ -2221,11 +2281,11 @@
     Wrapped<void, NullConstant>((w) => null, (u) => NullConstant(), Nothing());
 
 TextSerializer<InstantiationConstant> instantiationConstantSerializer =
-    Wrapped<Tuple2<TearOffConstant, List<DartType>>, InstantiationConstant>(
+    Wrapped<Tuple2<Constant, List<DartType>>, InstantiationConstant>(
         (w) => Tuple2(w.tearOffConstant, w.types),
-        (u) => InstantiationConstant(u.first, u.second),
+        (u) => InstantiationConstant(u.first as TearOffConstant, u.second),
         Tuple2Serializer(
-            tearOffConstantSerializer, ListSerializer(dartTypeSerializer)));
+            constantSerializer, ListSerializer(dartTypeSerializer)));
 
 TextSerializer<SetConstant> setConstantSerializer =
     Wrapped<Tuple2<DartType, List<Constant>>, SetConstant>(
@@ -2244,12 +2304,48 @@
         (u) => SymbolConstant(u.first, u.second?.reference),
         Tuple2Serializer(DartString(), Optional(CanonicalNameSerializer())));
 
-TextSerializer<StaticTearOffConstant> tearOffConstantSerializer =
+TextSerializer<StaticTearOffConstant> staticTearOffConstantSerializer =
     Wrapped<CanonicalName, StaticTearOffConstant>(
         (w) => w.targetReference.canonicalName!,
         (u) => StaticTearOffConstant.byReference(u.reference),
         CanonicalNameSerializer());
 
+TextSerializer<ConstructorTearOffConstant>
+    constructorTearOffConstantSerializer =
+    Wrapped<CanonicalName, ConstructorTearOffConstant>(
+        (w) => w.targetReference.canonicalName!,
+        (u) => ConstructorTearOffConstant.byReference(u.reference),
+        CanonicalNameSerializer());
+
+TextSerializer<RedirectingFactoryTearOffConstant>
+    redirectingFactoryTearOffConstantSerializer =
+    Wrapped<CanonicalName, RedirectingFactoryTearOffConstant>(
+        (w) => w.targetReference.canonicalName!,
+        (u) => RedirectingFactoryTearOffConstant.byReference(u.reference),
+        CanonicalNameSerializer());
+
+final TextSerializer<TypedefTearOffConstant> typedefTearOffConstantSerializer =
+    new Wrapped<Tuple2<List<TypeParameter>, Tuple2<Constant, List<DartType>>>,
+            TypedefTearOffConstant>(
+        unwrapTypedefTearOffConstant,
+        wrapTypedefTearOffConstant,
+        Bind(
+            typeParametersSerializer,
+            Tuple2Serializer(
+                constantSerializer, ListSerializer(dartTypeSerializer))));
+
+Tuple2<List<TypeParameter>, Tuple2<Constant, List<DartType>>>
+    unwrapTypedefTearOffConstant(TypedefTearOffConstant node) {
+  return new Tuple2(
+      node.parameters, new Tuple2(node.tearOffConstant, node.types));
+}
+
+TypedefTearOffConstant wrapTypedefTearOffConstant(
+    Tuple2<List<TypeParameter>, Tuple2<Constant, List<DartType>>> tuple) {
+  return new TypedefTearOffConstant(
+      tuple.first, tuple.second.first as TearOffConstant, tuple.second.second);
+}
+
 TextSerializer<TypeLiteralConstant> typeLiteralConstantSerializer =
     Wrapped<DartType, TypeLiteralConstant>(
         (w) => w.type, (u) => TypeLiteralConstant(u), dartTypeSerializer);
@@ -2547,7 +2643,10 @@
     "set-var": variableSetSerializer,
     "get-static": staticGetSerializer,
     "set-static": staticSetSerializer,
-    "tearoff-static": staticGetSerializer,
+    "tearoff-static": staticTearOffSerializer,
+    "tearoff-constructor": constructorTearOffSerializer,
+    "tearoff-redirecting-factory": redirectingFactoryTearOffSerializer,
+    "tearoff-typedef": typedefTearOffSerializer,
     "invoke-static": staticInvocationSerializer,
     "invoke-const-static": constStaticInvocationSerializer,
     "invoke-constructor": constructorInvocationSerializer,
@@ -2624,7 +2723,11 @@
     "const-set": setConstantSerializer,
     "const-string": stringConstantSerializer,
     "const-symbol": symbolConstantSerializer,
-    "const-tearoff": tearOffConstantSerializer,
+    "const-tearoff-static": staticTearOffConstantSerializer,
+    "const-tearoff-constructor": constructorTearOffConstantSerializer,
+    "const-tearoff-redirecting-factory":
+        redirectingFactoryTearOffConstantSerializer,
+    "const-tearoff-typedef": typedefTearOffConstantSerializer,
     "const-type": typeLiteralConstantSerializer,
     "const-expr": unevaluatedConstantSerializer,
     "const-object": instanceConstantSerializer,
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 4439705..e598523 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -136,9 +136,11 @@
 }
 
 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;
 
   FreshTypeParameters(
@@ -175,6 +177,8 @@
 
   static const Substitution empty = _NullSubstitution.instance;
 
+  bool get isEmpty => identical(this, empty);
+
   /// Substitutes each parameter to the type it maps to in [map].
   static Substitution fromMap(Map<TypeParameter, DartType> map) {
     if (map.isEmpty) return _NullSubstitution.instance;
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index 15a52eb..16d4c30 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -828,10 +828,13 @@
   visitTypeParameterType(TypeParameterType node) {
     TypeParameter parameter = node.parameter;
     if (!typeParametersInScope.contains(parameter)) {
+      TreeNode? owner = parameter.parent is FunctionNode
+          ? parameter.parent!.parent
+          : parameter.parent;
       problem(
           currentParent,
           "Type parameter '$parameter' referenced out of"
-          " scope, parent is: '${parameter.parent}'.");
+          " scope, owner is: '${owner}'.");
     }
     if (parameter.parent is Class && !classTypeParametersAreInScope) {
       problem(
diff --git a/pkg/kernel/test/verify_test.dart b/pkg/kernel/test/verify_test.dart
index 8c1a8bf..f1418df 100644
--- a/pkg/kernel/test/verify_test.dart
+++ b/pkg/kernel/test/verify_test.dart
@@ -136,7 +136,7 @@
     },
     (Node node, Node parent) =>
         "Type parameter '$node' referenced out of scope,"
-        " parent is: '$parent'.",
+        " owner is: '$parent'.",
   );
   negative2Test(
     'Class type parameter from another class',
@@ -148,7 +148,7 @@
     },
     (Node node, Node parent) =>
         "Type parameter '$node' referenced out of scope,"
-        " parent is: '$parent'.",
+        " owner is: '$parent'.",
   );
   negative2Test(
     'Class type parameter in static method',
@@ -208,7 +208,7 @@
     },
     (Node node, Node parent) =>
         "Type parameter '$node' referenced out of scope,"
-        " parent is: '$parent'.",
+        " owner is: '${(parent as TreeNode).parent}'.",
   );
   negative1Test(
     'Interface type arity too low',
diff --git a/pkg/nnbd_migration/lib/src/fix_builder.dart b/pkg/nnbd_migration/lib/src/fix_builder.dart
index 3e08d2f..8a70226 100644
--- a/pkg/nnbd_migration/lib/src/fix_builder.dart
+++ b/pkg/nnbd_migration/lib/src/fix_builder.dart
@@ -557,7 +557,7 @@
 
   @override
   void setCompoundAssignmentExpressionTypes(CompoundAssignmentExpression node) {
-    assert(_assignmentLikeExpressionHandlers[node as Expression] == null);
+    assert(_assignmentLikeExpressionHandlers[node] == null);
     if (node is AssignmentExpression) {
       var handler = _AssignmentExpressionHandler(node);
       _assignmentLikeExpressionHandlers[node] = handler;
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index d307442..cb269c4 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -115,8 +115,6 @@
   ThreadInterrupter::Cleanup();
   SampleBlockCleanupVisitor visitor;
   Isolate::VisitIsolates(&visitor);
-  delete sample_block_buffer_;
-  sample_block_buffer_ = nullptr;
   initialized_ = false;
 }
 
diff --git a/tools/VERSION b/tools/VERSION
index 5b933e1..8119d92 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 339
+PRERELEASE 340
 PRERELEASE_PATCH 0
\ No newline at end of file