[cfe] Handle lowered tear offs from dill

Change-Id: I6cf6e2a265a84c5ab84bce3385b4112f6bd688ea
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/207020
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
index fe9e63c..1462633 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
@@ -72,39 +72,42 @@
   @override
   Class get actualCls => cls;
 
-  void addMember(Member member) {
-    if (member is Field) {
-      DillFieldBuilder builder = new DillFieldBuilder(member, this);
-      String name = member.name.text;
-      scopeBuilder.addMember(name, builder);
-    } else if (member is Procedure) {
-      String name = member.name.text;
-      switch (member.kind) {
-        case ProcedureKind.Factory:
-          constructorScopeBuilder.addMember(
-              name, new DillFactoryBuilder(member, this));
-          break;
-        case ProcedureKind.Setter:
-          scopeBuilder.addSetter(name, new DillSetterBuilder(member, this));
-          break;
-        case ProcedureKind.Getter:
-          scopeBuilder.addMember(name, new DillGetterBuilder(member, this));
-          break;
-        case ProcedureKind.Operator:
-          scopeBuilder.addMember(name, new DillOperatorBuilder(member, this));
-          break;
-        case ProcedureKind.Method:
-          scopeBuilder.addMember(name, new DillMethodBuilder(member, this));
-          break;
-      }
-    } else if (member is Constructor) {
-      DillConstructorBuilder builder =
-          new DillConstructorBuilder(member, null, this);
-      String name = member.name.text;
-      constructorScopeBuilder.addMember(name, builder);
-    } else {
-      throw new UnsupportedError(
-          "Unexpected class member ${member} (${member.runtimeType})");
+  void addField(Field field) {
+    DillFieldBuilder builder = new DillFieldBuilder(field, this);
+    String name = field.name.text;
+    scopeBuilder.addMember(name, builder);
+  }
+
+  void addConstructor(Constructor constructor, Procedure? constructorTearOff) {
+    DillConstructorBuilder builder =
+        new DillConstructorBuilder(constructor, constructorTearOff, this);
+    String name = constructor.name.text;
+    constructorScopeBuilder.addMember(name, builder);
+  }
+
+  void addFactory(Procedure factory, Procedure? factoryTearOff) {
+    String name = factory.name.text;
+    constructorScopeBuilder.addMember(
+        name, new DillFactoryBuilder(factory, factoryTearOff, this));
+  }
+
+  void addProcedure(Procedure procedure) {
+    String name = procedure.name.text;
+    switch (procedure.kind) {
+      case ProcedureKind.Factory:
+        throw new UnsupportedError("Use addFactory for adding factories");
+      case ProcedureKind.Setter:
+        scopeBuilder.addSetter(name, new DillSetterBuilder(procedure, this));
+        break;
+      case ProcedureKind.Getter:
+        scopeBuilder.addMember(name, new DillGetterBuilder(procedure, this));
+        break;
+      case ProcedureKind.Operator:
+        scopeBuilder.addMember(name, new DillOperatorBuilder(procedure, this));
+        break;
+      case ProcedureKind.Method:
+        scopeBuilder.addMember(name, new DillMethodBuilder(procedure, this));
+        break;
     }
   }
 
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
index c899e3df..e52ce9a 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
@@ -10,6 +10,7 @@
     show
         Class,
         ConstantExpression,
+        Constructor,
         DartType,
         DynamicType,
         Expression,
@@ -48,6 +49,7 @@
         templateTypeNotFound,
         templateUnspecified;
 
+import '../kernel/constructor_tearoff_lowering.dart';
 import '../kernel/redirecting_factory_body.dart'
     show RedirectingFactoryBody, isRedirectingFactoryField;
 
@@ -167,10 +169,28 @@
   }
 
   void addClass(Class cls) {
-    DillClassBuilder classBulder = new DillClassBuilder(cls, this);
-    addBuilder(cls.name, classBulder, cls.fileOffset);
-    cls.procedures.forEach(classBulder.addMember);
-    cls.constructors.forEach(classBulder.addMember);
+    DillClassBuilder classBuilder = new DillClassBuilder(cls, this);
+    addBuilder(cls.name, classBuilder, cls.fileOffset);
+    Map<String, Procedure> tearOffs = {};
+    List<Procedure> nonTearOffs = [];
+    for (Procedure procedure in cls.procedures) {
+      String? name = extractConstructorNameFromTearOff(procedure.name);
+      if (name != null) {
+        tearOffs[name] = procedure;
+      } else {
+        nonTearOffs.add(procedure);
+      }
+    }
+    for (Procedure procedure in nonTearOffs) {
+      if (procedure.kind == ProcedureKind.Factory) {
+        classBuilder.addFactory(procedure, tearOffs[procedure.name.text]);
+      } else {
+        classBuilder.addProcedure(procedure);
+      }
+    }
+    for (Constructor constructor in cls.constructors) {
+      classBuilder.addConstructor(constructor, tearOffs[constructor.name.text]);
+    }
     for (Field field in cls.fields) {
       if (isRedirectingFactoryField(field)) {
         ListLiteral initializer = field.initializer as ListLiteral;
@@ -179,7 +199,7 @@
           RedirectingFactoryBody.restoreFromDill(get.target as Procedure);
         }
       } else {
-        classBulder.addMember(field);
+        classBuilder.addField(field);
       }
     }
   }
