Version 2.14.0-336.0.dev

Merge commit 'f638d06292ae6f34ee537638b114fe893db3719f' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index ae54a38..7fc3b9f 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -860,14 +860,13 @@
   /// used by the generated source, but not imported.
   String? getTypeSource(DartType type, Set<Source> librariesToImport,
       {StringBuffer? parametersBuffer}) {
-    var aliasElement = type.aliasElement;
-    var aliasArguments = type.aliasArguments;
-    if (aliasElement != null && aliasArguments != null) {
+    var alias = type.alias;
+    if (alias != null) {
       return _getTypeCodeElementArguments(
         librariesToImport: librariesToImport,
-        element: aliasElement,
+        element: alias.element,
         isNullable: type.nullabilitySuffix == NullabilitySuffix.question,
-        typeArguments: aliasArguments,
+        typeArguments: alias.typeArguments,
       );
     }
 
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 73619d3..337ad88 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,4 +1,4 @@
-## 2.1.0
+## 2.1.0-dev
 * Changed `AnalysisResult.path` to be non-nullable.
 * Changed `ParsedLibraryResult.units` to be non-nullable.
 * Changed `ResolvedLibraryResult.element` to be non-nullable.
@@ -11,6 +11,9 @@
   `content` and `unit` were `null`, when the result actually had only errors.
   Now it produces either `ResolvedUnitResult`, or `ErrorsResult`, or
   some other results that might be added in the future.
+* Added `DartType.alias` with information about instantiated type alias.
+  The type alias element and arguments are present or absent together.
+* Deprecated `DartType.aliasElement` and `DartType.aliasArguments`.
 
 ## 2.0.0
 * Removed deprecated `Scope.lookup2()`.
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index 44efa9f..5e9079a 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -28,12 +28,19 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class DartType {
+  /// If this type is an instantiation of a type alias, information about
+  /// the alias element, and the type arguments.
+  /// Otherwise return `null`.
+  InstantiatedTypeAliasElement? get alias;
+
   /// If this type is an instantiation of a type alias, return the type
   /// arguments used for the instantiation. Otherwise return `null`.
+  @Deprecated('Use alias instead')
   List<DartType>? get aliasArguments;
 
   /// If this type is an instantiation of a type alias, return it.
   /// Otherwise return `null`.
+  @Deprecated('Use alias instead')
   TypeAliasElement? get aliasElement;
 
   /// Return the name of this type as it should appear when presented to users
@@ -245,6 +252,17 @@
   FunctionType instantiate(List<DartType> argumentTypes);
 }
 
+/// Information about an instantiated [TypeAliasElement] and the type
+/// arguments with which it is instantiated.
+abstract class InstantiatedTypeAliasElement {
+  /// The alias element that is instantiated to produce a [DartType].
+  TypeAliasElement get element;
+
+  /// The type arguments with which the [element] was instantiated.
+  /// This list will be empty if the [element] is not generic.
+  List<DartType> get typeArguments;
+}
+
 /// The type introduced by either a class or an interface, or a reference to
 /// such a type.
 ///
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 4c232e6..a1800cd 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -5480,23 +5480,29 @@
         parameters: type.parameters,
         returnType: type.returnType,
         nullabilitySuffix: resultNullability,
-        aliasElement: this,
-        aliasArguments: typeArguments,
+        alias: InstantiatedTypeAliasElementImpl(
+          element: this,
+          typeArguments: typeArguments,
+        ),
       );
     } else if (type is InterfaceType) {
       return InterfaceTypeImpl(
         element: type.element,
         typeArguments: type.typeArguments,
         nullabilitySuffix: resultNullability,
-        aliasElement: this,
-        aliasArguments: typeArguments,
+        alias: InstantiatedTypeAliasElementImpl(
+          element: this,
+          typeArguments: typeArguments,
+        ),
       );
     } else if (type is TypeParameterType) {
       return TypeParameterTypeImpl(
         element: type.element,
         nullabilitySuffix: resultNullability,
-        aliasElement: this,
-        aliasArguments: typeArguments,
+        alias: InstantiatedTypeAliasElementImpl(
+          element: this,
+          typeArguments: typeArguments,
+        ),
       );
     } else {
       return (type as TypeImpl).withNullability(resultNullability);
diff --git a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
index b05ab3d..f4077d4 100644
--- a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
@@ -583,7 +583,7 @@
           if (typeElement != null && typeElement.hasOptionalTypeArgs) {
             return;
           }
-          var typeAliasElement = type.aliasElement;
+          var typeAliasElement = type.alias?.element;
           if (typeAliasElement != null &&
               typeAliasElement.hasOptionalTypeArgs) {
             return;
diff --git a/pkg/analyzer/lib/src/dart/element/replace_top_bottom_visitor.dart b/pkg/analyzer/lib/src/dart/element/replace_top_bottom_visitor.dart
index 5709733..2db9a85 100644
--- a/pkg/analyzer/lib/src/dart/element/replace_top_bottom_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/element/replace_top_bottom_visitor.dart
@@ -53,8 +53,9 @@
       }
     }
 
-    if (type.aliasElement != null) {
-      return _typeAliasInstantiation(type, variance);
+    var alias = type.alias;
+    if (alias != null) {
+      return _instantiatedTypeAlias(type, alias, variance);
     } else if (type is InterfaceType) {
       return _interfaceType(type, variance);
     } else if (type is FunctionType) {
@@ -83,6 +84,34 @@
     );
   }
 
+  DartType _instantiatedTypeAlias(
+    DartType type,
+    InstantiatedTypeAliasElement alias,
+    Variance variance,
+  ) {
+    var aliasElement = alias.element;
+    var aliasArguments = alias.typeArguments;
+
+    var typeParameters = aliasElement.typeParameters;
+    assert(typeParameters.length == aliasArguments.length);
+
+    var newTypeArguments = <DartType>[];
+    for (var i = 0; i < typeParameters.length; i++) {
+      var typeParameter = typeParameters[i] as TypeParameterElementImpl;
+      newTypeArguments.add(
+        process(
+          aliasArguments[i],
+          typeParameter.variance.combine(variance),
+        ),
+      );
+    }
+
+    return aliasElement.instantiate(
+      typeArguments: newTypeArguments,
+      nullabilitySuffix: type.nullabilitySuffix,
+    );
+  }
+
   DartType _interfaceType(InterfaceType type, Variance variance) {
     var typeParameters = type.element.typeParameters;
     if (typeParameters.isEmpty) {
@@ -105,30 +134,6 @@
     );
   }
 
-  DartType _typeAliasInstantiation(DartType type, Variance variance) {
-    var aliasElement = type.aliasElement!;
-    var aliasArguments = type.aliasArguments!;
-
-    var typeParameters = aliasElement.typeParameters;
-    assert(typeParameters.length == aliasArguments.length);
-
-    var newTypeArguments = <DartType>[];
-    for (var i = 0; i < typeParameters.length; i++) {
-      var typeParameter = typeParameters[i] as TypeParameterElementImpl;
-      newTypeArguments.add(
-        process(
-          aliasArguments[i],
-          typeParameter.variance.combine(variance),
-        ),
-      );
-    }
-
-    return aliasElement.instantiate(
-      typeArguments: newTypeArguments,
-      nullabilitySuffix: type.nullabilitySuffix,
-    );
-  }
-
   /// Runs an instance of the visitor on the given [type] and returns the
   /// resulting type.  If the type contains no instances of Top or Bottom, the
   /// original type object is returned to avoid unnecessary allocation.
