[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