@@ -215,10 +235,6 @@
         addBuilder(name, new DillFieldBuilder(member, this), member.fileOffset);
       } else if (member is Procedure) {
         switch (member.kind) {
-          case ProcedureKind.Factory:
-            addBuilder(
-                name, new DillFactoryBuilder(member, this), member.fileOffset);
-            break;
           case ProcedureKind.Setter:
             addBuilder(
                 name, new DillSetterBuilder(member, this), member.fileOffset);
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
index d076161..54a3158 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
@@ -188,13 +188,15 @@
 
 class DillFactoryBuilder extends DillMemberBuilder {
   final Procedure procedure;
+  final Procedure? _factoryTearOff;
 
-  DillFactoryBuilder(this.procedure, Builder parent) : super(procedure, parent);
+  DillFactoryBuilder(this.procedure, this._factoryTearOff, Builder parent)
+      : super(procedure, parent);
 
   Member get member => procedure;
 
   @override
-  Member? get readTarget => null;
+  Member? get readTarget => _factoryTearOff ?? procedure;
 
   @override
   Member? get writeTarget => null;
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 d5c0140..f9863ea 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
@@ -8,14 +8,36 @@
 import '../builder/member_builder.dart';
 import '../source/source_library_builder.dart';
 
-/// Creates the synthesized name to use for the lowering of a generative
-/// constructor by the given [constructorName] in [library].
-Name constructorTearOffName(String constructorName, Library library) {
+const String _constructorTearOffNamePrefix = '_#';
+const String _constructorTearOffNameSuffix = '#tearOff';
+
+/// Creates the synthesized name to use for the lowering of the tear off of a
+/// constructor or factory by the given [name] in [library].
+Name constructorTearOffName(String name, Library library) {
   return new Name(
-      '_#${constructorName.isEmpty ? 'new' : constructorName}#tearOff',
+      '$_constructorTearOffNamePrefix'
+      '${name.isEmpty ? 'new' : name}'
+      '$_constructorTearOffNameSuffix',
       library);
 }
 
+/// Returns the name of the corresponding constructor or factory if [name] is
+/// the synthesized name of a lowering of the tear off of a constructor or
+/// factory. Returns `null` otherwise.
+String? extractConstructorNameFromTearOff(Name name) {
+  if (name.text.startsWith(_constructorTearOffNamePrefix) &&
+      name.text.endsWith(_constructorTearOffNameSuffix) &&
+      name.text.length >
+          _constructorTearOffNamePrefix.length +
+              _constructorTearOffNameSuffix.length) {
+    String text = name.text
+        .substring(0, name.text.length - _constructorTearOffNameSuffix.length);
+    text = text.substring(_constructorTearOffNamePrefix.length);
+    return text == 'new' ? '' : text;
+  }
+  return null;
+}
+
 /// Creates the [Procedure] for the lowering of a generative constructor of
 /// the given [name] in [compilationUnit].
 ///
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 6f4a1af..07ed5c1 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -142,7 +142,6 @@
 bslash
 buffered
 builder`s
-bulder
 bulk
 bump
 bypassing
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index c241a42..4d4aa59 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -121,9 +121,13 @@
 c3d
 c4a
 c4b
+c4c
+c4d
 c59cdee365b94ce066344840f9e3412d642019b
 c5a
 c5b
+c5c
+c5d
 c6a
 c6b
 c6c
@@ -331,6 +335,7 @@
 f4
 f4a
 f4b
+f4c
 f5a
 f5b
 f6a
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart
new file mode 100644
index 0000000..e9ac4b7
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart
@@ -0,0 +1,107 @@
+// 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 'main_lib.dart';
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+  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));
+
+  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(true, c4a is Class4<dynamic>);
+  expect(false, c4a is Class4<int>);
+  var c4b = f4a<int>();
+  expect(true, c4b is Class4<int>);
+  expect(false, c4b is Class4<String>);
+  () {
+    f4a<int, String>(); // error
+  };
+
+  var f4b = f4a<int>;
+  var c4c = f4b();
+  expect(true, c4c is Class4<int>);
+  expect(false, c4c is Class4<String>);
+  () {
+    f4b<int>(); // error
+  };
+
+  dynamic f4c = Class4.new;
+  var c4d = f4c();
+  expect(true, c4d is Class4<dynamic>);
+  expect(false, c4d is Class4<int>);
+  throws(() => f4c<int, String>());
+
+  var f5a = Class5.new;
+  var c5a = f5a();
+  expect(true, c5a is Class5<num>);
+  expect(false, c5a is Class5<int>);
+  var c5b = f5a<int>();
+  expect(true, c5b is Class5<int>);
+  expect(false, c5b is Class5<double>);
+  () {
+    f5a<String>(); // error
+    f5a<int, String>(); // error
+  };
+
+  dynamic f5b = Class5.new;
+  var c5c = f5b();
+  expect(true, c5c is Class5<num>);
+  expect(false, c5c is Class5<int>);
+  var c5d = f5b<int>();
+  expect(true, c5d is Class5<int>);
+  expect(false, c5d is Class5<double>);
+  throws(() => f5b<String>());
+  throws(() => f5b<int, String>());
+}
+
+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/from_dill/main.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.expect
new file mode 100644
index 0000000..d1c7116
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.expect
@@ -0,0 +1,193 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35: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/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+//     f4a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+//     f4b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:77: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.
+//     f5a<String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+//     f5a<int, String>(); // error
+//        ^
+//
+import self as self;
+import "main_lib.dart" as mai;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///main_lib.dart";
+
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  () → mai::Class1 f1a = #C1;
+  mai::Class1 c1a = f1a(){() → mai::Class1};
+  self::expect(true, c1a is{ForNonNullableByDefault} mai::Class1);
+  dynamic f1b = #C1;
+  dynamic c1b = f1b{dynamic}.call();
+  self::expect(true, c1b is{ForNonNullableByDefault} mai::Class1);
+  self::expect(true, core::identical(f1a, f1b));
+  () → mai::Class2 f2a = #C2;
+  mai::Class2 c2a = f2a(){() → mai::Class2};
+  self::expect(true, c2a is{ForNonNullableByDefault} mai::Class2);
+  dynamic f2b = #C2;
+  dynamic c2b = f2b{dynamic}.call();
+  self::expect(true, c2b is{ForNonNullableByDefault} mai::Class2);
+  self::expect(true, core::identical(f2a, f2b));
+  (core::int) → mai::Class3 f3a = #C3;
+  mai::Class3 c3a = f3a(42){(core::int) → mai::Class3};
+  self::expect(42, c3a.{mai::Class3::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34: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/from_dill/main.dart:35: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 = #C3;
+  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));
+  <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C4;
+  mai::Class4<dynamic> c4a = f4a<dynamic>(){() → mai::Class4<dynamic>};
+  self::expect(true, c4a is{ForNonNullableByDefault} mai::Class4<dynamic>);
+  self::expect(false, c4a is{ForNonNullableByDefault} mai::Class4<core::int>);
+  mai::Class4<core::int> c4b = f4a<core::int>(){() → mai::Class4<core::int>};
+  self::expect(true, c4b is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::expect(false, c4b is{ForNonNullableByDefault} mai::Class4<core::String>);
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+    f4a<int, String>(); // error
+       ^" in f4a{<inapplicable>}.<core::int, core::String>();
+  };
+  () → mai::Class4<core::int> f4b = f4a<core::int>;
+  mai::Class4<core::int> c4c = f4b(){() → mai::Class4<core::int>};
+  self::expect(true, c4c is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::expect(false, c4c is{ForNonNullableByDefault} mai::Class4<core::String>);
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+    f4b<int>(); // error
+       ^" in f4b{<inapplicable>}.<core::int>();
+  };
+  dynamic f4c = #C4;
+  dynamic c4d = f4c{dynamic}.call();
+  self::expect(true, c4d is{ForNonNullableByDefault} mai::Class4<dynamic>);
+  self::expect(false, c4d is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::throws(() → dynamic => f4c{dynamic}.call<core::int, core::String>());
+  <T extends core::num>() → mai::Class5<T> f5a = #C5;
+  mai::Class5<core::num> c5a = f5a<core::num>(){() → mai::Class5<core::num>};
+  self::expect(true, c5a is{ForNonNullableByDefault} mai::Class5<core::num>);
+  self::expect(false, c5a is{ForNonNullableByDefault} mai::Class5<core::int>);
+  mai::Class5<core::int> c5b = f5a<core::int>(){() → mai::Class5<core::int>};
+  self::expect(true, c5b is{ForNonNullableByDefault} mai::Class5<core::int>);
+  self::expect(false, c5b is{ForNonNullableByDefault} mai::Class5<core::double>);
+  () → Null {
+    f5a<core::String>(){() → mai::Class5<core::String>};
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+    f5a<int, String>(); // error
+       ^" in f5a{<inapplicable>}.<core::int, core::String>();
+  };
+  dynamic f5b = #C5;
+  dynamic c5c = f5b{dynamic}.call();
+  self::expect(true, c5c is{ForNonNullableByDefault} mai::Class5<core::num>);
+  self::expect(false, c5c is{ForNonNullableByDefault} mai::Class5<core::int>);
+  dynamic c5d = f5b{dynamic}.call<core::int>();
+  self::expect(true, c5d is{ForNonNullableByDefault} mai::Class5<core::int>);
+  self::expect(false, c5d is{ForNonNullableByDefault} mai::Class5<core::double>);
+  self::throws(() → dynamic => f5b{dynamic}.call<core::String>());
+  self::throws(() → dynamic => f5b{dynamic}.call<core::int, core::String>());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C6}) → 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";
+}
+
+library /*isNonNullableByDefault*/;
+import self as mai;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → mai::Class1
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff() → mai::Class1
+    return new mai::Class1::•();
+}
+class Class2 extends core::Object {
+  constructor named() → mai::Class2
+    : super core::Object::•()
+    ;
+  static method _#named#tearOff() → mai::Class2
+    return new mai::Class2::named();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  constructor •(core::int field) → mai::Class3
+    : mai::Class3::field = field, super core::Object::•()
+    ;
+  static method _#new#tearOff(core::int field) → mai::Class3
+    return new mai::Class3::•(field);
+}
+class Class4<T extends core::Object? = dynamic> extends core::Object {
+  constructor _() → mai::Class4<mai::Class4::T%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#_#tearOff::T%>
+    return new mai::Class4::_<mai::Class4::_#_#tearOff::T%>();
+  static factory •<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::•::T%>
+    return new mai::Class4::_<mai::Class4::•::T%>();
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#new#tearOff::T%>
+    return mai::Class4::•<mai::Class4::_#new#tearOff::T%>();
+}
+class Class5<T extends core::num> extends core::Object {
+  constructor _() → mai::Class5<mai::Class5::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::num>() → mai::Class5<mai::Class5::_#_#tearOff::T>
+    return new mai::Class5::_<mai::Class5::_#_#tearOff::T>();
+  static factory •<T extends core::num>() → mai::Class5<mai::Class5::•::T>
+    return new mai::Class5::_<mai::Class5::•::T>();
+  static method _#new#tearOff<T extends core::num>() → mai::Class5<mai::Class5::_#new#tearOff::T>
+    return mai::Class5::•<mai::Class5::_#new#tearOff::T>();
+}
+
+constants  {
+  #C1 = tearoff mai::Class1::_#new#tearOff
+  #C2 = tearoff mai::Class2::_#named#tearOff
+  #C3 = tearoff mai::Class3::_#new#tearOff
+  #C4 = tearoff mai::Class4::_#new#tearOff
+  #C5 = tearoff mai::Class5::_#new#tearOff
+  #C6 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.transformed.expect
new file mode 100644
index 0000000..f476c02
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.strong.transformed.expect
@@ -0,0 +1,193 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35: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/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+//     f4a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+//     f4b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:77: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.
+//     f5a<String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+//     f5a<int, String>(); // error
+//        ^
+//
+import self as self;
+import "main_lib.dart" as mai;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///main_lib.dart";
+
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  () → mai::Class1 f1a = #C1;
+  mai::Class1 c1a = f1a(){() → mai::Class1};
+  self::expect(true, c1a is{ForNonNullableByDefault} mai::Class1);
+  dynamic f1b = #C1;
+  dynamic c1b = f1b{dynamic}.call();
+  self::expect(true, c1b is{ForNonNullableByDefault} mai::Class1);
+  self::expect(true, core::identical(f1a, f1b));
+  () → mai::Class2 f2a = #C2;
+  mai::Class2 c2a = f2a(){() → mai::Class2};
+  self::expect(true, c2a is{ForNonNullableByDefault} mai::Class2);
+  dynamic f2b = #C2;
+  dynamic c2b = f2b{dynamic}.call();
+  self::expect(true, c2b is{ForNonNullableByDefault} mai::Class2);
+  self::expect(true, core::identical(f2a, f2b));
+  (core::int) → mai::Class3 f3a = #C3;
+  mai::Class3 c3a = f3a(42){(core::int) → mai::Class3};
+  self::expect(42, c3a.{mai::Class3::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34: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/from_dill/main.dart:35: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 = #C3;
+  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));
+  <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C4;
+  mai::Class4<dynamic> c4a = f4a<dynamic>(){() → mai::Class4<dynamic>};
+  self::expect(true, c4a is{ForNonNullableByDefault} mai::Class4<dynamic>);
+  self::expect(false, c4a is{ForNonNullableByDefault} mai::Class4<core::int>);
+  mai::Class4<core::int> c4b = f4a<core::int>(){() → mai::Class4<core::int>};
+  self::expect(true, c4b is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::expect(false, c4b is{ForNonNullableByDefault} mai::Class4<core::String>);
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+    f4a<int, String>(); // error
+       ^" in f4a{<inapplicable>}.<core::int, core::String>();
+  };
+  () → mai::Class4<core::int> f4b = f4a<core::int>;
+  mai::Class4<core::int> c4c = f4b(){() → mai::Class4<core::int>};
+  self::expect(true, c4c is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::expect(false, c4c is{ForNonNullableByDefault} mai::Class4<core::String>);
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+    f4b<int>(); // error
+       ^" in f4b{<inapplicable>}.<core::int>();
+  };
+  dynamic f4c = #C4;
+  dynamic c4d = f4c{dynamic}.call();
+  self::expect(true, c4d is{ForNonNullableByDefault} mai::Class4<dynamic>);
+  self::expect(false, c4d is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::throws(() → dynamic => f4c{dynamic}.call<core::int, core::String>());
+  <T extends core::num>() → mai::Class5<T> f5a = #C5;
+  mai::Class5<core::num> c5a = f5a<core::num>(){() → mai::Class5<core::num>};
+  self::expect(true, c5a is{ForNonNullableByDefault} mai::Class5<core::num>);
+  self::expect(false, c5a is{ForNonNullableByDefault} mai::Class5<core::int>);
+  mai::Class5<core::int> c5b = f5a<core::int>(){() → mai::Class5<core::int>};
+  self::expect(true, c5b is{ForNonNullableByDefault} mai::Class5<core::int>);
+  self::expect(false, c5b is{ForNonNullableByDefault} mai::Class5<core::double>);
+  () → Null {
+    f5a<core::String>(){() → mai::Class5<core::String>};
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+    f5a<int, String>(); // error
+       ^" in f5a{<inapplicable>}.<core::int, core::String>();
+  };
+  dynamic f5b = #C5;
+  dynamic c5c = f5b{dynamic}.call();
+  self::expect(true, c5c is{ForNonNullableByDefault} mai::Class5<core::num>);
+  self::expect(false, c5c is{ForNonNullableByDefault} mai::Class5<core::int>);
+  dynamic c5d = f5b{dynamic}.call<core::int>();
+  self::expect(true, c5d is{ForNonNullableByDefault} mai::Class5<core::int>);
+  self::expect(false, c5d is{ForNonNullableByDefault} mai::Class5<core::double>);
+  self::throws(() → dynamic => f5b{dynamic}.call<core::String>());
+  self::throws(() → dynamic => f5b{dynamic}.call<core::int, core::String>());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C6}) → 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";
+}
+
+library /*isNonNullableByDefault*/;
+import self as mai;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → mai::Class1
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff() → mai::Class1
+    return new mai::Class1::•();
+}
+class Class2 extends core::Object {
+  constructor named() → mai::Class2
+    : super core::Object::•()
+    ;
+  static method _#named#tearOff() → mai::Class2
+    return new mai::Class2::named();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  constructor •(core::int field) → mai::Class3
+    : mai::Class3::field = field, super core::Object::•()
+    ;
+  static method _#new#tearOff(core::int field) → mai::Class3
+    return new mai::Class3::•(field);
+}
+class Class4<T extends core::Object? = dynamic> extends core::Object {
+  constructor _() → mai::Class4<mai::Class4::T%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#_#tearOff::T%>
+    return new mai::Class4::_<mai::Class4::_#_#tearOff::T%>();
+  static factory •<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::•::T%>
+    return new mai::Class4::_<mai::Class4::•::T%>();
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#new#tearOff::T%>
+    return mai::Class4::•<mai::Class4::_#new#tearOff::T%>();
+}
+class Class5<T extends core::num> extends core::Object {
+  constructor _() → mai::Class5<mai::Class5::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::num>() → mai::Class5<mai::Class5::_#_#tearOff::T>
+    return new mai::Class5::_<mai::Class5::_#_#tearOff::T>();
+  static factory •<T extends core::num>() → mai::Class5<mai::Class5::•::T>
+    return new mai::Class5::_<mai::Class5::•::T>();
+  static method _#new#tearOff<T extends core::num>() → mai::Class5<mai::Class5::_#new#tearOff::T>
+    return mai::Class5::•<mai::Class5::_#new#tearOff::T>();
+}
+
+constants  {
+  #C1 = tearoff mai::Class1::_#new#tearOff
+  #C2 = tearoff mai::Class2::_#named#tearOff
+  #C3 = tearoff mai::Class3::_#new#tearOff
+  #C4 = tearoff mai::Class4::_#new#tearOff
+  #C5 = tearoff mai::Class5::_#new#tearOff
+  #C6 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.textual_outline.expect
new file mode 100644
index 0000000..4166ca7
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.textual_outline.expect
@@ -0,0 +1,6 @@
+import 'main_lib.dart';
+
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..26f0c41
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.textual_outline_modelled.expect
@@ -0,0 +1,6 @@
+import 'main_lib.dart';
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.expect
new file mode 100644
index 0000000..d1c7116
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.expect
@@ -0,0 +1,193 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35: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/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+//     f4a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+//     f4b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:77: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.
+//     f5a<String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+//     f5a<int, String>(); // error
+//        ^
+//
+import self as self;
+import "main_lib.dart" as mai;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///main_lib.dart";
+
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  () → mai::Class1 f1a = #C1;
+  mai::Class1 c1a = f1a(){() → mai::Class1};
+  self::expect(true, c1a is{ForNonNullableByDefault} mai::Class1);
+  dynamic f1b = #C1;
+  dynamic c1b = f1b{dynamic}.call();
+  self::expect(true, c1b is{ForNonNullableByDefault} mai::Class1);
+  self::expect(true, core::identical(f1a, f1b));
+  () → mai::Class2 f2a = #C2;
+  mai::Class2 c2a = f2a(){() → mai::Class2};
+  self::expect(true, c2a is{ForNonNullableByDefault} mai::Class2);
+  dynamic f2b = #C2;
+  dynamic c2b = f2b{dynamic}.call();
+  self::expect(true, c2b is{ForNonNullableByDefault} mai::Class2);
+  self::expect(true, core::identical(f2a, f2b));
+  (core::int) → mai::Class3 f3a = #C3;
+  mai::Class3 c3a = f3a(42){(core::int) → mai::Class3};
+  self::expect(42, c3a.{mai::Class3::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34: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/from_dill/main.dart:35: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 = #C3;
+  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));
+  <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C4;
+  mai::Class4<dynamic> c4a = f4a<dynamic>(){() → mai::Class4<dynamic>};
+  self::expect(true, c4a is{ForNonNullableByDefault} mai::Class4<dynamic>);
+  self::expect(false, c4a is{ForNonNullableByDefault} mai::Class4<core::int>);
+  mai::Class4<core::int> c4b = f4a<core::int>(){() → mai::Class4<core::int>};
+  self::expect(true, c4b is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::expect(false, c4b is{ForNonNullableByDefault} mai::Class4<core::String>);
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+    f4a<int, String>(); // error
+       ^" in f4a{<inapplicable>}.<core::int, core::String>();
+  };
+  () → mai::Class4<core::int> f4b = f4a<core::int>;
+  mai::Class4<core::int> c4c = f4b(){() → mai::Class4<core::int>};
+  self::expect(true, c4c is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::expect(false, c4c is{ForNonNullableByDefault} mai::Class4<core::String>);
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+    f4b<int>(); // error
+       ^" in f4b{<inapplicable>}.<core::int>();
+  };
+  dynamic f4c = #C4;
+  dynamic c4d = f4c{dynamic}.call();
+  self::expect(true, c4d is{ForNonNullableByDefault} mai::Class4<dynamic>);
+  self::expect(false, c4d is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::throws(() → dynamic => f4c{dynamic}.call<core::int, core::String>());
+  <T extends core::num>() → mai::Class5<T> f5a = #C5;
+  mai::Class5<core::num> c5a = f5a<core::num>(){() → mai::Class5<core::num>};
+  self::expect(true, c5a is{ForNonNullableByDefault} mai::Class5<core::num>);
+  self::expect(false, c5a is{ForNonNullableByDefault} mai::Class5<core::int>);
+  mai::Class5<core::int> c5b = f5a<core::int>(){() → mai::Class5<core::int>};
+  self::expect(true, c5b is{ForNonNullableByDefault} mai::Class5<core::int>);
+  self::expect(false, c5b is{ForNonNullableByDefault} mai::Class5<core::double>);
+  () → Null {
+    f5a<core::String>(){() → mai::Class5<core::String>};
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+    f5a<int, String>(); // error
+       ^" in f5a{<inapplicable>}.<core::int, core::String>();
+  };
+  dynamic f5b = #C5;
+  dynamic c5c = f5b{dynamic}.call();
+  self::expect(true, c5c is{ForNonNullableByDefault} mai::Class5<core::num>);
+  self::expect(false, c5c is{ForNonNullableByDefault} mai::Class5<core::int>);
+  dynamic c5d = f5b{dynamic}.call<core::int>();
+  self::expect(true, c5d is{ForNonNullableByDefault} mai::Class5<core::int>);
+  self::expect(false, c5d is{ForNonNullableByDefault} mai::Class5<core::double>);
+  self::throws(() → dynamic => f5b{dynamic}.call<core::String>());
+  self::throws(() → dynamic => f5b{dynamic}.call<core::int, core::String>());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C6}) → 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";
+}
+
+library /*isNonNullableByDefault*/;
+import self as mai;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → mai::Class1
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff() → mai::Class1
+    return new mai::Class1::•();
+}
+class Class2 extends core::Object {
+  constructor named() → mai::Class2
+    : super core::Object::•()
+    ;
+  static method _#named#tearOff() → mai::Class2
+    return new mai::Class2::named();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  constructor •(core::int field) → mai::Class3
+    : mai::Class3::field = field, super core::Object::•()
+    ;
+  static method _#new#tearOff(core::int field) → mai::Class3
+    return new mai::Class3::•(field);
+}
+class Class4<T extends core::Object? = dynamic> extends core::Object {
+  constructor _() → mai::Class4<mai::Class4::T%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#_#tearOff::T%>
+    return new mai::Class4::_<mai::Class4::_#_#tearOff::T%>();
+  static factory •<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::•::T%>
+    return new mai::Class4::_<mai::Class4::•::T%>();
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#new#tearOff::T%>
+    return mai::Class4::•<mai::Class4::_#new#tearOff::T%>();
+}
+class Class5<T extends core::num> extends core::Object {
+  constructor _() → mai::Class5<mai::Class5::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::num>() → mai::Class5<mai::Class5::_#_#tearOff::T>
+    return new mai::Class5::_<mai::Class5::_#_#tearOff::T>();
+  static factory •<T extends core::num>() → mai::Class5<mai::Class5::•::T>
+    return new mai::Class5::_<mai::Class5::•::T>();
+  static method _#new#tearOff<T extends core::num>() → mai::Class5<mai::Class5::_#new#tearOff::T>
+    return mai::Class5::•<mai::Class5::_#new#tearOff::T>();
+}
+
+constants  {
+  #C1 = tearoff mai::Class1::_#new#tearOff
+  #C2 = tearoff mai::Class2::_#named#tearOff
+  #C3 = tearoff mai::Class3::_#new#tearOff
+  #C4 = tearoff mai::Class4::_#new#tearOff
+  #C5 = tearoff mai::Class5::_#new#tearOff
+  #C6 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.outline.expect
new file mode 100644
index 0000000..2591204
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.outline.expect
@@ -0,0 +1,57 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///main_lib.dart";
+
+static final field core::bool inSoundMode;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, {core::bool inSoundModeOnly}) → dynamic
+  ;
+
+library /*isNonNullableByDefault*/;
+import self as self2;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → self2::Class1
+    ;
+  static method _#new#tearOff() → self2::Class1
+    return new self2::Class1::•();
+}
+class Class2 extends core::Object {
+  constructor named() → self2::Class2
+    ;
+  static method _#named#tearOff() → self2::Class2
+    return new self2::Class2::named();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  constructor •(core::int field) → self2::Class3
+    ;
+  static method _#new#tearOff(core::int field) → self2::Class3
+    return new self2::Class3::•(field);
+}
+class Class4<T extends core::Object? = dynamic> extends core::Object {
+  constructor _() → self2::Class4<self2::Class4::T%>
+    ;
+  static method _#_#tearOff<T extends core::Object? = dynamic>() → self2::Class4<self2::Class4::_#_#tearOff::T%>
+    return new self2::Class4::_<self2::Class4::_#_#tearOff::T%>();
+  static factory •<T extends core::Object? = dynamic>() → self2::Class4<self2::Class4::•::T%>
+    ;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self2::Class4<self2::Class4::_#new#tearOff::T%>
+    return self2::Class4::•<self2::Class4::_#new#tearOff::T%>();
+}
+class Class5<T extends core::num> extends core::Object {
+  constructor _() → self2::Class5<self2::Class5::T>
+    ;
+  static method _#_#tearOff<T extends core::num>() → self2::Class5<self2::Class5::_#_#tearOff::T>
+    return new self2::Class5::_<self2::Class5::_#_#tearOff::T>();
+  static factory •<T extends core::num>() → self2::Class5<self2::Class5::•::T>
+    ;
+  static method _#new#tearOff<T extends core::num>() → self2::Class5<self2::Class5::_#new#tearOff::T>
+    return self2::Class5::•<self2::Class5::_#new#tearOff::T>();
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.transformed.expect
new file mode 100644
index 0000000..f476c02
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart.weak.transformed.expect
@@ -0,0 +1,193 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34:8: Error: Too few positional arguments: 1 required, 0 given.
+//     f3a(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:35: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/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+//     f4a<int, String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+//     f4b<int>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:77: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.
+//     f5a<String>(); // error
+//        ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+//     f5a<int, String>(); // error
+//        ^
+//
+import self as self;
+import "main_lib.dart" as mai;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///main_lib.dart";
+
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+  () → mai::Class1 f1a = #C1;
+  mai::Class1 c1a = f1a(){() → mai::Class1};
+  self::expect(true, c1a is{ForNonNullableByDefault} mai::Class1);
+  dynamic f1b = #C1;
+  dynamic c1b = f1b{dynamic}.call();
+  self::expect(true, c1b is{ForNonNullableByDefault} mai::Class1);
+  self::expect(true, core::identical(f1a, f1b));
+  () → mai::Class2 f2a = #C2;
+  mai::Class2 c2a = f2a(){() → mai::Class2};
+  self::expect(true, c2a is{ForNonNullableByDefault} mai::Class2);
+  dynamic f2b = #C2;
+  dynamic c2b = f2b{dynamic}.call();
+  self::expect(true, c2b is{ForNonNullableByDefault} mai::Class2);
+  self::expect(true, core::identical(f2a, f2b));
+  (core::int) → mai::Class3 f3a = #C3;
+  mai::Class3 c3a = f3a(42){(core::int) → mai::Class3};
+  self::expect(42, c3a.{mai::Class3::field}{core::int});
+  () → Null {
+    let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:34: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/from_dill/main.dart:35: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 = #C3;
+  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));
+  <T extends core::Object? = dynamic>() → mai::Class4<T%> f4a = #C4;
+  mai::Class4<dynamic> c4a = f4a<dynamic>(){() → mai::Class4<dynamic>};
+  self::expect(true, c4a is{ForNonNullableByDefault} mai::Class4<dynamic>);
+  self::expect(false, c4a is{ForNonNullableByDefault} mai::Class4<core::int>);
+  mai::Class4<core::int> c4b = f4a<core::int>(){() → mai::Class4<core::int>};
+  self::expect(true, c4b is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::expect(false, c4b is{ForNonNullableByDefault} mai::Class4<core::String>);
+  () → Null {
+    let final Never #t3 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:52:8: Error: Expected 1 type arguments.
+    f4a<int, String>(); // error
+       ^" in f4a{<inapplicable>}.<core::int, core::String>();
+  };
+  () → mai::Class4<core::int> f4b = f4a<core::int>;
+  mai::Class4<core::int> c4c = f4b(){() → mai::Class4<core::int>};
+  self::expect(true, c4c is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::expect(false, c4c is{ForNonNullableByDefault} mai::Class4<core::String>);
+  () → Null {
+    let final Never #t4 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:60:8: Error: Expected 0 type arguments.
+    f4b<int>(); // error
+       ^" in f4b{<inapplicable>}.<core::int>();
+  };
+  dynamic f4c = #C4;
+  dynamic c4d = f4c{dynamic}.call();
+  self::expect(true, c4d is{ForNonNullableByDefault} mai::Class4<dynamic>);
+  self::expect(false, c4d is{ForNonNullableByDefault} mai::Class4<core::int>);
+  self::throws(() → dynamic => f4c{dynamic}.call<core::int, core::String>());
+  <T extends core::num>() → mai::Class5<T> f5a = #C5;
+  mai::Class5<core::num> c5a = f5a<core::num>(){() → mai::Class5<core::num>};
+  self::expect(true, c5a is{ForNonNullableByDefault} mai::Class5<core::num>);
+  self::expect(false, c5a is{ForNonNullableByDefault} mai::Class5<core::int>);
+  mai::Class5<core::int> c5b = f5a<core::int>(){() → mai::Class5<core::int>};
+  self::expect(true, c5b is{ForNonNullableByDefault} mai::Class5<core::int>);
+  self::expect(false, c5b is{ForNonNullableByDefault} mai::Class5<core::double>);
+  () → Null {
+    f5a<core::String>(){() → mai::Class5<core::String>};
+    let final Never #t5 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main.dart:78:8: Error: Expected 1 type arguments.
+    f5a<int, String>(); // error
+       ^" in f5a{<inapplicable>}.<core::int, core::String>();
+  };
+  dynamic f5b = #C5;
+  dynamic c5c = f5b{dynamic}.call();
+  self::expect(true, c5c is{ForNonNullableByDefault} mai::Class5<core::num>);
+  self::expect(false, c5c is{ForNonNullableByDefault} mai::Class5<core::int>);
+  dynamic c5d = f5b{dynamic}.call<core::int>();
+  self::expect(true, c5d is{ForNonNullableByDefault} mai::Class5<core::int>);
+  self::expect(false, c5d is{ForNonNullableByDefault} mai::Class5<core::double>);
+  self::throws(() → dynamic => f5b{dynamic}.call<core::String>());
+  self::throws(() → dynamic => f5b{dynamic}.call<core::int, core::String>());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C6}) → 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";
+}
+
+library /*isNonNullableByDefault*/;
+import self as mai;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → mai::Class1
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff() → mai::Class1
+    return new mai::Class1::•();
+}
+class Class2 extends core::Object {
+  constructor named() → mai::Class2
+    : super core::Object::•()
+    ;
+  static method _#named#tearOff() → mai::Class2
+    return new mai::Class2::named();
+}
+class Class3 extends core::Object {
+  final field core::int field;
+  constructor •(core::int field) → mai::Class3
+    : mai::Class3::field = field, super core::Object::•()
+    ;
+  static method _#new#tearOff(core::int field) → mai::Class3
+    return new mai::Class3::•(field);
+}
+class Class4<T extends core::Object? = dynamic> extends core::Object {
+  constructor _() → mai::Class4<mai::Class4::T%>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#_#tearOff::T%>
+    return new mai::Class4::_<mai::Class4::_#_#tearOff::T%>();
+  static factory •<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::•::T%>
+    return new mai::Class4::_<mai::Class4::•::T%>();
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → mai::Class4<mai::Class4::_#new#tearOff::T%>
+    return mai::Class4::•<mai::Class4::_#new#tearOff::T%>();
+}
+class Class5<T extends core::num> extends core::Object {
+  constructor _() → mai::Class5<mai::Class5::T>
+    : super core::Object::•()
+    ;
+  static method _#_#tearOff<T extends core::num>() → mai::Class5<mai::Class5::_#_#tearOff::T>
+    return new mai::Class5::_<mai::Class5::_#_#tearOff::T>();
+  static factory •<T extends core::num>() → mai::Class5<mai::Class5::•::T>
+    return new mai::Class5::_<mai::Class5::•::T>();
+  static method _#new#tearOff<T extends core::num>() → mai::Class5<mai::Class5::_#new#tearOff::T>
+    return mai::Class5::•<mai::Class5::_#new#tearOff::T>();
+}
+
+constants  {
+  #C1 = tearoff mai::Class1::_#new#tearOff
+  #C2 = tearoff mai::Class2::_#named#tearOff
+  #C3 = tearoff mai::Class3::_#new#tearOff
+  #C4 = tearoff mai::Class4::_#new#tearOff
+  #C5 = tearoff mai::Class5::_#new#tearOff
+  #C6 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main_lib.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main_lib.dart
new file mode 100644
index 0000000..f50d3cd
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/main_lib.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Class1 {}
+
+class Class2 {
+  Class2.named();
+}
+
+class Class3 {
+  final int field;
+
+  Class3(this.field);
+}
+
+class Class4<T> {
+  Class4._();
+  factory Class4() => new Class4<T>._();
+}
+
+class Class5<T extends num> {
+  Class5._();
+  factory Class5() => new Class5<T>._();
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/test.options b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/test.options
new file mode 100644
index 0000000..bfe6dc8
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/from_dill/test.options
@@ -0,0 +1 @@
+main_lib.dart
\ No newline at end of file