diff --git a/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart b/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
index c1c1a79..638ad0f 100644
--- a/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/element/replacement_visitor.dart
@@ -29,13 +29,14 @@
 
   DartType? createFunctionType({
     required FunctionType type,
-    required List<DartType>? newAliasArguments,
+    required InstantiatedTypeAliasElement? newAlias,
     required List<TypeParameterElement>? newTypeParameters,
     required List<ParameterElement>? newParameters,
     required DartType? newReturnType,
     required NullabilitySuffix? newNullability,
   }) {
-    if (newNullability == null &&
+    if (newAlias == null &&
+        newNullability == null &&
         newReturnType == null &&
         newParameters == null) {
       return null;
@@ -46,8 +47,7 @@
       parameters: newParameters ?? type.parameters,
       returnType: newReturnType ?? type.returnType,
       nullabilitySuffix: newNullability ?? type.nullabilitySuffix,
-      aliasElement: type.aliasElement,
-      aliasArguments: newAliasArguments ?? type.aliasArguments,
+      alias: newAlias ?? type.alias,
     );
   }
 
@@ -74,11 +74,11 @@
 
   DartType? createInterfaceType({
     required InterfaceType type,
-    required List<DartType>? newAliasArguments,
+    required InstantiatedTypeAliasElement? newAlias,
     required List<DartType>? newTypeArguments,
     required NullabilitySuffix? newNullability,
   }) {
-    if (newAliasArguments == null &&
+    if (newAlias == null &&
         newTypeArguments == null &&
         newNullability == null) {
       return null;
@@ -88,8 +88,7 @@
       element: type.element,
       typeArguments: newTypeArguments ?? type.typeArguments,
       nullabilitySuffix: newNullability ?? type.nullabilitySuffix,
-      aliasElement: type.aliasElement,
-      aliasArguments: newAliasArguments ?? type.aliasArguments,
+      alias: newAlias ?? type.alias,
     );
   }
 
@@ -136,8 +135,7 @@
       element: type.element,
       nullabilitySuffix: newNullability ?? type.nullabilitySuffix,
       promotedBound: newPromotedBound ?? promotedBound,
-      aliasElement: type.aliasElement,
-      aliasArguments: type.aliasArguments,
+      alias: type.alias,
     );
   }
 
@@ -152,8 +150,7 @@
     return TypeParameterTypeImpl(
       element: type.element,
       nullabilitySuffix: newNullability,
-      aliasElement: type.aliasElement,
-      aliasArguments: type.aliasArguments,
+      alias: type.alias,
     );
   }
 
@@ -215,16 +212,24 @@
 
     var newReturnType = visitType(node.returnType);
 
-    List<DartType>? newAliasArguments;
-    var aliasArguments = node.aliasArguments;
-    if (aliasArguments != null) {
+    InstantiatedTypeAliasElement? newAlias;
+    var alias = node.alias;
+    if (alias != null) {
+      List<DartType>? newArguments;
+      var aliasArguments = alias.typeArguments;
       for (var i = 0; i < aliasArguments.length; i++) {
         var substitution = aliasArguments[i].accept(this);
         if (substitution != null) {
-          newAliasArguments ??= aliasArguments.toList(growable: false);
-          newAliasArguments[i] = substitution;
+          newArguments ??= aliasArguments.toList(growable: false);
+          newArguments[i] = substitution;
         }
       }
+      if (newArguments != null) {
+        newAlias = InstantiatedTypeAliasElementImpl(
+          element: alias.element,
+          typeArguments: newArguments,
+        );
+      }
     }
 
     changeVariance();
@@ -253,7 +258,7 @@
 
     return createFunctionType(
       type: node,
-      newAliasArguments: newAliasArguments,
+      newAlias: newAlias,
       newTypeParameters: newTypeParameters,
       newParameters: newParameters,
       newReturnType: newReturnType,
@@ -351,13 +356,20 @@
   DartType? visitInterfaceType(InterfaceType type) {
     var newNullability = visitNullability(type);
 
-    var aliasElement = type.aliasElement;
-    var newAliasArguments = aliasElement != null
-        ? _typeArguments(
-            aliasElement.typeParameters,
-            type.aliasArguments,
-          )
-        : null;
+    InstantiatedTypeAliasElement? newAlias;
+    var alias = type.alias;
+    if (alias != null) {
+      var newArguments = _typeArguments(
+        alias.element.typeParameters,
+        alias.typeArguments,
+      );
+      if (newArguments != null) {
+        newAlias = InstantiatedTypeAliasElementImpl(
+          element: alias.element,
+          typeArguments: newArguments,
+        );
+      }
+    }
 
     var newTypeArguments = _typeArguments(
       type.element.typeParameters,
@@ -366,7 +378,7 @@
 
     return createInterfaceType(
       type: type,
-      newAliasArguments: newAliasArguments,
+      newAlias: newAlias,
       newTypeArguments: newTypeArguments,
       newNullability: newNullability,
     );
@@ -453,12 +465,8 @@
 
   List<DartType>? _typeArguments(
     List<TypeParameterElement> parameters,
-    List<DartType>? arguments,
+    List<DartType> arguments,
   ) {
-    if (arguments == null) {
-      return null;
-    }
-
     if (arguments.length != parameters.length) {
       return null;
     }
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index a123137..846f845 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -109,13 +109,12 @@
     required List<ParameterElement> parameters,
     required DartType returnType,
     required NullabilitySuffix nullabilitySuffix,
-    TypeAliasElement? aliasElement,
-    List<DartType>? aliasArguments,
+    InstantiatedTypeAliasElement? alias,
   })  : typeFormals = typeFormals,
         parameters = _sortNamedParameters(parameters),
         returnType = returnType,
         nullabilitySuffix = nullabilitySuffix,
-        super(null, aliasElement: aliasElement, aliasArguments: aliasArguments);
+        super(null, alias: alias);
 
   @override
   int get hashCode {
@@ -297,8 +296,7 @@
       parameters: parameters,
       returnType: returnType,
       nullabilitySuffix: nullabilitySuffix,
-      aliasElement: aliasElement,
-      aliasArguments: aliasArguments,
+      alias: alias,
     );
   }
 
@@ -610,6 +608,19 @@
   }
 }
 
+class InstantiatedTypeAliasElementImpl implements InstantiatedTypeAliasElement {
+  @override
+  final TypeAliasElement element;
+
+  @override
+  final List<DartType> typeArguments;
+
+  InstantiatedTypeAliasElementImpl({
+    required this.element,
+    required this.typeArguments,
+  });
+}
+
 /// A concrete implementation of an [InterfaceType].
 class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
   @override
@@ -631,12 +642,10 @@
     required ClassElement element,
     required this.typeArguments,
     required this.nullabilitySuffix,
-    TypeAliasElement? aliasElement,
-    List<DartType>? aliasArguments,
+    InstantiatedTypeAliasElement? alias,
   }) : super(
           element,
-          aliasElement: aliasElement,
-          aliasArguments: aliasArguments,
+          alias: alias,
         );
 
   @override
@@ -1615,19 +1624,26 @@
 /// representing the declared type of elements in the element model.
 abstract class TypeImpl implements DartType {
   @override
-  final List<DartType>? aliasArguments;
-
-  @override
-  final TypeAliasElement? aliasElement;
+  InstantiatedTypeAliasElement? alias;
 
   /// The element representing the declaration of this type, or `null` if the
   /// type has not, or cannot, be associated with an element.
   final Element? _element;
 
   /// Initialize a newly created type to be declared by the given [element].
-  TypeImpl(this._element, {this.aliasElement, this.aliasArguments})
-      : assert(aliasElement == null && aliasArguments == null ||
-            aliasElement != null && aliasArguments != null);
+  TypeImpl(this._element, {this.alias});
+
+  @Deprecated('Use alias instead')
+  @override
+  List<DartType>? get aliasArguments {
+    return alias?.typeArguments;
+  }
+
+  @Deprecated('Use alias instead')
+  @override
+  TypeAliasElement? get aliasElement {
+    return alias?.element;
+  }
 
   @deprecated
   @override
@@ -1774,12 +1790,10 @@
     required TypeParameterElement element,
     required this.nullabilitySuffix,
     this.promotedBound,
-    TypeAliasElement? aliasElement,
-    List<DartType>? aliasArguments,
+    InstantiatedTypeAliasElement? alias,
   }) : super(
           element,
-          aliasElement: aliasElement,
-          aliasArguments: aliasArguments,
+          alias: alias,
         );
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/type_algebra.dart b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
index 326f73a..9057b2c 100644
--- a/pkg/analyzer/lib/src/dart/element/type_algebra.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
@@ -444,9 +444,13 @@
 
     var returnType = type.returnType.accept(inner);
 
-    var aliasArguments = type.aliasArguments;
-    var newAliasArguments =
-        aliasArguments != null ? _mapList(aliasArguments) : null;
+    var alias = type.alias;
+    var newAlias = alias != null
+        ? InstantiatedTypeAliasElementImpl(
+            element: alias.element,
+            typeArguments: _mapList(alias.typeArguments),
+          )
+        : null;
 
     if (useCounter == before) return type;
 
@@ -455,8 +459,7 @@
       parameters: parameters,
       returnType: returnType,
       nullabilitySuffix: type.nullabilitySuffix,
-      aliasElement: type.aliasElement,
-      aliasArguments: newAliasArguments,
+      alias: newAlias,
     );
   }
 
