Version 2.14.0-339.0.dev

Merge commit '93d5c4eeeff269d798fe66df78aafc28ed3ab605' into 'dev'
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index ae2d2bc7..73cc7f3 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -277,12 +277,26 @@
 
     for (Annotation annotation in annotations) {
       if (annotation.name.name == _ffiNativeName) {
+        // All FFI Natives must be static.
         final isStatic = (node is FunctionDeclaration) ||
             ((node is MethodDeclaration) && node.isStatic);
         if (!isStatic) {
           _errorReporter.reportErrorForNode(
               FfiCode.FFI_NATIVE_ONLY_STATIC, node);
         }
+        // Leaf call FFI Natives can't use Handles.
+        ArgumentList? argumentList = annotation.arguments;
+        if (argumentList != null) {
+          NodeList<Expression> arguments = argumentList.arguments;
+          TypeArgumentList? typeArgumentList = annotation.typeArguments;
+          if (typeArgumentList != null) {
+            NodeList<TypeAnnotation> typeArguments = typeArgumentList.arguments;
+            if (typeArguments.isNotEmpty && typeArguments[0].type != null) {
+              _validateFfiLeafCallUsesNoHandles(
+                  arguments, typeArguments[0].type!, node);
+            }
+          }
+        }
       }
     }
   }
@@ -530,7 +544,8 @@
         _errorReporter.reportErrorForNode(
             FfiCode.MUST_BE_A_SUBTYPE, node, [TPrime, F, 'asFunction']);
       }
-      _validateFfiLeafCallUsesNoHandles(node, TPrime, node);
+      _validateFfiLeafCallUsesNoHandles(node.argumentList.arguments, TPrime,
+          node);
     }
     _validateIsLeafIsConst(node);
   }
@@ -622,9 +637,8 @@
     }
   }
 
-  void _validateFfiLeafCallUsesNoHandles(
-      MethodInvocation node, DartType nativeType, AstNode errorNode) {
-    final args = node.argumentList.arguments;
+  void _validateFfiLeafCallUsesNoHandles(NodeList<Expression> args,
+      DartType nativeType, AstNode errorNode) {
     if (args.isNotEmpty) {
       for (final arg in args) {
         if (arg is NamedExpression) {
@@ -817,7 +831,8 @@
           FfiCode.MUST_BE_A_SUBTYPE, errorNode, [S, F, 'lookupFunction']);
     }
     _validateIsLeafIsConst(node);
-    _validateFfiLeafCallUsesNoHandles(node, S, typeArguments![0]);
+    _validateFfiLeafCallUsesNoHandles(node.argumentList.arguments, S,
+        typeArguments![0]);
   }
 
   /// Validate that none of the [annotations] are from `dart:ffi`.
diff --git a/pkg/analyzer/test/src/diagnostics/ffi_native_test.dart b/pkg/analyzer/test/src/diagnostics/ffi_native_test.dart
index e90a157..a11172c 100644
--- a/pkg/analyzer/test/src/diagnostics/ffi_native_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/ffi_native_test.dart
@@ -26,4 +26,32 @@
       error(FfiCode.FFI_NATIVE_ONLY_STATIC, 31, 75),
     ]);
   }