diff --git a/pkg/analyzer/lib/src/dart/element/type_demotion.dart b/pkg/analyzer/lib/src/dart/element/type_demotion.dart
index 4b1cc1a..4839abe 100644
--- a/pkg/analyzer/lib/src/dart/element/type_demotion.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_demotion.dart
@@ -38,8 +38,7 @@
         return TypeParameterTypeImpl(
           element: type.element,
           nullabilitySuffix: newNullability ?? type.nullabilitySuffix,
-          aliasElement: type.aliasElement,
-          aliasArguments: type.aliasArguments,
+          alias: type.alias,
         );
       }
     }
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index a299c7d..711f2ab 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -628,7 +628,7 @@
             appendParameters(type.returnType);
             type.parameters.map((p) => p.type).forEach(appendParameters);
             // TODO(scheglov) https://github.com/dart-lang/sdk/issues/44218
-            type.aliasArguments?.forEach(appendParameters);
+            type.alias?.typeArguments.forEach(appendParameters);
           } else if (type is InterfaceType) {
             type.typeArguments.forEach(appendParameters);
           }
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index e11ec7f..aa4627e 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -39,6 +39,7 @@
 import 'package:analyzer/src/util/performance/operation_performance.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
 import 'package:collection/collection.dart';
+import 'package:meta/meta.dart';
 import 'package:yaml/yaml.dart';
 
 const M = 1024 * 1024 /*1 MiB*/;
@@ -109,7 +110,8 @@
   /// It is used to allow assists and fixes without resolving the same file
   /// multiple times, as we compute more than one assist, or fixes when there
   /// are more than one error on a line.
-  final Map<String, ResolvedLibraryResult> _cachedResults = {};
+  @visibleForTesting
+  final Map<String, ResolvedLibraryResult> cachedResults = {};
 
   FileResolver(
     PerformanceLog logger,
@@ -164,7 +166,7 @@
     }
 
     // Forget all results, anything is potentially affected.
-    _cachedResults.clear();
+    cachedResults.clear();
 
     // Remove this file and all files that transitively depend on it.
     var removedFiles = <FileState>[];
@@ -445,24 +447,16 @@
         }
       }
 
-      var libraryUnit = resolveLibrary(
+      var libraryResult = resolveLibrary(
         completionLine: completionLine,
         completionColumn: completionColumn,
         path: libraryFile.path,
-        completionPath: path,
+        completionPath: completionLine != null ? path : null,
         performance: performance,
       );
-      var result =
-          libraryUnit.units.firstWhereOrNull((element) => element.path == path);
-      // TODO(scheglov) Fix and remove.
-      if (result == null) {
-        throw StateError('''
-libraryFile.path: ${libraryFile.path}
-path: $path
-units: ${libraryUnit.units.map((e) => '(${e.uri} = ${e.path})').toList()}
-''');
-      }
-      return result;
+      return libraryResult.units.firstWhere(
+        (unitResult) => unitResult.path == path,
+      );
     });
   }
 
@@ -478,7 +472,7 @@
 
     performance ??= OperationPerformanceImpl('<default>');
 
-    var cachedResult = _cachedResults[path];
+    var cachedResult = cachedResults[path];
     if (cachedResult != null) {
       return cachedResult;
     }
@@ -570,7 +564,11 @@
       var libraryUnit = resolvedUnits.first;
       var result = ResolvedLibraryResultImpl(contextObjects!.analysisSession,
           path, libraryUnit.uri, libraryUnit.libraryElement, resolvedUnits);
-      _cachedResults[path] = result;
+
+      if (completionPath == null) {
+        cachedResults[path] = result;
+      }
+
       return result;
     });
   }
diff --git a/pkg/analyzer/lib/src/dart/resolver/legacy_type_asserter.dart b/pkg/analyzer/lib/src/dart/resolver/legacy_type_asserter.dart
index 94c39d7..7be20ef 100644
--- a/pkg/analyzer/lib/src/dart/resolver/legacy_type_asserter.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/legacy_type_asserter.dart
@@ -144,7 +144,7 @@
       return;
     }
 