+
+  test_FfiNativeCanUseHandles() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+@FfiNative<Handle Function(Handle)>('DoesntMatter')
+external Object doesntMatter(Object);
+''', []);
+  }
+
+  test_FfiNativeLeafMustNotReturnHandle() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+@FfiNative<Handle Function()>('DoesntMatter', isLeaf:true)
+external Object doesntMatter();
+''', [
+      error(FfiCode.LEAF_CALL_MUST_NOT_RETURN_HANDLE, 19, 90),
+    ]);
+  }
+
+  test_FfiNativeLeafMustNotTakeHandles() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+@FfiNative<Void Function(Handle)>('DoesntMatter', isLeaf:true)
+external void doesntMatter(Object o);
+''', [
+      error(FfiCode.LEAF_CALL_MUST_NOT_TAKE_HANDLE, 19, 100),
+    ]);
+  }
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 010fd50..08e70bf 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -708,6 +708,12 @@
   }
 
   @override
+  TreeNode visitRedirectingFactoryTearOff(
+      RedirectingFactoryTearOff node, TreeNode? removalSentinel) {
+    return evaluateAndTransformWithContext(node, node);
+  }
+
+  @override
   TreeNode visitInstantiation(Instantiation node, TreeNode? removalSentinel) {
     Instantiation result =
         super.visitInstantiation(node, removalSentinel) as Instantiation;
@@ -3434,7 +3440,7 @@
 
   @override
   Constant visitRedirectingFactoryTearOff(RedirectingFactoryTearOff node) {
-    return defaultExpression(node);
+    return canonicalize(new RedirectingFactoryTearOffConstant(node.target));
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index e49f3a2e..8842a74 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -3178,8 +3178,13 @@
               tearOffExpression = _helper.forest
                   .createConstructorTearOff(token.charOffset, tearOff);
             } else if (tearOff is Procedure) {
-              tearOffExpression =
-                  _helper.forest.createStaticTearOff(token.charOffset, tearOff);
+              if (tearOff.isRedirectingFactory) {
+                tearOffExpression = _helper.forest
+                    .createRedirectingFactoryTearOff(token.charOffset, tearOff);
+              } else {
+                tearOffExpression = _helper.forest
+                    .createStaticTearOff(token.charOffset, tearOff);
+              }
             } else if (tearOff != null) {
               unhandled("${tearOff.runtimeType}", "buildPropertyAccess",
                   operatorOffset, _helper.uri);
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 19e7096..8ba13f0 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -836,9 +836,17 @@
   StaticTearOff createStaticTearOff(int fileOffset, Procedure procedure) {
     // ignore: unnecessary_null_comparison
     assert(fileOffset != null);
+    assert(!procedure.isRedirectingFactory);
     return new StaticTearOff(procedure)..fileOffset = fileOffset;
   }
 
+  RedirectingFactoryTearOff createRedirectingFactoryTearOff(
+      int fileOffset, Procedure procedure) {
+    // ignore: unnecessary_null_comparison
+    assert(fileOffset != null);
+    return new RedirectingFactoryTearOff(procedure)..fileOffset = fileOffset;
+  }
+
   Instantiation createInstantiation(
       int fileOffset, Expression expression, List<DartType> typeArguments) {
     // ignore: unnecessary_null_comparison
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index a435c3d..9e9b67d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -225,7 +225,9 @@
   @override
   ExpressionInferenceResult visitRedirectingFactoryTearOff(
       RedirectingFactoryTearOff node, DartType typeContext) {
-    return _unhandledExpression(node, typeContext);
+    DartType type =
+        node.target.function.computeFunctionType(inferrer.library.nonNullable);
+    return inferrer.instantiateTearOff(type, typeContext, node);
   }
 
   @override
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.strong.expect
index 4251833..b0293c7 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.strong.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.strong.expect
@@ -62,7 +62,7 @@
   return self::test();
 
 constants  {
-  #C1 = static-tearoff self::A::redirectingFactory
-  #C2 = static-tearoff self::A::redirectingFactoryChild
-  #C3 = static-tearoff self::A::redirectingTwice
+  #C1 = redirecting-factory-tearoff self::A::redirectingFactory
+  #C2 = redirecting-factory-tearoff self::A::redirectingFactoryChild
+  #C3 = redirecting-factory-tearoff self::A::redirectingTwice
 }
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.strong.transformed.expect
index 4f2b568..44e6acc 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.strong.transformed.expect
@@ -62,7 +62,7 @@
   return self::test();
 
 constants  {
-  #C1 = static-tearoff self::A::redirectingFactory
-  #C2 = static-tearoff self::A::redirectingFactoryChild
-  #C3 = static-tearoff self::A::redirectingTwice
+  #C1 = redirecting-factory-tearoff self::A::redirectingFactory
+  #C2 = redirecting-factory-tearoff self::A::redirectingFactoryChild
+  #C3 = redirecting-factory-tearoff self::A::redirectingTwice
 }
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.weak.expect
index 4251833..b0293c7 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.weak.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.weak.expect
@@ -62,7 +62,7 @@
   return self::test();
 
 constants  {
-  #C1 = static-tearoff self::A::redirectingFactory
-  #C2 = static-tearoff self::A::redirectingFactoryChild
-  #C3 = static-tearoff self::A::redirectingTwice
+  #C1 = redirecting-factory-tearoff self::A::redirectingFactory
+  #C2 = redirecting-factory-tearoff self::A::redirectingFactoryChild
+  #C3 = redirecting-factory-tearoff self::A::redirectingTwice
 }
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.weak.transformed.expect
index 4f2b568..44e6acc 100644
--- a/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_constructors.dart.weak.transformed.expect
@@ -62,7 +62,7 @@
   return self::test();
 
 constants  {
-  #C1 = static-tearoff self::A::redirectingFactory
-  #C2 = static-tearoff self::A::redirectingFactoryChild
-  #C3 = static-tearoff self::A::redirectingTwice
+  #C1 = redirecting-factory-tearoff self::A::redirectingFactory
+  #C2 = redirecting-factory-tearoff self::A::redirectingFactoryChild
+  #C3 = redirecting-factory-tearoff self::A::redirectingTwice
 }
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart
new file mode 100644
index 0000000..75d63fa
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart
@@ -0,0 +1,163 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+  print('inSoundMode: $inSoundMode');
+  testNoArgs();
+  testArgs();
+}
+
+class Class1 {
+  Class1._();
+  factory Class1() = Class1._;
+}
+
+class Class2 {
+  Class2._();
+  factory Class2.named() = Class2._;
+}
+
+testNoArgs() {
+  var f1a = Class1.new;
+  var c1a = f1a();
+  expect(true, c1a is Class1);
+
+  dynamic f1b = Class1.new;
+  var c1b = f1b();
+  expect(true, c1b is Class1);
+
+  expect(true, identical(f1a, f1b));
+
+  var f2a = Class2.named;
+  var c2a = f2a();
+  expect(true, c2a is Class2);
+
+  dynamic f2b = Class2.named;
+  var c2b = f2b();
+  expect(true, c2b is Class2);
+
+  expect(true, identical(f2a, f2b));
+}
+
+class Class3 {
+  final int field;
+
+  Class3._(this.field);
+  factory Class3(int field) = Class3._;
+}
+
+class Class4 {
+  final int? field;
+
+  Class4._([this.field]);
+  factory Class4([int? field]) = Class4._;
+}
+
+class Class5 {
+  final int field1;
+  final int? field2;
+
+  Class5._(this.field1, [this.field2]);
+  factory Class5(int field1, [int? field2]) = Class5._;
+}
+
+class Class6 {
+  final int field1;
+  final int? field2;
+  final int field3;
+
+  Class6._(this.field1, {this.field2, required this.field3});
+  factory Class6(int field1, {int? field2, required int field3}) =
+      Class6._;
+}
+
+testArgs() {
+  var f3a = Class3.new;
+  var c3a = f3a(42);
+  expect(42, c3a.field);
+  () {
+    f3a(); // error
+    f3a(42, 87); // error
+  };
+
+  dynamic f3b = Class3.new;
+  var c3b = f3b(87);
+  expect(87, c3b.field);
+  throws(() => f3b());
+  throws(() => f3b(42, 87));
+
+  var f4a = Class4.new;
+  var c4a = f4a();
+  expect(null, c4a.field);
+  var c4b = f4a(42);
+  expect(42, c4b.field);
+  () {
+    f4a(42, 87); // error
+  };
+  dynamic f4b = Class4.new;
+  throws(() => f4b(42, 87));
+
+
+  var f5a = Class5.new;
+  var c5a = f5a(42);
+  expect(42, c5a.field1);
+  expect(null, c5a.field2);
+  var c5b = f5a(87, 42);
+  expect(87, c5b.field1);
+  expect(42, c5b.field2);
+  () {
+    f5a(); // error
+    f5a(42, 87, 123); // error
+  };
+  dynamic f5b = Class5.new;
+  throws(() => f5b());
+  throws(() => f5b(42, 87, 123));
+
+  var f6a = Class6.new;
+  var c6a = f6a(42, field3: 87);
+  expect(42, c6a.field1);
+  expect(null, c6a.field2);
+  expect(87, c6a.field3);
+  () {
+    f6a(); // error
+    f6a(42); // error
+    f6a(42, 87); // error
+    f6a(field1: 87, field2: 87); // error
+  };
+
+  var c6b = f6a(42, field2: 123, field3: 87);
+  expect(42, c6b.field1);
+  expect(123, c6b.field2);
+  expect(87, c6b.field3);
+
+  var c6c = f6a(87, field3: 42, field2: 123);
+  expect(87, c6c.field1);
+  expect(123, c6c.field2);
+  expect(42, c6c.field3);
+
+  dynamic f6b = Class6.new;
+  throws(() => f6b());
+  throws(() => f6b(42), inSoundModeOnly: true);
+  throws(() => f6b(42, 87), inSoundModeOnly: true);
+  throws(() => f6b(field1: 87, field2: 87));
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(Function() f, {bool inSoundModeOnly: false}) {
+  try {
+    f();
+  } catch (e) {
+    print('Thrown: $e');
+    return;
+  }
+  if (!inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw 'Expected exception';
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.expect
new file mode 100644
index 0000000..f2dd642
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.expect
@@ -0,0 +1,236 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f3a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f4a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+//     f5a(42, 87, 123); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f6a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(field1: 87, field2: 87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static factory •() → self::Class1
+    let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+}
+class Class2 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static factory named() → self::Class2
+    let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _(core::int field) → self::Class3
+    : self::Class3::field = field, super core::Object::•()
+    ;
+  static factory •(core::int field) → self::Class3
+    let dynamic #redirecting_factory = self::Class3::_ in invalid-expression;
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _([core::int? field = #C1]) → self::Class4
+    : self::Class4::field = field, super core::Object::•()
+    ;
+  static factory •([core::int? field = #C1]) → self::Class4
+    let dynamic #redirecting_factory = self::Class4::_ in invalid-expression;
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+  constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+    ;
+  static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    let dynamic #redirecting_factory = self::Class5::_ in invalid-expression;
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+  constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+    ;
+  static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
+}
+static 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/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+    f3a(); // error
+       ^" in f3a{<inapplicable>}.();
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f3a(42, 87); // error
+       ^" in f3a{<inapplicable>}.(42, 87);
+  };
+  dynamic f3b = #C4;
+  dynamic c3b = f3b{dynamic}.call(87);
+  self::expect(87, c3b{dynamic}.field);
+  self::throws(() → dynamic => f3b{dynamic}.call());
+  self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+  ([core::int?]) → self::Class4 f4a = #C5;
+  self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+  self::expect(null, c4a.{self::Class4::field}{core::int?});
+  self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+  self::expect(42, c4b.{self::Class4::field}{core::int?});
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f4a(42, 87); // error
+       ^" in f4a{<inapplicable>}.(42, 87);
+  };
+  dynamic f4b = #C5;
+  self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+  (core::int, [core::int?]) → self::Class5 f5a = #C6;
+  self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+  self::expect(42, c5a.{self::Class5::field1}{core::int});
+  self::expect(null, c5a.{self::Class5::field2}{core::int?});
+  self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+  self::expect(87, c5b.{self::Class5::field1}{core::int});
+  self::expect(42, c5b.{self::Class5::field2}{core::int?});
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+    f5a(); // error
+       ^" in f5a{<inapplicable>}.();
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+    f5a(42, 87, 123); // error
+       ^" in f5a{<inapplicable>}.(42, 87, 123);
+  };
+  dynamic f5b = #C6;
+  self::throws(() → dynamic => f5b{dynamic}.call());
+  self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+  (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+  self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6a.{self::Class6::field1}{core::int});
+  self::expect(null, c6a.{self::Class6::field2}{core::int?});
+  self::expect(87, c6a.{self::Class6::field3}{core::int});
+  () → Null {
+    let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(); // error
+       ^" in f6a{<inapplicable>}.();
+    let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+    f6a(42); // error
+       ^" in f6a{<inapplicable>}.(42);
+    let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f6a(42, 87); // error
+       ^" in f6a{<inapplicable>}.(42, 87);
+    let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(field1: 87, field2: 87); // error
+       ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+  };
+  self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6b.{self::Class6::field1}{core::int});
+  self::expect(123, c6b.{self::Class6::field2}{core::int?});
+  self::expect(87, c6b.{self::Class6::field3}{core::int});
+  self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(87, c6c.{self::Class6::field1}{core::int});
+  self::expect(123, c6c.{self::Class6::field2}{core::int?});
+  self::expect(42, c6c.{self::Class6::field3}{core::int});
+  dynamic f6b = #C7;
+  self::throws(() → dynamic => f6b{dynamic}.call());
+  self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = null
+  #C2 = redirecting-factory-tearoff self::Class1::•
+  #C3 = redirecting-factory-tearoff self::Class2::named
+  #C4 = redirecting-factory-tearoff self::Class3::•
+  #C5 = redirecting-factory-tearoff self::Class4::•
+  #C6 = redirecting-factory-tearoff self::Class5::•
+  #C7 = redirecting-factory-tearoff self::Class6::•
+  #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.transformed.expect
new file mode 100644
index 0000000..ccaec42
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.strong.transformed.expect
@@ -0,0 +1,236 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f3a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f4a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+//     f5a(42, 87, 123); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f6a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(field1: 87, field2: 87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static factory •() → self::Class1
+    let Never #redirecting_factory = self::Class1::_ in invalid-expression;
+}
+class Class2 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static factory named() → self::Class2
+    let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _(core::int field) → self::Class3
+    : self::Class3::field = field, super core::Object::•()
+    ;
+  static factory •(core::int field) → self::Class3
+    let Never #redirecting_factory = self::Class3::_ in invalid-expression;
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _([core::int? field = #C1]) → self::Class4
+    : self::Class4::field = field, super core::Object::•()
+    ;
+  static factory •([core::int? field = #C1]) → self::Class4
+    let Never #redirecting_factory = self::Class4::_ in invalid-expression;
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+  constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+    ;
+  static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    let Never #redirecting_factory = self::Class5::_ in invalid-expression;
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+  constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+    ;
+  static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    let Never #redirecting_factory = self::Class6::_ in invalid-expression;
+}
+static 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/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+    f3a(); // error
+       ^" in f3a{<inapplicable>}.();
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f3a(42, 87); // error
+       ^" in f3a{<inapplicable>}.(42, 87);
+  };
+  dynamic f3b = #C4;
+  dynamic c3b = f3b{dynamic}.call(87);
+  self::expect(87, c3b{dynamic}.field);
+  self::throws(() → dynamic => f3b{dynamic}.call());
+  self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+  ([core::int?]) → self::Class4 f4a = #C5;
+  self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+  self::expect(null, c4a.{self::Class4::field}{core::int?});
+  self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+  self::expect(42, c4b.{self::Class4::field}{core::int?});
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f4a(42, 87); // error
+       ^" in f4a{<inapplicable>}.(42, 87);
+  };
+  dynamic f4b = #C5;
+  self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+  (core::int, [core::int?]) → self::Class5 f5a = #C6;
+  self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+  self::expect(42, c5a.{self::Class5::field1}{core::int});
+  self::expect(null, c5a.{self::Class5::field2}{core::int?});
+  self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+  self::expect(87, c5b.{self::Class5::field1}{core::int});
+  self::expect(42, c5b.{self::Class5::field2}{core::int?});
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+    f5a(); // error
+       ^" in f5a{<inapplicable>}.();
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+    f5a(42, 87, 123); // error
+       ^" in f5a{<inapplicable>}.(42, 87, 123);
+  };
+  dynamic f5b = #C6;
+  self::throws(() → dynamic => f5b{dynamic}.call());
+  self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+  (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+  self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6a.{self::Class6::field1}{core::int});
+  self::expect(null, c6a.{self::Class6::field2}{core::int?});
+  self::expect(87, c6a.{self::Class6::field3}{core::int});
+  () → Null {
+    let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(); // error
+       ^" in f6a{<inapplicable>}.();
+    let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+    f6a(42); // error
+       ^" in f6a{<inapplicable>}.(42);
+    let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f6a(42, 87); // error
+       ^" in f6a{<inapplicable>}.(42, 87);
+    let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(field1: 87, field2: 87); // error
+       ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+  };
+  self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6b.{self::Class6::field1}{core::int});
+  self::expect(123, c6b.{self::Class6::field2}{core::int?});
+  self::expect(87, c6b.{self::Class6::field3}{core::int});
+  self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(87, c6c.{self::Class6::field1}{core::int});
+  self::expect(123, c6c.{self::Class6::field2}{core::int?});
+  self::expect(42, c6c.{self::Class6::field3}{core::int});
+  dynamic f6b = #C7;
+  self::throws(() → dynamic => f6b{dynamic}.call());
+  self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = null
+  #C2 = redirecting-factory-tearoff self::Class1::•
+  #C3 = redirecting-factory-tearoff self::Class2::named
+  #C4 = redirecting-factory-tearoff self::Class3::•
+  #C5 = redirecting-factory-tearoff self::Class4::•
+  #C6 = redirecting-factory-tearoff self::Class5::•
+  #C7 = redirecting-factory-tearoff self::Class6::•
+  #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline.expect
new file mode 100644
index 0000000..999b5d2
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline.expect
@@ -0,0 +1,45 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1 {
+  Class1._();
+  factory Class1() = Class1._;
+}
+
+class Class2 {
+  Class2._();
+  factory Class2.named() = Class2._;
+}
+
+testNoArgs() {}
+
+class Class3 {
+  final int field;
+  Class3._(this.field);
+  factory Class3(int field) = Class3._;
+}
+
+class Class4 {
+  final int? field;
+  Class4._([this.field]);
+  factory Class4([int? field]) = Class4._;
+}
+
+class Class5 {
+  final int field1;
+  final int? field2;
+  Class5._(this.field1, [this.field2]);
+  factory Class5(int field1, [int? field2]) = Class5._;
+}
+
+class Class6 {
+  final int field1;
+  final int? field2;
+  final int field3;
+  Class6._(this.field1, {this.field2, required this.field3});
+  factory Class6(int field1, {int? field2, required int field3}) = Class6._;
+}
+
+testArgs() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..edb4f68
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.textual_outline_modelled.expect
@@ -0,0 +1,43 @@
+class Class1 {
+  Class1._();
+  factory Class1() = Class1._;
+}
+
+class Class2 {
+  Class2._();
+  factory Class2.named() = Class2._;
+}
+
+class Class3 {
+  Class3._(this.field);
+  factory Class3(int field) = Class3._;
+  final int field;
+}
+
+class Class4 {
+  Class4._([this.field]);
+  factory Class4([int? field]) = Class4._;
+  final int? field;
+}
+
+class Class5 {
+  Class5._(this.field1, [this.field2]);
+  factory Class5(int field1, [int? field2]) = Class5._;
+  final int? field2;
+  final int field1;
+}
+
+class Class6 {
+  Class6._(this.field1, {this.field2, required this.field3});
+  factory Class6(int field1, {int? field2, required int field3}) = Class6._;
+  final int? field2;
+  final int field1;
+  final int field3;
+}
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+testArgs() {}
+testNoArgs() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.expect
new file mode 100644
index 0000000..f2dd642
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.expect
@@ -0,0 +1,236 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f3a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f4a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+//     f5a(42, 87, 123); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f6a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(field1: 87, field2: 87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static factory •() → self::Class1
+    let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+}
+class Class2 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static factory named() → self::Class2
+    let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _(core::int field) → self::Class3
+    : self::Class3::field = field, super core::Object::•()
+    ;
+  static factory •(core::int field) → self::Class3
+    let dynamic #redirecting_factory = self::Class3::_ in invalid-expression;
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _([core::int? field = #C1]) → self::Class4
+    : self::Class4::field = field, super core::Object::•()
+    ;
+  static factory •([core::int? field = #C1]) → self::Class4
+    let dynamic #redirecting_factory = self::Class4::_ in invalid-expression;
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+  constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+    ;
+  static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    let dynamic #redirecting_factory = self::Class5::_ in invalid-expression;
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+  constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+    ;
+  static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
+}
+static 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/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+    f3a(); // error
+       ^" in f3a{<inapplicable>}.();
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f3a(42, 87); // error
+       ^" in f3a{<inapplicable>}.(42, 87);
+  };
+  dynamic f3b = #C4;
+  dynamic c3b = f3b{dynamic}.call(87);
+  self::expect(87, c3b{dynamic}.field);
+  self::throws(() → dynamic => f3b{dynamic}.call());
+  self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+  ([core::int?]) → self::Class4 f4a = #C5;
+  self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+  self::expect(null, c4a.{self::Class4::field}{core::int?});
+  self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+  self::expect(42, c4b.{self::Class4::field}{core::int?});
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f4a(42, 87); // error
+       ^" in f4a{<inapplicable>}.(42, 87);
+  };
+  dynamic f4b = #C5;
+  self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+  (core::int, [core::int?]) → self::Class5 f5a = #C6;
+  self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+  self::expect(42, c5a.{self::Class5::field1}{core::int});
+  self::expect(null, c5a.{self::Class5::field2}{core::int?});
+  self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+  self::expect(87, c5b.{self::Class5::field1}{core::int});
+  self::expect(42, c5b.{self::Class5::field2}{core::int?});
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+    f5a(); // error
+       ^" in f5a{<inapplicable>}.();
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+    f5a(42, 87, 123); // error
+       ^" in f5a{<inapplicable>}.(42, 87, 123);
+  };
+  dynamic f5b = #C6;
+  self::throws(() → dynamic => f5b{dynamic}.call());
+  self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+  (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+  self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6a.{self::Class6::field1}{core::int});
+  self::expect(null, c6a.{self::Class6::field2}{core::int?});
+  self::expect(87, c6a.{self::Class6::field3}{core::int});
+  () → Null {
+    let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(); // error
+       ^" in f6a{<inapplicable>}.();
+    let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+    f6a(42); // error
+       ^" in f6a{<inapplicable>}.(42);
+    let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f6a(42, 87); // error
+       ^" in f6a{<inapplicable>}.(42, 87);
+    let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(field1: 87, field2: 87); // error
+       ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+  };
+  self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6b.{self::Class6::field1}{core::int});
+  self::expect(123, c6b.{self::Class6::field2}{core::int?});
+  self::expect(87, c6b.{self::Class6::field3}{core::int});
+  self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(87, c6c.{self::Class6::field1}{core::int});
+  self::expect(123, c6c.{self::Class6::field2}{core::int?});
+  self::expect(42, c6c.{self::Class6::field3}{core::int});
+  dynamic f6b = #C7;
+  self::throws(() → dynamic => f6b{dynamic}.call());
+  self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = null
+  #C2 = redirecting-factory-tearoff self::Class1::•
+  #C3 = redirecting-factory-tearoff self::Class2::named
+  #C4 = redirecting-factory-tearoff self::Class3::•
+  #C5 = redirecting-factory-tearoff self::Class4::•
+  #C6 = redirecting-factory-tearoff self::Class5::•
+  #C7 = redirecting-factory-tearoff self::Class6::•
+  #C8 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.outline.expect
new file mode 100644
index 0000000..44ac319
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.outline.expect
@@ -0,0 +1,64 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1
+    ;
+  static factory •() → self::Class1
+    let dynamic #redirecting_factory = self::Class1::_ in invalid-expression;
+}
+class Class2 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+  constructor _() → self::Class2
+    ;
+  static factory named() → self::Class2
+    let dynamic #redirecting_factory = self::Class2::_ in invalid-expression;
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _(core::int field) → self::Class3
+    ;
+  static factory •(core::int field) → self::Class3
+    let dynamic #redirecting_factory = self::Class3::_ in invalid-expression;
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _([core::int? field]) → self::Class4
+    ;
+  static factory •([core::int? field]) → self::Class4
+    let dynamic #redirecting_factory = self::Class4::_ in invalid-expression;
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+  constructor _(core::int field1, [core::int? field2]) → self::Class5
+    ;
+  static factory •(core::int field1, [core::int? field2]) → self::Class5
+    let dynamic #redirecting_factory = self::Class5::_ in invalid-expression;
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+  constructor _(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+    ;
+  static factory •(core::int field1, {core::int? field2, required core::int field3}) → self::Class6
+    let dynamic #redirecting_factory = self::Class6::_ in invalid-expression;
+}
+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/redirecting_factory_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.transformed.expect
new file mode 100644
index 0000000..ccaec42
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart.weak.transformed.expect
@@ -0,0 +1,236 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f3a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f4a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f5a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+// Try removing the extra positional arguments.
+//     f5a(42, 87, 123); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+//     f6a(42); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+// Try removing the extra positional arguments.
+//     f6a(42, 87); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f6a(field1: 87, field2: 87); // error
+//        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class1::•]/*isLegacy*/;
+  constructor _() → self::Class1
+    : super core::Object::•()
+    ;
+  static factory •() → self::Class1
+    let Never #redirecting_factory = self::Class1::_ in invalid-expression;
+}
+class Class2 extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[self::Class2::named]/*isLegacy*/;
+  constructor _() → self::Class2
+    : super core::Object::•()
+    ;
+  static factory named() → self::Class2
+    let Never #redirecting_factory = self::Class2::_ in invalid-expression;
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class3::•]/*isLegacy*/;
+  constructor _(core::int field) → self::Class3
+    : self::Class3::field = field, super core::Object::•()
+    ;
+  static factory •(core::int field) → self::Class3
+    let Never #redirecting_factory = self::Class3::_ in invalid-expression;
+}
+class Class4 extends core::Object {
+  final field core::int? field;
+  static final field dynamic _redirecting# = <dynamic>[self::Class4::•]/*isLegacy*/;
+  constructor _([core::int? field = #C1]) → self::Class4
+    : self::Class4::field = field, super core::Object::•()
+    ;
+  static factory •([core::int? field = #C1]) → self::Class4
+    let Never #redirecting_factory = self::Class4::_ in invalid-expression;
+}
+class Class5 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  static final field dynamic _redirecting# = <dynamic>[self::Class5::•]/*isLegacy*/;
+  constructor _(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    : self::Class5::field1 = field1, self::Class5::field2 = field2, super core::Object::•()
+    ;
+  static factory •(core::int field1, [core::int? field2 = #C1]) → self::Class5
+    let Never #redirecting_factory = self::Class5::_ in invalid-expression;
+}
+class Class6 extends core::Object {
+  final field core::int field1;
+  final field core::int? field2;
+  final field core::int field3;
+  static final field dynamic _redirecting# = <dynamic>[self::Class6::•]/*isLegacy*/;
+  constructor _(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    : self::Class6::field1 = field1, self::Class6::field2 = field2, self::Class6::field3 = field3, super core::Object::•()
+    ;
+  static factory •(core::int field1, {core::int? field2 = #C1, required core::int field3 = #C1}) → self::Class6
+    let Never #redirecting_factory = self::Class6::_ in invalid-expression;
+}
+static 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/redirecting_factory_tear_off.dart:82:8: Error: Too few positional arguments: 1 required, 0 given.
+    f3a(); // error
+       ^" in f3a{<inapplicable>}.();
+    let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:83:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f3a(42, 87); // error
+       ^" in f3a{<inapplicable>}.(42, 87);
+  };
+  dynamic f3b = #C4;
+  dynamic c3b = f3b{dynamic}.call(87);
+  self::expect(87, c3b{dynamic}.field);
+  self::throws(() → dynamic => f3b{dynamic}.call());
+  self::throws(() → dynamic => f3b{dynamic}.call(42, 87));
+  ([core::int?]) → self::Class4 f4a = #C5;
+  self::Class4 c4a = f4a(){([core::int?]) → self::Class4};
+  self::expect(null, c4a.{self::Class4::field}{core::int?});
+  self::Class4 c4b = f4a(42){([core::int?]) → self::Class4};
+  self::expect(42, c4b.{self::Class4::field}{core::int?});
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:98:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f4a(42, 87); // error
+       ^" in f4a{<inapplicable>}.(42, 87);
+  };
+  dynamic f4b = #C5;
+  self::throws(() → dynamic => f4b{dynamic}.call(42, 87));
+  (core::int, [core::int?]) → self::Class5 f5a = #C6;
+  self::Class5 c5a = f5a(42){(core::int, [core::int?]) → self::Class5};
+  self::expect(42, c5a.{self::Class5::field1}{core::int});
+  self::expect(null, c5a.{self::Class5::field2}{core::int?});
+  self::Class5 c5b = f5a(87, 42){(core::int, [core::int?]) → self::Class5};
+  self::expect(87, c5b.{self::Class5::field1}{core::int});
+  self::expect(42, c5b.{self::Class5::field2}{core::int?});
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:112:8: Error: Too few positional arguments: 1 required, 0 given.
+    f5a(); // error
+       ^" in f5a{<inapplicable>}.();
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:113:8: Error: Too many positional arguments: 2 allowed, but 3 found.
+Try removing the extra positional arguments.
+    f5a(42, 87, 123); // error
+       ^" in f5a{<inapplicable>}.(42, 87, 123);
+  };
+  dynamic f5b = #C6;
+  self::throws(() → dynamic => f5b{dynamic}.call());
+  self::throws(() → dynamic => f5b{dynamic}.call(42, 87, 123));
+  (core::int, {field2: core::int?, required field3: core::int}) → self::Class6 f6a = #C7;
+  self::Class6 c6a = f6a(42, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6a.{self::Class6::field1}{core::int});
+  self::expect(null, c6a.{self::Class6::field2}{core::int?});
+  self::expect(87, c6a.{self::Class6::field3}{core::int});
+  () → Null {
+    let final Never #t6 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:125:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(); // error
+       ^" in f6a{<inapplicable>}.();
+    let final Never #t7 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:126:8: Error: Required named parameter 'field3' must be provided.
+    f6a(42); // error
+       ^" in f6a{<inapplicable>}.(42);
+    let final Never #t8 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:127:8: Error: Too many positional arguments: 1 allowed, but 2 found.
+Try removing the extra positional arguments.
+    f6a(42, 87); // error
+       ^" in f6a{<inapplicable>}.(42, 87);
+    let final Never #t9 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/redirecting_factory_tear_off.dart:128:8: Error: Too few positional arguments: 1 required, 0 given.
+    f6a(field1: 87, field2: 87); // error
+       ^" in f6a{<inapplicable>}.(field1: 87, field2: 87);
+  };
+  self::Class6 c6b = f6a(42, field2: 123, field3: 87){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(42, c6b.{self::Class6::field1}{core::int});
+  self::expect(123, c6b.{self::Class6::field2}{core::int?});
+  self::expect(87, c6b.{self::Class6::field3}{core::int});
+  self::Class6 c6c = f6a(87, field3: 42, field2: 123){(core::int, {field2: core::int?, required field3: core::int}) → self::Class6};
+  self::expect(87, c6c.{self::Class6::field1}{core::int});
+  self::expect(123, c6c.{self::Class6::field2}{core::int?});
+  self::expect(42, c6c.{self::Class6::field3}{core::int});
+  dynamic f6b = #C7;
+  self::throws(() → dynamic => f6b{dynamic}.call());
+  self::throws(() → dynamic => f6b{dynamic}.call(42), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(42, 87), inSoundModeOnly: true);
+  self::throws(() → dynamic => f6b{dynamic}.call(field1: 87, field2: 87));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C8}) → dynamic {
+  try {
+    f(){() → dynamic};
+  }
+  on core::Object catch(final core::Object e) {
+    core::print("Thrown: ${e}");
+    return;
+  }
+  if(!self::inSoundMode && inSoundModeOnly) {
+    return;
+  }
+  throw "Expected exception";
+}
+
+constants  {
+  #C1 = null
+  #C2 = redirecting-factory-tearoff self::Class1::•
+  #C3 = redirecting-factory-tearoff self::Class2::named
+  #C4 = redirecting-factory-tearoff self::Class3::•
+  #C5 = redirecting-factory-tearoff self::Class4::•
+  #C6 = redirecting-factory-tearoff self::Class5::•
+  #C7 = redirecting-factory-tearoff self::Class6::•
+  #C8 = false
+}
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index cfb0715..d6b5325 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -9,6 +9,7 @@
 dart2js/late_statics: SemiFuzzFailure # dartbug.com/45854
 
 constructor_tearoffs/redirecting_constructors: RuntimeError
+constructor_tearoffs/redirecting_factory_tear_off: RuntimeError
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
 extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 82cb3b9..81314ea 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -12,7 +12,8 @@
 constructor_tearoffs/instantiation: TextSerializationFailure
 constructor_tearoffs/nongeneric_tearoff_with_context: TextSerializationFailure
 constructor_tearoffs/nongeneric_tearoff_without_context: TextSerializationFailure
-constructor_tearoffs/redirecting_constructors: RuntimeError
+constructor_tearoffs/redirecting_constructors: TextSerializationFailure
+constructor_tearoffs/redirecting_factory_tear_off: TextSerializationFailure
 constructor_tearoffs/typedef_tearoffs: TextSerializationFailure
 constructor_tearoffs/unnamed_constructor: TextSerializationFailure
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 82c2ba6..f69c2ec 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -12,6 +12,7 @@
 dart2js/late_statics: SemiFuzzFailure # dartbug.com/45854
 
 constructor_tearoffs/redirecting_constructors: RuntimeError
+constructor_tearoffs/redirecting_factory_tear_off: RuntimeError
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
 extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index b6b135c..06cd777 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -373,6 +373,8 @@
         return _readStaticTearOffConstant();
       case ConstantTag.ConstructorTearOffConstant:
         return _readConstructorTearOffConstant();
+      case ConstantTag.RedirectingFactoryTearOffConstant:
+        return _readRedirectingFactoryTearOffConstant();
       case ConstantTag.TypeLiteralConstant:
         return _readTypeLiteralConstant();
       case ConstantTag.UnevaluatedConstant:
@@ -470,6 +472,11 @@
     return new ConstructorTearOffConstant.byReference(reference);
   }
 
+  Constant _readRedirectingFactoryTearOffConstant() {
+    final Reference reference = readNonNullCanonicalNameReference().reference;
+    return new RedirectingFactoryTearOffConstant.byReference(reference);
+  }
+
   Constant _readTypeLiteralConstant() {
     final DartType type = readDartType();
     return new TypeLiteralConstant(type);
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index 837bfc7..b2666d8 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -2048,6 +2048,10 @@
     writeMemberReferenceFromReference(node.targetReference);
   }
 
+  visitRedirectingFactoryTearOff(RedirectingFactoryTearOff node) {
+    writeMemberReferenceFromReference(node.targetReference);
+  }
+
   visitTypedefTearOff(TypedefTearOff node) {
     writeTypeParameterList(node.typeParameters);
     state = SYMBOL;
@@ -2721,6 +2725,17 @@
     endLine();
   }
 
+  visitRedirectingFactoryTearOffConstant(
+      RedirectingFactoryTearOffConstant node) {
+    writeIndentation();
+    writeConstantReference(node);
+    writeSpaced('=');
+    writeWord('redirecting-factory-tearoff');
+    writeSpace();
+    writeMemberReferenceFromReference(node.targetReference);
+    endLine();
+  }
+
   defaultNode(Node node) {
     write('<${node.runtimeType}>');
   }
diff --git a/tools/VERSION b/tools/VERSION
index 46fd44a..5b933e1 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 338
+PRERELEASE 339
 PRERELEASE_PATCH 0
\ No newline at end of file