-    type.aliasArguments?.forEach(_assertLegacyType);
+    type.alias?.typeArguments.forEach(_assertLegacyType);
 
     if (type is TypeParameterType) {
       _assertLegacyType(type.bound);
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index a1d8739..bfa745d 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -755,7 +755,7 @@
       // not report synthetic `dynamic` in place of an unresolved type.
       if ((type.element == _nullType.element ||
               (type.isDynamic && name == 'dynamic')) &&
-          type.aliasElement == null) {
+          type.alias == null) {
         _errorReporter.reportErrorForNode(
             HintCode.UNNECESSARY_QUESTION_MARK, node, [name]);
       }
@@ -1048,7 +1048,7 @@
           ...element.typeParameters.map((tp) => tp.bound),
         ];
         for (var type in signatureTypes) {
-          var aliasElement = type?.aliasElement;
+          var aliasElement = type?.alias?.element;
           if (aliasElement != null && aliasElement.hasInternal) {
             _errorReporter.reportErrorForNode(
                 HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT_INDIRECTLY,
diff --git a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
index e4a6930..55d66ce 100644
--- a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
+++ b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
@@ -210,10 +210,10 @@
 
     List<TypeParameterElement> typeParameters;
     List<DartType> typeArguments;
-    var aliasElement = type.aliasElement;
-    if (aliasElement != null) {
-      typeParameters = aliasElement.typeParameters;
-      typeArguments = type.aliasArguments!;
+    var alias = type.alias;
+    if (alias != null) {
+      typeParameters = alias.element.typeParameters;
+      typeArguments = alias.typeArguments;
     } else if (type is InterfaceType) {
       typeParameters = type.element.typeParameters;
       typeArguments = type.typeArguments;
@@ -277,8 +277,9 @@
 
     // Prepare type arguments for checking for super-bounded.
     type = _typeSystem.replaceTopAndBottom(type);
-    if (type.aliasElement != null) {
-      typeArguments = type.aliasArguments!;
+    alias = type.alias;
+    if (alias != null) {
+      typeArguments = alias.typeArguments;
     } else if (type is InterfaceType) {
       typeArguments = type.typeArguments;
     } else {
@@ -422,9 +423,9 @@
   bool _isMissingTypeArguments(AstNode node, DartType type, Element? element,
       Expression? inferenceContextNode) {
     List<DartType> typeArguments;
-    var aliasElement = type.aliasElement;
-    if (aliasElement != null) {
-      typeArguments = type.aliasArguments!;
+    var alias = type.alias;
+    if (alias != null) {
+      typeArguments = alias.typeArguments;
     } else if (type is InterfaceType) {
       typeArguments = type.typeArguments;
     } else {
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index dd65232..211a94c 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -504,6 +504,8 @@
       offset: resolutionOffset,
     );
 
+    _declareDartCoreDynamicNever();
+
     InformativeDataApplier(_elementFactory, _unitsInformativeBytes)
         .applyTo(libraryElement);
 
@@ -514,6 +516,14 @@
     return libraryElement;
   }
 
+  /// These elements are implicitly declared in `dart:core`.
+  void _declareDartCoreDynamicNever() {
+    if (_reference.name == 'dart:core') {
+      _reference.getChild('dynamic').element = DynamicElementImpl.instance;
+      _reference.getChild('Never').element = NeverElementImpl.instance;
+    }
+  }
+
   ClassElementImpl _readClassElement(
     CompilationUnitElementImpl unitElement,
     Reference unitReference,
@@ -1541,23 +1551,29 @@
           parameters: type.parameters,
           returnType: type.returnType,
           nullabilitySuffix: type.nullabilitySuffix,
-          aliasElement: aliasElement,
-          aliasArguments: aliasArguments,
+          alias: InstantiatedTypeAliasElementImpl(
+            element: aliasElement,
+            typeArguments: aliasArguments,
+          ),
         );
       } else if (type is InterfaceType) {
         return InterfaceTypeImpl(
           element: type.element,
           typeArguments: type.typeArguments,
           nullabilitySuffix: type.nullabilitySuffix,
-          aliasElement: aliasElement,
-          aliasArguments: aliasArguments,
+          alias: InstantiatedTypeAliasElementImpl(
+            element: aliasElement,
+            typeArguments: aliasArguments,
+          ),
         );
       } else if (type is TypeParameterType) {
         return TypeParameterTypeImpl(
           element: type.element,
           nullabilitySuffix: type.nullabilitySuffix,
-          aliasElement: aliasElement,
-          aliasArguments: aliasArguments,
+          alias: InstantiatedTypeAliasElementImpl(
+            element: aliasElement,
+            typeArguments: aliasArguments,
+          ),
         );
       } else if (type is VoidType) {
         // TODO(scheglov) add support for `void` aliasing
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index cb33459..35d4cce 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -707,10 +707,10 @@
   }
 
   void _writeTypeAliasElementArguments(DartType type) {
-    var aliasElement = type.aliasElement;
-    _writeElement(aliasElement);
-    if (aliasElement != null) {
-      _writeTypeList(type.aliasArguments!);
+    var alias = type.alias;
+    _writeElement(alias?.element);
+    if (alias != null) {
+      _writeTypeList(alias.typeArguments);
     }
   }
 
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index 3340f8a..12df589 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -117,10 +117,7 @@
         unitElement: linkingUnit.element,
       ).buildDeclarationElementsMacro(linkingUnit.macroNode);
     }
-    if ('$uri' == 'dart:core') {
-      localScope.declare('dynamic', reference.getChild('dynamic'));
-      localScope.declare('Never', reference.getChild('Never'));
-    }
+    _declareDartCoreDynamicNever();
   }
 
   void buildEnumChildren() {
@@ -202,6 +199,19 @@
     }
   }
 
+  /// These elements are implicitly declared in `dart:core`.
+  void _declareDartCoreDynamicNever() {
+    if (reference.name == 'dart:core') {
+      var dynamicRef = reference.getChild('dynamic');
+      dynamicRef.element = DynamicElementImpl.instance;
+      localScope.declare('dynamic', dynamicRef);
+
+      var neverRef = reference.getChild('Never');
+      neverRef.element = NeverElementImpl.instance;
+      localScope.declare('Never', neverRef);
+    }
+  }
+
   static void build(Linker linker, LinkInputLibrary inputLibrary) {
     var elementFactory = linker.elementFactory;
 
diff --git a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
index a449b97..e83e492 100644
--- a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
@@ -27,7 +27,6 @@
   ) {
     ArgumentError.checkNotNull(analysisContext, 'analysisContext');
     ArgumentError.checkNotNull(analysisSession, 'analysisSession');
-    _declareDartCoreDynamicNever();
   }
 
   Reference get dynamicRef {
@@ -182,10 +181,22 @@
   /// that the client can re-add the bundle, this time read from bytes.
   void removeBundle(Set<String> uriStrSet) {
     removeLibraries(uriStrSet);
+  }
 
-    // This is the bundle with dart:core and dart:async, based on full ASTs.
-    // To link them, the linker set the type provider. We are removing these
-    // libraries, and we should also remove the type provider.
+  /// Remove libraries with the specified URIs from the reference tree, and
+  /// any session level caches.
+  void removeLibraries(Set<String> uriStrSet) {
+    for (var uriStr in uriStrSet) {
+      _exportsOfLibrary.remove(uriStr);
+      libraryReaders.remove(uriStr);
+      rootReference.removeChild(uriStr);
+    }
+
+    analysisSession.classHierarchy.removeOfLibraries(uriStrSet);
+    analysisSession.inheritanceManager.removeOfLibraries(uriStrSet);
+
+    // If we discard `dart:core` and `dart:async`, we should also discard
+    // the type provider.
     if (uriStrSet.contains('dart:core')) {
       if (!uriStrSet.contains('dart:async')) {
         throw StateError(
@@ -200,23 +211,9 @@
         );
       }
       analysisContext.clearTypeProvider();
-      _declareDartCoreDynamicNever();
     }
   }
 
-  /// Remove libraries with the specified URIs from the reference tree, and
-  /// any session level caches.
-  void removeLibraries(Set<String> uriStrSet) {
-    for (var uriStr in uriStrSet) {
-      _exportsOfLibrary.remove(uriStr);
-      libraryReaders.remove(uriStr);
-      rootReference.removeChild(uriStr);
-    }
-
-    analysisSession.classHierarchy.removeOfLibraries(uriStrSet);
-    analysisSession.inheritanceManager.removeOfLibraries(uriStrSet);
-  }
-
   /// Set exports of the library with [uriStr], after building exports during
   /// linking, or after reading a linked bundle.
   void setExportsOfLibrary(String uriStr, List<Reference> exports) {
@@ -242,10 +239,4 @@
 
     libraryElement.createLoadLibraryFunction();
   }
-
-  void _declareDartCoreDynamicNever() {
-    var dartCoreRef = rootReference.getChild('dart:core');
-    dartCoreRef.getChild('dynamic').element = DynamicElementImpl.instance;
-    dartCoreRef.getChild('Never').element = NeverElementImpl.instance;
-  }
 }
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index d52b622..4afb0cc 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 2.0.0
+version: 2.1.0-dev
 description: This package provides a library that performs static analysis of Dart code.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
 
diff --git a/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart b/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart
index 632677a..ff5c8f9 100644
--- a/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart
+++ b/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart
@@ -2,6 +2,7 @@
 // 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:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
@@ -155,13 +156,11 @@
       nullabilitySuffix: NullabilitySuffix.none,
     );
     expect(_typeToString(input), 'int Function()');
-    expect(input.aliasElement, same(A));
-    expect(input.aliasArguments!.map(_typeToString).join(', '), 'int');
+    _assertInstantiatedAlias(input, A, 'int');
 
     var result = NullabilityEliminator.perform(typeProvider, input);
     expect(_typeToString(result), 'int* Function()*');
-    expect(result.aliasElement, same(A));
-    expect(result.aliasArguments!.map(_typeToString).join(', '), 'int*');
+    _assertInstantiatedAlias(result, A, 'int*');
   }
 
   test_functionType_typeParameters() {
@@ -278,8 +277,7 @@
 
     var result = NullabilityEliminator.perform(typeProvider, input);
     expect(_typeToString(result), 'List<int*>*');
-    expect(result.aliasElement, same(A));
-    expect(result.aliasArguments!.map(_typeToString).join(', '), 'int*');
+    _assertInstantiatedAlias(result, A, 'int*');
   }
 
   test_interfaceType_int() {
@@ -333,6 +331,13 @@
     _verifySame(typeProvider.voidType);
   }
 
+  void _assertInstantiatedAlias(
+      DartType type, Element aliasElement, String aliasArguments) {
+    var alias = type.alias!;
+    expect(alias.element, same(aliasElement));
+    expect(alias.typeArguments.map(_typeToString).join(', '), aliasArguments);
+  }
+
   String _typeToString(DartType type) {
     return type.getDisplayString(withNullability: true);
   }
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index 93122d1..0944438 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -346,6 +346,29 @@
         (fileResolver.byteStore as CiderCachedByteStore).testView!.length);
   }
 
+  test_elements_export_dartCoreDynamic() async {
+    var a_path = convertPath('/workspace/dart/test/lib/a.dart');
+    newFile(a_path, content: r'''
+export 'dart:core' show dynamic;
+''');
+
+    // Analyze so that `dart:core` is linked.
+    var a_result = await resolveFile(a_path);
+
+    // Touch `dart:core` so that its element model is discarded.
+    var dartCorePath = a_result.session.uriConverter.uriToPath(
+      Uri.parse('dart:core'),
+    )!;
+    fileResolver.changeFile(dartCorePath);
+
+    // Analyze, this will read the element model for `dart:core`.
+    // There was a bug that `root::dart:core::dynamic` had no element set.
+    await assertNoErrorsInCode(r'''
+import 'a.dart' as p;
+p.dynamic f() {}
+''');
+  }
+
   test_findReferences_class() async {
     var aPath = convertPath('/workspace/dart/test/lib/a.dart');
     newFile(aPath, content: r'''
@@ -1036,17 +1059,21 @@
     newFile(path, content: 'var a = 0;');
 
     // No resolved files yet.
-    expect(fileResolver.testView!.resolvedFiles, isEmpty);
+    var testView = fileResolver.testView!;
+    expect(testView.resolvedFiles, isEmpty);
 
     await resolveFile2(path);
     var result1 = result;
 
     // The file was resolved.
-    expect(fileResolver.testView!.resolvedFiles, [path]);
+    expect(testView.resolvedFiles, [path]);
+
+    // The result is cached.
+    expect(fileResolver.cachedResults, contains(path));
 
     // Ask again, no changes, not resolved.
     await resolveFile2(path);
-    expect(fileResolver.testView!.resolvedFiles, [path]);
+    expect(testView.resolvedFiles, [path]);
 
     // The same result was returned.
     expect(result, same(result1));
@@ -1057,12 +1084,41 @@
 
     // The was a change to a file, no matter which, resolve again.
     await resolveFile2(path);
-    expect(fileResolver.testView!.resolvedFiles, [path, path]);
+    expect(testView.resolvedFiles, [path, path]);
 
     // Get should get a new result.
     expect(result, isNot(same(result1)));
   }
 
+  test_resolveFile_dontCache_whenForCompletion() async {
+    var a_path = convertPath('/workspace/dart/test/lib/a.dart');
+    newFile(a_path, content: r'''
+part 'b.dart';
+''');
+
+    var b_path = convertPath('/workspace/dart/test/lib/b.dart');
+    newFile(b_path, content: r'''
+part of 'a.dart';
+''');
+
+    // No resolved files yet.
+    var testView = fileResolver.testView!;
+    expect(testView.resolvedFiles, isEmpty);
+
+    fileResolver.resolve(
+      path: b_path,
+      completionLine: 0,
+      completionColumn: 0,
+    );
+
+    // The file was resolved.
+    expect(testView.resolvedFiles, [a_path]);
+
+    // The completion location was set, so not units are resolved.
+    // So, the result should not be cached.
+    expect(fileResolver.cachedResults, isEmpty);
+  }
+
   test_resolveLibrary() async {
     var aPath = convertPath('/workspace/dart/test/lib/a.dart');
     newFile(aPath, content: r'''
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 3b2f5a4..63a93db 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -754,8 +754,8 @@
     required TypeAliasElement element,
     required List<String> typeArguments,
   }) {
-    assertElement2(type.aliasElement, declaration: element);
-    assertElementTypeStrings(type.aliasArguments, typeArguments);
+    assertElement2(type.alias?.element, declaration: element);
+    assertElementTypeStrings(type.alias?.typeArguments, typeArguments);
   }
 
   /// Assert that the given [identifier] is a reference to a type alias, in the
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 61f9169..982f6c8 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -758,15 +758,14 @@
       _writelnWithIndent('$typeStr');
     }
 
-    var aliasElement = type.aliasElement;
-    var aliasArguments = type.aliasArguments;
-    if (aliasElement is TypeAliasElementImpl && aliasArguments != null) {
+    var alias = type.alias;
+    if (alias != null) {
       _withIndent(() {
-        _createAstPrinter().writeElement('aliasElement', aliasElement);
+        _createAstPrinter().writeElement('aliasElement', alias.element);
 
         _writeElements<DartType>(
           'aliasArguments',
-          aliasArguments,
+          alias.typeArguments,
           _writeType,
         );
       });
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index fe2372d..ae5fbb6 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -16762,8 +16762,8 @@
     var unit = library.definingCompilationUnit;
     var type = unit.topLevelVariables[0].type as FunctionType;
 
-    expect(type.aliasElement, same(unit.typeAliases[0]));
-    _assertTypeStrings(type.aliasArguments!, ['int']);
+    expect(type.alias!.element, same(unit.typeAliases[0]));
+    _assertTypeStrings(type.alias!.typeArguments, ['int']);
   }
 
   test_functionTypeAlias_typeParameters_variance_contravariant() async {
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index f6b890f..7d86a7f 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -1155,12 +1155,11 @@
       return false;
     }
 
-    var aliasElement = type.aliasElement;
-    var aliasArguments = type.aliasArguments;
-    if (aliasElement != null && aliasArguments != null) {
+    var alias = type.alias;
+    if (alias != null) {
       _writeTypeElementArguments(
-        element: aliasElement,
-        typeArguments: aliasArguments,
+        element: alias.element,
+        typeArguments: alias.typeArguments,
         methodBeingCopied: methodBeingCopied,
       );
       _writeTypeNullability(type);
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 ae02cb6..e79afa3 100644
--- a/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
@@ -7,6 +7,7 @@
 import '../dill/dill_member_builder.dart';
 
 import '../kernel/class_hierarchy_builder.dart';
+import '../kernel/constructor_tearoff_lowering.dart';
 import '../kernel/forest.dart';
 import '../kernel/internal_ast.dart';
 import '../kernel/kernel_api.dart';
@@ -45,7 +46,8 @@
 
   final bool isExtensionInstanceMember = false;
 
-  late Procedure _procedureInternal;
+  final Procedure _procedureInternal;
+  final Procedure? _factoryTearOff;
 
   SourceFactoryBuilder? actualOrigin;
 
@@ -65,19 +67,21 @@
       AsyncMarker asyncModifier,
       ProcedureNameScheme procedureNameScheme,
       {String? nativeMethodName})
-      : super(metadata, modifiers, returnType, name, typeVariables, formals,
+      : _procedureInternal = new Procedure(
+            procedureNameScheme.getName(ProcedureKind.Factory, name),
+            ProcedureKind.Factory,
+            new FunctionNode(null),
+            fileUri: libraryBuilder.fileUri,
+            reference: procedureReference)
+          ..startFileOffset = startCharOffset
+          ..fileOffset = charOffset
+          ..fileEndOffset = charEndOffset
+          ..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault,
+        _factoryTearOff = createConstructorTearOffProcedure(
+            name, libraryBuilder, libraryBuilder.fileUri, charOffset,
+            forAbstractClassOrEnum: false),
+        super(metadata, modifiers, returnType, name, typeVariables, formals,
             libraryBuilder, charOffset, nativeMethodName) {
-    _procedureInternal = new Procedure(
-        procedureNameScheme.getName(kind, name),
-        isExtensionInstanceMember ? ProcedureKind.Method : kind,
-        new FunctionNode(null),
-        fileUri: libraryBuilder.fileUri,
-        reference: procedureReference)
-      ..startFileOffset = startCharOffset
-      ..fileOffset = charOffset
-      ..fileEndOffset = charEndOffset
-      ..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault;
-
     this.asyncModifier = asyncModifier;
   }
 
@@ -116,7 +120,7 @@
   FunctionNode get function => _procedureInternal.function;
 
   @override
-  Member? get readTarget => _procedure;
+  Member? get readTarget => origin._factoryTearOff ?? _procedure;
 
   @override
   Member? get writeTarget => null;
@@ -132,6 +136,9 @@
       SourceLibraryBuilder library, void Function(Member, BuiltMemberKind) f) {
     Member member = build(library);
     f(member, BuiltMemberKind.Method);
+    if (_factoryTearOff != null) {
+      f(_factoryTearOff!, BuiltMemberKind.Method);
+    }
   }
 
   @override
@@ -145,6 +152,11 @@
     _procedureInternal.isConst = isConst;
     updatePrivateMemberName(_procedureInternal, libraryBuilder);
     _procedureInternal.isStatic = isStatic;
+
+    if (_factoryTearOff != null) {
+      buildConstructorTearOffProcedure(_factoryTearOff!, _procedureInternal,
+          classBuilder!.cls, libraryBuilder);
+    }
     return _procedureInternal;
   }
 
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 64c8403..d5c0140 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
@@ -38,14 +38,24 @@
 }
 
 /// Creates the parameters and body for [tearOff] based on [constructor].
-void buildConstructorTearOffProcedure(
-    Procedure tearOff,
-    Constructor constructor,
-    Class enclosingClass,
-    SourceLibraryBuilder libraryBuilder) {
+void buildConstructorTearOffProcedure(Procedure tearOff, Member constructor,
+    Class enclosingClass, SourceLibraryBuilder libraryBuilder) {
+  assert(constructor is Constructor ||
+      (constructor is Procedure && constructor.kind == ProcedureKind.Factory));
+
   int fileOffset = tearOff.fileOffset;
 
-  List<TypeParameter> classTypeParameters = enclosingClass.typeParameters;
+  FunctionNode function = constructor.function!;
+  List<TypeParameter> classTypeParameters;
+  if (constructor is Constructor) {
+    // Generative constructors implicitly have the type parameters of the
+    // enclosing class.
+    classTypeParameters = enclosingClass.typeParameters;
+  } else {
+    // Factory constructors explicitly copy over the type parameters of the
+    // enclosing class.
+    classTypeParameters = function.typeParameters;
+  }
 
   List<TypeParameter> typeParameters;
   List<DartType> typeArguments;
@@ -66,7 +76,7 @@
 
   List<Expression> positionalArguments = [];
   for (VariableDeclaration constructorParameter
-      in constructor.function.positionalParameters) {
+      in function.positionalParameters) {
     VariableDeclaration tearOffParameter = new VariableDeclaration(
         constructorParameter.name,
         type: substitution.substituteType(constructorParameter.type))
@@ -77,8 +87,7 @@
     tearOffParameter.parent = tearOff.function;
   }
   List<NamedExpression> namedArguments = [];
-  for (VariableDeclaration constructorParameter
-      in constructor.function.namedParameters) {
+  for (VariableDeclaration constructorParameter in function.namedParameters) {
     VariableDeclaration tearOffParameter = new VariableDeclaration(
         constructorParameter.name,
         type: substitution.substituteType(constructorParameter.type),
@@ -91,16 +100,22 @@
       ..fileOffset = fileOffset);
   }
   tearOff.function.returnType =
-      substitution.substituteType(constructor.function.returnType);
-  tearOff.function.requiredParameterCount =
-      constructor.function.requiredParameterCount;
-  tearOff.function.body = new ReturnStatement(
-      new ConstructorInvocation(
-          constructor,
-          new Arguments(positionalArguments,
-              named: namedArguments, types: typeArguments)
-            ..fileOffset = tearOff.fileOffset)
-        ..fileOffset = tearOff.fileOffset)
+      substitution.substituteType(function.returnType);
+  tearOff.function.requiredParameterCount = function.requiredParameterCount;
+
+  Arguments arguments = new Arguments(positionalArguments,
+      named: namedArguments, types: typeArguments)
+    ..fileOffset = tearOff.fileOffset;
+  Expression constructorInvocation;
+  if (constructor is Constructor) {
+    constructorInvocation = new ConstructorInvocation(constructor, arguments)
+      ..fileOffset = tearOff.fileOffset;
+  } else {
+    constructorInvocation =
+        new StaticInvocation(constructor as Procedure, arguments)
+          ..fileOffset = tearOff.fileOffset;
+  }
+  tearOff.function.body = new ReturnStatement(constructorInvocation)
     ..fileOffset = tearOff.fileOffset
     ..parent = tearOff.function;
   tearOff.function.fileOffset = tearOff.fileOffset;
@@ -112,7 +127,6 @@
 ///
 /// These might have been inferred and therefore not available when the
 /// parameters were created.
-// TODO(johnniwinther): Add tests for inferred parameter types.
 // TODO(johnniwinther): Avoid doing this when parameter types are not inferred.
 void buildConstructorTearOffOutline(
     Procedure tearOff, Constructor constructor, Class enclosingClass) {
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart
new file mode 100644
index 0000000..9c6ef02
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/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() => new Class1._();
+}
+
+class Class2 {
+  Class2._();
+  factory Class2.named() => new 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) => new Class3._(field);
+}
+
+class Class4 {
+  final int? field;
+
+  Class4._([this.field]);
+  factory Class4([int? field]) => new Class4._(field);
+}
+
+class Class5 {
+  final int field1;
+  final int? field2;
+
+  Class5._(this.field1, [this.field2]);
+  factory Class5(int field1, [int? field2]) => new Class5._(field1, field2);
+}
+
+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}) =>
+      new Class6._(field1, field2: field2, field3: field3);
+}
+
+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/factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect
new file mode 100644
index 0000000..aa4165c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.expect
@@ -0,0 +1,254 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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/factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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 {
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class1
+    return new self::Class1::_();
+  static factory •() → self::Class1
+    return new self::Class1::_();
+  static method _#new#tearOff() → self::Class1
+    return self::Class1::•();
+}
+class Class2 extends core::Object {
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class2
+    return new self::Class2::_();
+  static factory named() → self::Class2
+    return new self::Class2::_();
+  static method _#named#tearOff() → self::Class2
+    return self::Class2::named();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  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
+    return new self::Class3::_(field);
+  static method _#new#tearOff(core::int field) → self::Class3
+    return self::Class3::•(field);
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  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
+    return new self::Class4::_(field);
+  static method _#new#tearOff([core::int? field]) → self::Class4
+    return self::Class4::•(field);
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  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
+    return new self::Class5::_(field1, field2);
+  static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+    return self::Class5::•(field1, field2);
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  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
+    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
+    return 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/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/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/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/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/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/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/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/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/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 = tearoff self::Class1::_#new#tearOff
+  #C3 = tearoff self::Class2::_#named#tearOff
+  #C4 = tearoff self::Class3::_#new#tearOff
+  #C5 = tearoff self::Class4::_#new#tearOff
+  #C6 = tearoff self::Class5::_#new#tearOff
+  #C7 = tearoff self::Class6::_#new#tearOff
+  #C8 = false
+}
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
new file mode 100644
index 0000000..3a8fa1a
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.strong.transformed.expect
@@ -0,0 +1,254 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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/factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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 {
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class1
+    return new self::Class1::_();
+  static factory •() → self::Class1
+    return new self::Class1::_();
+  static method _#new#tearOff() → self::Class1
+    return self::Class1::•();
+}
+class Class2 extends core::Object {
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class2
+    return new self::Class2::_();
+  static factory named() → self::Class2
+    return new self::Class2::_();
+  static method _#named#tearOff() → self::Class2
+    return self::Class2::named();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  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
+    return new self::Class3::_(field);
+  static method _#new#tearOff(core::int field) → self::Class3
+    return self::Class3::•(field);
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  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
+    return new self::Class4::_(field);
+  static method _#new#tearOff([core::int? field]) → self::Class4
+    return self::Class4::•(field);
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  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
+    return new self::Class5::_(field1, field2);
+  static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+    return self::Class5::•(field1, field2);
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  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
+    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
+    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>);
+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/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/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/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/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/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/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/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/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/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 = tearoff self::Class1::_#new#tearOff
+  #C3 = tearoff self::Class2::_#named#tearOff
+  #C4 = tearoff self::Class3::_#new#tearOff
+  #C5 = tearoff self::Class4::_#new#tearOff
+  #C6 = tearoff self::Class5::_#new#tearOff
+  #C7 = tearoff self::Class6::_#new#tearOff
+  #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline.expect
new file mode 100644
index 0000000..e4d0e54
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline.expect
@@ -0,0 +1,46 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1 {
+  Class1._();
+  factory Class1() => new Class1._();
+}
+
+class Class2 {
+  Class2._();
+  factory Class2.named() => new Class2._();
+}
+
+testNoArgs() {}
+
+class Class3 {
+  final int field;
+  Class3._(this.field);
+  factory Class3(int field) => new Class3._(field);
+}
+
+class Class4 {
+  final int? field;
+  Class4._([this.field]);
+  factory Class4([int? field]) => new Class4._(field);
+}
+
+class Class5 {
+  final int field1;
+  final int? field2;
+  Class5._(this.field1, [this.field2]);
+  factory Class5(int field1, [int? field2]) => new Class5._(field1, field2);
+}
+
+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}) =>
+      new Class6._(field1, field2: field2, field3: field3);
+}
+
+testArgs() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..0e60ce8
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.textual_outline_modelled.expect
@@ -0,0 +1,44 @@
+class Class1 {
+  Class1._();
+  factory Class1() => new Class1._();
+}
+
+class Class2 {
+  Class2._();
+  factory Class2.named() => new Class2._();
+}
+
+class Class3 {
+  Class3._(this.field);
+  factory Class3(int field) => new Class3._(field);
+  final int field;
+}
+
+class Class4 {
+  Class4._([this.field]);
+  factory Class4([int? field]) => new Class4._(field);
+  final int? field;
+}
+
+class Class5 {
+  Class5._(this.field1, [this.field2]);
+  factory Class5(int field1, [int? field2]) => new Class5._(field1, field2);
+  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}) =>
+      new Class6._(field1, field2: field2, field3: field3);
+  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/factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect
new file mode 100644
index 0000000..aa4165c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.expect
@@ -0,0 +1,254 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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/factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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 {
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class1
+    return new self::Class1::_();
+  static factory •() → self::Class1
+    return new self::Class1::_();
+  static method _#new#tearOff() → self::Class1
+    return self::Class1::•();
+}
+class Class2 extends core::Object {
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class2
+    return new self::Class2::_();
+  static factory named() → self::Class2
+    return new self::Class2::_();
+  static method _#named#tearOff() → self::Class2
+    return self::Class2::named();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  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
+    return new self::Class3::_(field);
+  static method _#new#tearOff(core::int field) → self::Class3
+    return self::Class3::•(field);
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  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
+    return new self::Class4::_(field);
+  static method _#new#tearOff([core::int? field]) → self::Class4
+    return self::Class4::•(field);
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  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
+    return new self::Class5::_(field1, field2);
+  static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+    return self::Class5::•(field1, field2);
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  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
+    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
+    return 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/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/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/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/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/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/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/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/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/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 = tearoff self::Class1::_#new#tearOff
+  #C3 = tearoff self::Class2::_#named#tearOff
+  #C4 = tearoff self::Class3::_#new#tearOff
+  #C5 = tearoff self::Class4::_#new#tearOff
+  #C6 = tearoff self::Class5::_#new#tearOff
+  #C7 = tearoff self::Class6::_#new#tearOff
+  #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.outline.expect
new file mode 100644
index 0000000..5366579f
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.outline.expect
@@ -0,0 +1,82 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  constructor _() → self::Class1
+    ;
+  static method _#_#tearOff() → self::Class1
+    return new self::Class1::_();
+  static factory •() → self::Class1
+    ;
+  static method _#new#tearOff() → self::Class1
+    return self::Class1::•();
+}
+class Class2 extends core::Object {
+  constructor _() → self::Class2
+    ;
+  static method _#_#tearOff() → self::Class2
+    return new self::Class2::_();
+  static factory named() → self::Class2
+    ;
+  static method _#named#tearOff() → self::Class2
+    return self::Class2::named();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  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
+    ;
+  static method _#new#tearOff(core::int field) → self::Class3
+    return self::Class3::•(field);
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  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
+    ;
+  static method _#new#tearOff([core::int? field]) → self::Class4
+    return self::Class4::•(field);
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  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
+    ;
+  static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+    return self::Class5::•(field1, field2);
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  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
+    ;
+  static method _#new#tearOff(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+    return 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/factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect
new file mode 100644
index 0000000..3a8fa1a
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart.weak.transformed.expect
@@ -0,0 +1,254 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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/factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/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/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 {
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class1
+    return new self::Class1::_();
+  static factory •() → self::Class1
+    return new self::Class1::_();
+  static method _#new#tearOff() → self::Class1
+    return self::Class1::•();
+}
+class Class2 extends core::Object {
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff() → self::Class2
+    return new self::Class2::_();
+  static factory named() → self::Class2
+    return new self::Class2::_();
+  static method _#named#tearOff() → self::Class2
+    return self::Class2::named();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  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
+    return new self::Class3::_(field);
+  static method _#new#tearOff(core::int field) → self::Class3
+    return self::Class3::•(field);
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  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
+    return new self::Class4::_(field);
+  static method _#new#tearOff([core::int? field]) → self::Class4
+    return self::Class4::•(field);
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  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
+    return new self::Class5::_(field1, field2);
+  static method _#new#tearOff(core::int field1, [core::int? field2]) → self::Class5
+    return self::Class5::•(field1, field2);
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  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
+    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
+    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>);
+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/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/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/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/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/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/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/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/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/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 = tearoff self::Class1::_#new#tearOff
+  #C3 = tearoff self::Class2::_#named#tearOff
+  #C4 = tearoff self::Class3::_#new#tearOff
+  #C5 = tearoff self::Class4::_#new#tearOff
+  #C6 = tearoff self::Class5::_#new#tearOff
+  #C7 = tearoff self::Class6::_#new#tearOff
+  #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart
new file mode 100644
index 0000000..a8d167a
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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() => new 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() => new Class2<T>._();
+}
+
+class Class3<T extends S, S> {
+  Class3._();
+  factory Class3() => new Class3<T, S>._();
+}
+
+class Class4<T extends Class4<T>> {
+  Class4._();
+  factory Class4() => new Class4<T>._();
+}
+
+class Class4int extends Class4<Class4int> {
+  Class4int._() : super._();
+  factory Class4int() => new 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_factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.strong.expect
new file mode 100644
index 0000000..7dc5b5e
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.strong.expect
@@ -0,0 +1,200 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+//     f1a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+//     f1b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+//     f2a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_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_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 {
+  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%>
+    return new self::Class1::_<self::Class1::•::T%>();
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+    return self::Class1::•<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+  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>
+    return new self::Class2::_<self::Class2::•::T>();
+  static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+    return self::Class2::•<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  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%>
+    return new self::Class3::_<self::Class3::•::T%, self::Class3::•::S%>();
+  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 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 {
+  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>
+    return new self::Class4::_<self::Class4::•::T>();
+  static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+    return self::Class4::•<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+  constructor _() → self::Class4int
+    : super self::Class4::_()
+    ;
+  static method _#_#tearOff() → self::Class4int
+    return new self::Class4int::_();
+  static factory •() → self::Class4int
+    return new self::Class4int::_();
+  static method _#new#tearOff() → self::Class4int
+    return 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_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_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_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 = tearoff self::Class1::_#new#tearOff
+  #C2 = tearoff self::Class2::_#new#tearOff
+  #C3 = tearoff self::Class3::_#new#tearOff
+  #C4 = tearoff self::Class4::_#new#tearOff
+  #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.strong.transformed.expect
new file mode 100644
index 0000000..867fcb1
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.strong.transformed.expect
@@ -0,0 +1,200 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+//     f1a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+//     f1b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+//     f2a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_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_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 {
+  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%>
+    return new self::Class1::_<self::Class1::•::T%>();
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+    return self::Class1::•<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+  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>
+    return new self::Class2::_<self::Class2::•::T>();
+  static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+    return self::Class2::•<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  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%>
+    return new self::Class3::_<self::Class3::•::T%, self::Class3::•::S%>();
+  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 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 {
+  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>
+    return new self::Class4::_<self::Class4::•::T>();
+  static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+    return self::Class4::•<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+  constructor _() → self::Class4int
+    : super self::Class4::_()
+    ;
+  static method _#_#tearOff() → self::Class4int
+    return new self::Class4int::_();
+  static factory •() → self::Class4int
+    return new self::Class4int::_();
+  static method _#new#tearOff() → self::Class4int
+    return 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_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_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_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 = tearoff self::Class1::_#new#tearOff
+  #C2 = tearoff self::Class2::_#new#tearOff
+  #C3 = tearoff self::Class3::_#new#tearOff
+  #C4 = tearoff self::Class4::_#new#tearOff
+  #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.textual_outline.expect
new file mode 100644
index 0000000..b692fbf
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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() => new Class1<T>._();
+}
+
+testGeneric() {}
+
+class Class2<T extends num> {
+  Class2._();
+  factory Class2() => new Class2<T>._();
+}
+
+class Class3<T extends S, S> {
+  Class3._();
+  factory Class3() => new Class3<T, S>._();
+}
+
+class Class4<T extends Class4<T>> {
+  Class4._();
+  factory Class4() => new Class4<T>._();
+}
+
+class Class4int extends Class4<Class4int> {
+  Class4int._() : super._();
+  factory Class4int() => new Class4int._();
+}
+
+testBounded() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..c82d489
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.textual_outline_modelled.expect
@@ -0,0 +1,31 @@
+class Class1<T> {
+  Class1._();
+  factory Class1() => new Class1<T>._();
+}
+
+class Class2<T extends num> {
+  Class2._();
+  factory Class2() => new Class2<T>._();
+}
+
+class Class3<T extends S, S> {
+  Class3._();
+  factory Class3() => new Class3<T, S>._();
+}
+
+class Class4<T extends Class4<T>> {
+  Class4._();
+  factory Class4() => new Class4<T>._();
+}
+
+class Class4int extends Class4<Class4int> {
+  Class4int._() : super._();
+  factory Class4int() => new 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_factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.expect
new file mode 100644
index 0000000..7dc5b5e
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.expect
@@ -0,0 +1,200 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+//     f1a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+//     f1b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+//     f2a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_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_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 {
+  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%>
+    return new self::Class1::_<self::Class1::•::T%>();
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+    return self::Class1::•<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+  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>
+    return new self::Class2::_<self::Class2::•::T>();
+  static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+    return self::Class2::•<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  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%>
+    return new self::Class3::_<self::Class3::•::T%, self::Class3::•::S%>();
+  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 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 {
+  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>
+    return new self::Class4::_<self::Class4::•::T>();
+  static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+    return self::Class4::•<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+  constructor _() → self::Class4int
+    : super self::Class4::_()
+    ;
+  static method _#_#tearOff() → self::Class4int
+    return new self::Class4int::_();
+  static factory •() → self::Class4int
+    return new self::Class4int::_();
+  static method _#new#tearOff() → self::Class4int
+    return 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_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_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_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 = tearoff self::Class1::_#new#tearOff
+  #C2 = tearoff self::Class2::_#new#tearOff
+  #C3 = tearoff self::Class3::_#new#tearOff
+  #C4 = tearoff self::Class4::_#new#tearOff
+  #C5 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.outline.expect
new file mode 100644
index 0000000..6216fd6
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.outline.expect
@@ -0,0 +1,65 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1<T extends core::Object? = dynamic> extends core::Object {
+  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%>
+    ;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+    return self::Class1::•<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+  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>
+    ;
+  static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+    return self::Class2::•<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  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%>
+    ;
+  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 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 {
+  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>
+    ;
+  static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+    return self::Class4::•<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+  constructor _() → self::Class4int
+    ;
+  static method _#_#tearOff() → self::Class4int
+    return new self::Class4int::_();
+  static factory •() → self::Class4int
+    ;
+  static method _#new#tearOff() → self::Class4int
+    return 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_factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.transformed.expect
new file mode 100644
index 0000000..867fcb1
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart.weak.transformed.expect
@@ -0,0 +1,200 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:27:8: Error: Expected 1 type arguments.
+//     f1a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_factory_tear_off.dart:35:8: Error: Expected 0 type arguments.
+//     f1b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_factory_tear_off.dart:75:8: Error: Expected 1 type arguments.
+//     f2a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/generic_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_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_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 {
+  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%>
+    return new self::Class1::_<self::Class1::•::T%>();
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class1<self::Class1::_#new#tearOff::T%>
+    return self::Class1::•<self::Class1::_#new#tearOff::T%>();
+}
+class Class2<T extends core::num> extends core::Object {
+  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>
+    return new self::Class2::_<self::Class2::•::T>();
+  static method _#new#tearOff<T extends core::num>() → self::Class2<self::Class2::_#new#tearOff::T>
+    return self::Class2::•<self::Class2::_#new#tearOff::T>();
+}
+class Class3<T extends self::Class3::S% = dynamic, S extends core::Object? = dynamic> extends core::Object {
+  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%>
+    return new self::Class3::_<self::Class3::•::T%, self::Class3::•::S%>();
+  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 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 {
+  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>
+    return new self::Class4::_<self::Class4::•::T>();
+  static method _#new#tearOff<T extends self::Class4<self::Class4::_#new#tearOff::T> = self::Class4<dynamic>>() → self::Class4<self::Class4::_#new#tearOff::T>
+    return self::Class4::•<self::Class4::_#new#tearOff::T>();
+}
+class Class4int extends self::Class4<self::Class4int> {
+  constructor _() → self::Class4int
+    : super self::Class4::_()
+    ;
+  static method _#_#tearOff() → self::Class4int
+    return new self::Class4int::_();
+  static factory •() → self::Class4int
+    return new self::Class4int::_();
+  static method _#new#tearOff() → self::Class4int
+    return 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_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_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_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 = tearoff self::Class1::_#new#tearOff
+  #C2 = tearoff self::Class2::_#new#tearOff
+  #C3 = tearoff self::Class3::_#new#tearOff
+  #C4 = tearoff self::Class4::_#new#tearOff
+  #C5 = false
+}
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 4590a76..d307442 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -196,6 +196,8 @@
 SampleBlockBuffer::~SampleBlockBuffer() {
   delete[] blocks_;
   blocks_ = nullptr;
+  delete memory_;
+  memory_ = nullptr;
   capacity_ = 0;
   cursor_ = 0;
 }
@@ -345,6 +347,11 @@
   cursor_ = 0;
 }
 
+AllocationSampleBuffer::~AllocationSampleBuffer() {
+  delete memory_;
+  memory_ = nullptr;
+}
+
 void AllocationSampleBuffer::FreeAllocationSample(Sample* sample) {
   MutexLocker ml(&mutex_);
   while (sample != nullptr) {
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index a4adbff4..dd30bcc 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -870,7 +870,7 @@
 class AllocationSampleBuffer : public SampleBuffer {
  public:
   explicit AllocationSampleBuffer(intptr_t capacity = 60000);
-  virtual ~AllocationSampleBuffer() = default;
+  virtual ~AllocationSampleBuffer();
 
   virtual Sample* ReserveSample();
   virtual Sample* ReserveSampleAndLink(Sample* previous);
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
index 54576b0..33854c7 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
@@ -85,10 +85,14 @@
 gbind(f, @rest List<Object> typeArgs) {
   GenericFunctionType type = JS('!', '#[#]', f, _runtimeType);
   type.checkBounds(typeArgs);
-  // Create a JS wrapper function that will also pass the type arguments, and
-  // tag it with the instantiated function type.
+  // Create a JS wrapper function that will also pass the type arguments.
   var result =
       JS('', '(...args) => #.apply(null, #.concat(args))', f, typeArgs);
+  // Tag the wrapper with the original function to be used for equality checks.
+  JS('', '#["_originalFn"] = #', result, f);
+  JS('', '#["_typeArgs"] = #', result, constList(typeArgs, Object));
+
+  // Tag the wrapper with the instantiated function type.
   return fn(result, type.instantiate(typeArgs));
 }
 
diff --git a/tests/language/closure/regress46568_test.dart b/tests/language/closure/regress46568_test.dart
new file mode 100644
index 0000000..33e34b6
--- /dev/null
+++ b/tests/language/closure/regress46568_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+// Regression test for https://github.com/dart-lang/sdk/issues/46568.
+
+var genericTopLevelFunctionCallCount = 0;
+var genericStaticMethodCallCount = 0;
+
+T? genericTopLevelFunction<T>() {
+  genericTopLevelFunctionCallCount++;
+  return null;
+}
+
+class A {
+  static T? genericStaticMethod<T>() {
+    genericStaticMethodCallCount++;
+    return null;
+  }
+}
+
+const int? Function() cIntTopLevelFunction1 = genericTopLevelFunction;
+const int? Function() cIntStaticMethod1 = A.genericStaticMethod;
+
+void main() {
+  // Two different const generic function instantiations should not be
+  // canonicalized to the same value.
+  Expect.isFalse(identical(cIntTopLevelFunction1, cIntStaticMethod1));
+  Expect.notEquals(cIntTopLevelFunction1, cIntStaticMethod1);
+
+  cIntTopLevelFunction1();
+  Expect.equals(1, genericTopLevelFunctionCallCount);
+  Expect.equals(0, genericStaticMethodCallCount);
+
+  cIntStaticMethod1();
+  Expect.equals(1, genericTopLevelFunctionCallCount);
+  Expect.equals(1, genericStaticMethodCallCount);
+}
diff --git a/tests/language_2/closure/regress46568_test.dart b/tests/language_2/closure/regress46568_test.dart
new file mode 100644
index 0000000..1117775
--- /dev/null
+++ b/tests/language_2/closure/regress46568_test.dart
@@ -0,0 +1,42 @@
+// 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.
+
+// @dart = 2.9
+
+import 'package:expect/expect.dart';
+
+// Regression test for https://github.com/dart-lang/sdk/issues/46568.
+
+var genericTopLevelFunctionCallCount = 0;
+var genericStaticMethodCallCount = 0;
+
+T genericTopLevelFunction<T>() {
+  genericTopLevelFunctionCallCount++;
+  return null;
+}
+
+class A {
+  static T genericStaticMethod<T>() {
+    genericStaticMethodCallCount++;
+    return null;
+  }
+}
+
+const int Function() cIntTopLevelFunction1 = genericTopLevelFunction;
+const int Function() cIntStaticMethod1 = A.genericStaticMethod;
+
+void main() {
+  // Two different const generic function instantiations should not be
+  // canonicalized to the same value.
+  Expect.isFalse(identical(cIntTopLevelFunction1, cIntStaticMethod1));
+  Expect.notEquals(cIntTopLevelFunction1, cIntStaticMethod1);
+
+  cIntTopLevelFunction1();
+  Expect.equals(1, genericTopLevelFunctionCallCount);
+  Expect.equals(0, genericStaticMethodCallCount);
+
+  cIntStaticMethod1();
+  Expect.equals(1, genericTopLevelFunctionCallCount);
+  Expect.equals(1, genericStaticMethodCallCount);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 21e7eeb..b0a5cb0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 335
+PRERELEASE 336
 PRERELEASE_PATCH 0
\ No newline at end of file