[cfe] Add check for constructor tear off on abstract classes
+ add test for inferred types on constructor tear offs
+ avoid creating tear off lowering for abstract classes
Change-Id: I0d7921690ecea090f96a9811d25248e7e02582b4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/206082
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 1229ded..289ec96 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -12,6 +12,15 @@
part of _fe_analyzer_shared.messages.codes;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeAbstractClassConstructorTearOff =
+ messageAbstractClassConstructorTearOff;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageAbstractClassConstructorTearOff = const MessageCode(
+ "AbstractClassConstructorTearOff",
+ message: r"""Constructors on abstract classes can't be torn off.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String name)>
templateAbstractClassInstantiation =
const Template<Message Function(String name)>(
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
index a82100b..d659697 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
@@ -126,7 +126,8 @@
this.charOpenParenOffset,
int charEndOffset,
Member? referenceFrom,
- [String? nativeMethodName])
+ {String? nativeMethodName,
+ required bool forAbstractClassOrEnum})
: _constructor = new Constructor(new FunctionNode(null),
name: new Name(name, compilationUnit.library),
fileUri: compilationUnit.fileUri,
@@ -136,7 +137,8 @@
..fileEndOffset = charEndOffset
..isNonNullableByDefault = compilationUnit.isNonNullableByDefault,
_constructorTearOff = createConstructorTearOffProcedure(
- name, compilationUnit, charOffset),
+ name, compilationUnit, charOffset,
+ forAbstractClassOrEnum: forAbstractClassOrEnum),
super(metadata, modifiers, returnType, name, typeVariables, formals,
compilationUnit, charOffset, nativeMethodName);
diff --git a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
index 9d294ec..8947531 100644
--- a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
@@ -288,7 +288,8 @@
charOffset,
charOffset,
charEndOffset,
- constructorReference);
+ constructorReference,
+ forAbstractClassOrEnum: true);
constructors[""] = constructorBuilder;
FieldBuilder valuesBuilder = new SourceFieldBuilder(
/* metadata = */ 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 c14c0b7..33aa5d1 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
@@ -21,9 +21,11 @@
///
/// If constructor tear off lowering is not enabled, `null` is returned.
Procedure? createConstructorTearOffProcedure(
- String name, SourceLibraryBuilder compilationUnit, int fileOffset) {
- if (compilationUnit
- .loader.target.backendTarget.isConstructorTearOffLoweringEnabled) {
+ String name, SourceLibraryBuilder compilationUnit, int fileOffset,
+ {required bool forAbstractClassOrEnum}) {
+ if (!forAbstractClassOrEnum &&
+ compilationUnit
+ .loader.target.backendTarget.isConstructorTearOffLoweringEnabled) {
return new Procedure(constructorTearOffName(name, compilationUnit.library),
ProcedureKind.Method, new FunctionNode(null),
fileUri: compilationUnit.fileUri, isStatic: true)
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index 7150059..9789db1 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -3091,6 +3091,7 @@
@override
buildPropertyAccess(
IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
+ int nameOffset = offsetForToken(send.token);
Name name = send.name;
Arguments? arguments = send.arguments;
@@ -3106,8 +3107,7 @@
if (declarationBuilder is DeclarationBuilder) {
DeclarationBuilder declaration = declarationBuilder;
Builder? member = declaration.findStaticBuilder(
- name.text, offsetForToken(send.token), _uri, _helper.libraryBuilder);
-
+ name.text, nameOffset, _uri, _helper.libraryBuilder);
Generator generator;
if (member == null) {
// If we find a setter, [member] is an [AccessErrorBuilder], not null.
@@ -3115,10 +3115,16 @@
if (_helper.enableConstructorTearOffsInLibrary &&
declarationBuilder is ClassBuilder) {
MemberBuilder? constructor =
- declarationBuilder.findConstructorOrFactory(name.text,
- offsetForToken(send.token), _uri, _helper.libraryBuilder);
+ declarationBuilder.findConstructorOrFactory(
+ name.text, nameOffset, _uri, _helper.libraryBuilder);
Member? tearOff = constructor?.readTarget;
if (tearOff is Constructor) {
+ if (declarationBuilder.isAbstract) {
+ return _helper.buildProblem(
+ messageAbstractClassConstructorTearOff,
+ nameOffset,
+ name.text.length);
+ }
return _helper.forest
.createConstructorTearOff(token.charOffset, tearOff);
} else if (tearOff is Procedure) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 851d924..2531ba7 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -810,7 +810,9 @@
..isNonNullableByDefault =
enclosingClass.enclosingLibrary.isNonNullableByDefault;
Procedure? constructorTearOff = createConstructorTearOffProcedure(
- '', classBuilder.library, constructor.fileOffset);
+ '', classBuilder.library, constructor.fileOffset,
+ forAbstractClassOrEnum:
+ enclosingClass.isAbstract || enclosingClass.isEnum);
if (constructorTearOff != null) {
buildConstructorTearOffProcedure(constructorTearOff, constructor,
classBuilder.cls, classBuilder.library);
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index ec8bc6f..4cc93c2 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -105,6 +105,7 @@
final bool enableNative;
final bool stringExpectedAfterNative;
+ bool inAbstractClass = false;
bool inConstructor = false;
bool inConstructorName = false;
int importIndex = 0;
@@ -470,6 +471,7 @@
libraryBuilder.currentTypeParameterScopeBuilder
.markAsClassDeclaration(name.lexeme, name.charOffset, typeVariables);
libraryBuilder.setCurrentClassName(name.lexeme);
+ inAbstractClass = abstractToken != null;
push(abstractToken != null ? abstractMask : 0);
}
@@ -584,6 +586,7 @@
supertype.typeVariables = typeVariables;
}
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
+ inAbstractClass = false;
checkEmpty(beginToken.charOffset);
if (name is ParserRecovery) {
libraryBuilder
@@ -1240,7 +1243,8 @@
formalsOffset,
endToken.charOffset,
nativeMethodName,
- beginInitializers: beginInitializers);
+ beginInitializers: beginInitializers,
+ forAbstractClass: inAbstractClass);
} else {
if (isConst) {
// TODO(danrubel): consider removing this
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 78cf330..b9eed88 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -2324,7 +2324,8 @@
int charOpenParenOffset,
int charEndOffset,
String? nativeMethodName,
- {Token? beginInitializers}) {
+ {Token? beginInitializers,
+ required bool forAbstractClass}) {
Member? referenceFrom;
if (_currentClassReferencesFromIndexed != null) {
referenceFrom = _currentClassReferencesFromIndexed!.lookupConstructor(
@@ -2344,7 +2345,8 @@
charOpenParenOffset,
charEndOffset,
referenceFrom,
- nativeMethodName);
+ nativeMethodName: nativeMethodName,
+ forAbstractClassOrEnum: forAbstractClass);
checkTypeVariables(typeVariables, constructorBuilder);
addBuilder(constructorName, constructorBuilder, charOffset,
getterReference: referenceFrom?.reference);
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 18c7bae..f6e79b9a 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -5,6 +5,7 @@
# Note that test/spelling: Status will have no effect. Spelling errors can
# always be fixed by either spelling correctly or updating the dictionary.
+AbstractClassConstructorTearOff/analyzerCode: Fail
AbstractClassInstantiation/example: Fail
AbstractExtensionField/analyzerCode: Fail
AbstractExtensionField/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 8045d59..84ed8c2 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -5232,3 +5232,10 @@
script: |
f<X>() {}
main() => f<int, String>;
+
+AbstractClassConstructorTearOff:
+ template: "Constructors on abstract classes can't be torn off."
+ experiments: constructor-tearoffs
+ script: |
+ abstract class Class {}
+ main() => Class.new;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart
new file mode 100644
index 0000000..31fcc39
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart
@@ -0,0 +1,21 @@
+// 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 ConcreteClass {}
+abstract class AbstractClass {}
+mixin Mixin {}
+class NamedMixinApplication = Object with Mixin;
+abstract class AbstractNamedMixinApplication = Object with Mixin;
+extension Extension on int {}
+
+test() {
+ ConcreteClass.new; // ok
+ AbstractClass.new; // error
+ Mixin.new; // error
+ NamedMixinApplication.new; // ok
+ AbstractNamedMixinApplication.new; // error
+ Extension.new; // error
+}
+
+main() {}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.strong.expect
new file mode 100644
index 0000000..e8c1280
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.strong.expect
@@ -0,0 +1,64 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:14:17: Error: Constructors on abstract classes can't be torn off.
+// AbstractClass.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:15:9: Error: Getter not found: 'new'.
+// Mixin.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:17:33: Error: Constructors on abstract classes can't be torn off.
+// AbstractNamedMixinApplication.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:18:13: Error: Getter not found: 'new'.
+// Extension.new; // error
+// ^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class ConcreteClass extends core::Object {
+ synthetic constructor •() → self::ConcreteClass
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractClass extends core::Object {
+ synthetic constructor •() → self::AbstractClass
+ : super core::Object::•()
+ ;
+}
+abstract class Mixin extends core::Object /*isMixinDeclaration*/ {
+}
+class NamedMixinApplication = core::Object with self::Mixin /*hasConstConstructor*/ {
+ const synthetic constructor •() → self::NamedMixinApplication
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractNamedMixinApplication = core::Object with self::Mixin /*hasConstConstructor*/ {
+ const synthetic constructor •() → self::AbstractNamedMixinApplication
+ : super core::Object::•()
+ ;
+}
+extension Extension on core::int {
+}
+static method test() → dynamic {
+ self::ConcreteClass::•;
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:14:17: Error: Constructors on abstract classes can't be torn off.
+ AbstractClass.new; // error
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:15:9: Error: Getter not found: 'new'.
+ Mixin.new; // error
+ ^^^";
+ self::NamedMixinApplication::•;
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:17:33: Error: Constructors on abstract classes can't be torn off.
+ AbstractNamedMixinApplication.new; // error
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:18:13: Error: Getter not found: 'new'.
+ Extension.new; // error
+ ^^^";
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.strong.transformed.expect
new file mode 100644
index 0000000..b86fac8
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.strong.transformed.expect
@@ -0,0 +1,64 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:14:17: Error: Constructors on abstract classes can't be torn off.
+// AbstractClass.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:15:9: Error: Getter not found: 'new'.
+// Mixin.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:17:33: Error: Constructors on abstract classes can't be torn off.
+// AbstractNamedMixinApplication.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:18:13: Error: Getter not found: 'new'.
+// Extension.new; // error
+// ^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class ConcreteClass extends core::Object {
+ synthetic constructor •() → self::ConcreteClass
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractClass extends core::Object {
+ synthetic constructor •() → self::AbstractClass
+ : super core::Object::•()
+ ;
+}
+abstract class Mixin extends core::Object /*isMixinDeclaration*/ {
+}
+class NamedMixinApplication extends core::Object implements self::Mixin /*isEliminatedMixin,hasConstConstructor*/ {
+ const synthetic constructor •() → self::NamedMixinApplication
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractNamedMixinApplication extends core::Object implements self::Mixin /*isEliminatedMixin,hasConstConstructor*/ {
+ const synthetic constructor •() → self::AbstractNamedMixinApplication
+ : super core::Object::•()
+ ;
+}
+extension Extension on core::int {
+}
+static method test() → dynamic {
+ self::ConcreteClass::•;
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:14:17: Error: Constructors on abstract classes can't be torn off.
+ AbstractClass.new; // error
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:15:9: Error: Getter not found: 'new'.
+ Mixin.new; // error
+ ^^^";
+ self::NamedMixinApplication::•;
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:17:33: Error: Constructors on abstract classes can't be torn off.
+ AbstractNamedMixinApplication.new; // error
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:18:13: Error: Getter not found: 'new'.
+ Extension.new; // error
+ ^^^";
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.textual_outline.expect
new file mode 100644
index 0000000..a955952
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.textual_outline.expect
@@ -0,0 +1,12 @@
+class ConcreteClass {}
+
+abstract class AbstractClass {}
+
+mixin Mixin {}
+class NamedMixinApplication = Object with Mixin;
+abstract class AbstractNamedMixinApplication = Object with Mixin;
+
+extension Extension on int {}
+
+test() {}
+main() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..f9d5a03
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.textual_outline_modelled.expect
@@ -0,0 +1,13 @@
+abstract class AbstractClass {}
+
+abstract class AbstractNamedMixinApplication = Object with Mixin;
+
+class ConcreteClass {}
+
+class NamedMixinApplication = Object with Mixin;
+
+extension Extension on int {}
+
+main() {}
+mixin Mixin {}
+test() {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.weak.expect
new file mode 100644
index 0000000..e8c1280
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.weak.expect
@@ -0,0 +1,64 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:14:17: Error: Constructors on abstract classes can't be torn off.
+// AbstractClass.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:15:9: Error: Getter not found: 'new'.
+// Mixin.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:17:33: Error: Constructors on abstract classes can't be torn off.
+// AbstractNamedMixinApplication.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:18:13: Error: Getter not found: 'new'.
+// Extension.new; // error
+// ^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class ConcreteClass extends core::Object {
+ synthetic constructor •() → self::ConcreteClass
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractClass extends core::Object {
+ synthetic constructor •() → self::AbstractClass
+ : super core::Object::•()
+ ;
+}
+abstract class Mixin extends core::Object /*isMixinDeclaration*/ {
+}
+class NamedMixinApplication = core::Object with self::Mixin /*hasConstConstructor*/ {
+ const synthetic constructor •() → self::NamedMixinApplication
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractNamedMixinApplication = core::Object with self::Mixin /*hasConstConstructor*/ {
+ const synthetic constructor •() → self::AbstractNamedMixinApplication
+ : super core::Object::•()
+ ;
+}
+extension Extension on core::int {
+}
+static method test() → dynamic {
+ self::ConcreteClass::•;
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:14:17: Error: Constructors on abstract classes can't be torn off.
+ AbstractClass.new; // error
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:15:9: Error: Getter not found: 'new'.
+ Mixin.new; // error
+ ^^^";
+ self::NamedMixinApplication::•;
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:17:33: Error: Constructors on abstract classes can't be torn off.
+ AbstractNamedMixinApplication.new; // error
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:18:13: Error: Getter not found: 'new'.
+ Extension.new; // error
+ ^^^";
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.weak.outline.expect
new file mode 100644
index 0000000..23490ce
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.weak.outline.expect
@@ -0,0 +1,30 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class ConcreteClass extends core::Object {
+ synthetic constructor •() → self::ConcreteClass
+ ;
+}
+abstract class AbstractClass extends core::Object {
+ synthetic constructor •() → self::AbstractClass
+ ;
+}
+abstract class Mixin extends core::Object /*isMixinDeclaration*/ {
+}
+class NamedMixinApplication = core::Object with self::Mixin /*hasConstConstructor*/ {
+ const synthetic constructor •() → self::NamedMixinApplication
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractNamedMixinApplication = core::Object with self::Mixin /*hasConstConstructor*/ {
+ const synthetic constructor •() → self::AbstractNamedMixinApplication
+ : super core::Object::•()
+ ;
+}
+extension Extension on core::int {
+}
+static method test() → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.weak.transformed.expect
new file mode 100644
index 0000000..b86fac8
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart.weak.transformed.expect
@@ -0,0 +1,64 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:14:17: Error: Constructors on abstract classes can't be torn off.
+// AbstractClass.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:15:9: Error: Getter not found: 'new'.
+// Mixin.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:17:33: Error: Constructors on abstract classes can't be torn off.
+// AbstractNamedMixinApplication.new; // error
+// ^^^
+//
+// pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:18:13: Error: Getter not found: 'new'.
+// Extension.new; // error
+// ^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class ConcreteClass extends core::Object {
+ synthetic constructor •() → self::ConcreteClass
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractClass extends core::Object {
+ synthetic constructor •() → self::AbstractClass
+ : super core::Object::•()
+ ;
+}
+abstract class Mixin extends core::Object /*isMixinDeclaration*/ {
+}
+class NamedMixinApplication extends core::Object implements self::Mixin /*isEliminatedMixin,hasConstConstructor*/ {
+ const synthetic constructor •() → self::NamedMixinApplication
+ : super core::Object::•()
+ ;
+}
+abstract class AbstractNamedMixinApplication extends core::Object implements self::Mixin /*isEliminatedMixin,hasConstConstructor*/ {
+ const synthetic constructor •() → self::AbstractNamedMixinApplication
+ : super core::Object::•()
+ ;
+}
+extension Extension on core::int {
+}
+static method test() → dynamic {
+ self::ConcreteClass::•;
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:14:17: Error: Constructors on abstract classes can't be torn off.
+ AbstractClass.new; // error
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:15:9: Error: Getter not found: 'new'.
+ Mixin.new; // error
+ ^^^";
+ self::NamedMixinApplication::•;
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:17:33: Error: Constructors on abstract classes can't be torn off.
+ AbstractNamedMixinApplication.new; // error
+ ^^^";
+ invalid-expression "pkg/front_end/testcases/constructor_tearoffs/abstract_class_constructor_tear_off.dart:18:13: Error: Getter not found: 'new'.
+ Extension.new; // error
+ ^^^";
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart
new file mode 100644
index 0000000..fc8cba1
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart
@@ -0,0 +1,73 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+final bool inSoundMode = <int?>[] is! List<int>;
+
+main() {
+ print('inSoundMode: $inSoundMode');
+ testInferred();
+}
+
+class Class1 {
+ int field;
+
+ Class1(this.field);
+}
+
+abstract class Interface2 {
+ int get field;
+}
+
+class Class2 implements Interface2 {
+ final field;
+
+ Class2(this.field);
+}
+
+testInferred() {
+ var f1a = Class1.new;
+ expect(true, f1a is Class1 Function(int));
+ expect(false, f1a is Class1 Function(String));
+ var c1a = f1a(0);
+ expect(true, c1a is Class1);
+ () {
+ f1a(''); // error
+ };
+
+ dynamic f1b = Class1.new;
+ var c1b = f1b(0);
+ expect(true, c1b is Class1);
+ throws(() => f1b(''));
+
+ var f2a = Class2.new;
+ expect(true, f2a is Class2 Function(int));
+ expect(false, f2a is Class2 Function(String));
+ var c2a = f2a(0);
+ expect(true, c2a is Class2);
+ () {
+ f2a(''); // error
+ };
+
+ dynamic f2b = Class2.new;
+ var c2b = f2b(0);
+ expect(true, c2b is Class2);
+ throws(() => f2b(''));
+}
+
+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/inferred_constructor_tear_off.dart.strong.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.strong.expect
new file mode 100644
index 0000000..edd7977
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.strong.expect
@@ -0,0 +1,95 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:35:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+// f1a(''); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:49:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+// f2a(''); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int field;
+ constructor •(core::int field) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff(core::int field) → self::Class1
+ return new self::Class1::•(field);
+}
+abstract class Interface2 extends core::Object {
+ synthetic constructor •() → self::Interface2
+ : super core::Object::•()
+ ;
+ abstract get field() → core::int;
+}
+class Class2 extends core::Object implements self::Interface2 {
+ final field core::int field;
+ constructor •(core::int field) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff(core::int field) → self::Class2
+ return new self::Class2::•(field);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testInferred();
+}
+static method testInferred() → dynamic {
+ (core::int) → self::Class1 f1a = #C1;
+ self::expect(true, f1a is{ForNonNullableByDefault} (core::int) → self::Class1);
+ self::expect(false, f1a is{ForNonNullableByDefault} (core::String) → self::Class1);
+ self::Class1 c1a = f1a(0){(core::int) → self::Class1};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+ () → Null {
+ f1a(let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:35:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+ f1a(''); // error
+ ^" in "" as{TypeError,ForNonNullableByDefault} core::int){(core::int) → self::Class1};
+ };
+ dynamic f1b = #C1;
+ dynamic c1b = f1b{dynamic}.call(0);
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+ self::throws(() → dynamic => f1b{dynamic}.call(""));
+ (core::int) → self::Class2 f2a = #C2;
+ self::expect(true, f2a is{ForNonNullableByDefault} (core::int) → self::Class2);
+ self::expect(false, f2a is{ForNonNullableByDefault} (core::String) → self::Class2);
+ self::Class2 c2a = f2a(0){(core::int) → self::Class2};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+ () → Null {
+ f2a(let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:49:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+ f2a(''); // error
+ ^" in "" as{TypeError,ForNonNullableByDefault} core::int){(core::int) → self::Class2};
+ };
+ dynamic f2b = #C2;
+ dynamic c2b = f2b{dynamic}.call(0);
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+ self::throws(() → dynamic => f2b{dynamic}.call(""));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C3}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = tearoff self::Class1::_#new#tearOff
+ #C2 = tearoff self::Class2::_#new#tearOff
+ #C3 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.strong.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.strong.transformed.expect
new file mode 100644
index 0000000..9297490
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.strong.transformed.expect
@@ -0,0 +1,95 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:35:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+// f1a(''); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:49:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+// f2a(''); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int field;
+ constructor •(core::int field) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff(core::int field) → self::Class1
+ return new self::Class1::•(field);
+}
+abstract class Interface2 extends core::Object {
+ synthetic constructor •() → self::Interface2
+ : super core::Object::•()
+ ;
+ abstract get field() → core::int;
+}
+class Class2 extends core::Object implements self::Interface2 {
+ final field core::int field;
+ constructor •(core::int field) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff(core::int field) → self::Class2
+ return new self::Class2::•(field);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testInferred();
+}
+static method testInferred() → dynamic {
+ (core::int) → self::Class1 f1a = #C1;
+ self::expect(true, f1a is{ForNonNullableByDefault} (core::int) → self::Class1);
+ self::expect(false, f1a is{ForNonNullableByDefault} (core::String) → self::Class1);
+ self::Class1 c1a = f1a(0){(core::int) → self::Class1};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+ () → Null {
+ f1a(let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:35:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+ f1a(''); // error
+ ^" in "" as{TypeError,ForNonNullableByDefault} core::int){(core::int) → self::Class1};
+ };
+ dynamic f1b = #C1;
+ dynamic c1b = f1b{dynamic}.call(0);
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+ self::throws(() → dynamic => f1b{dynamic}.call(""));
+ (core::int) → self::Class2 f2a = #C2;
+ self::expect(true, f2a is{ForNonNullableByDefault} (core::int) → self::Class2);
+ self::expect(false, f2a is{ForNonNullableByDefault} (core::String) → self::Class2);
+ self::Class2 c2a = f2a(0){(core::int) → self::Class2};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+ () → Null {
+ f2a(let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:49:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+ f2a(''); // error
+ ^" in "" as{TypeError,ForNonNullableByDefault} core::int){(core::int) → self::Class2};
+ };
+ dynamic f2b = #C2;
+ dynamic c2b = f2b{dynamic}.call(0);
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+ self::throws(() → dynamic => f2b{dynamic}.call(""));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C3}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = tearoff self::Class1::_#new#tearOff
+ #C2 = tearoff self::Class2::_#new#tearOff
+ #C3 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.textual_outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.textual_outline.expect
new file mode 100644
index 0000000..9e086db
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.textual_outline.expect
@@ -0,0 +1,20 @@
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+
+class Class1 {
+ int field;
+ Class1(this.field);
+}
+
+abstract class Interface2 {
+ int get field;
+}
+
+class Class2 implements Interface2 {
+ final field;
+ Class2(this.field);
+}
+
+testInferred() {}
+expect(expected, actual) {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..8944ae7
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.textual_outline_modelled.expect
@@ -0,0 +1,19 @@
+abstract class Interface2 {
+ int get field;
+}
+
+class Class1 {
+ Class1(this.field);
+ int field;
+}
+
+class Class2 implements Interface2 {
+ Class2(this.field);
+ final field;
+}
+
+expect(expected, actual) {}
+final bool inSoundMode = <int?>[] is! List<int>;
+main() {}
+testInferred() {}
+throws(Function() f, {bool inSoundModeOnly: false}) {}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.weak.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.weak.expect
new file mode 100644
index 0000000..edd7977
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.weak.expect
@@ -0,0 +1,95 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:35:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+// f1a(''); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:49:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+// f2a(''); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int field;
+ constructor •(core::int field) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff(core::int field) → self::Class1
+ return new self::Class1::•(field);
+}
+abstract class Interface2 extends core::Object {
+ synthetic constructor •() → self::Interface2
+ : super core::Object::•()
+ ;
+ abstract get field() → core::int;
+}
+class Class2 extends core::Object implements self::Interface2 {
+ final field core::int field;
+ constructor •(core::int field) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff(core::int field) → self::Class2
+ return new self::Class2::•(field);
+}
+static final field core::bool inSoundMode = !(<core::int?>[] is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testInferred();
+}
+static method testInferred() → dynamic {
+ (core::int) → self::Class1 f1a = #C1;
+ self::expect(true, f1a is{ForNonNullableByDefault} (core::int) → self::Class1);
+ self::expect(false, f1a is{ForNonNullableByDefault} (core::String) → self::Class1);
+ self::Class1 c1a = f1a(0){(core::int) → self::Class1};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+ () → Null {
+ f1a(let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:35:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+ f1a(''); // error
+ ^" in "" as{TypeError,ForNonNullableByDefault} core::int){(core::int) → self::Class1};
+ };
+ dynamic f1b = #C1;
+ dynamic c1b = f1b{dynamic}.call(0);
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+ self::throws(() → dynamic => f1b{dynamic}.call(""));
+ (core::int) → self::Class2 f2a = #C2;
+ self::expect(true, f2a is{ForNonNullableByDefault} (core::int) → self::Class2);
+ self::expect(false, f2a is{ForNonNullableByDefault} (core::String) → self::Class2);
+ self::Class2 c2a = f2a(0){(core::int) → self::Class2};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+ () → Null {
+ f2a(let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:49:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+ f2a(''); // error
+ ^" in "" as{TypeError,ForNonNullableByDefault} core::int){(core::int) → self::Class2};
+ };
+ dynamic f2b = #C2;
+ dynamic c2b = f2b{dynamic}.call(0);
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+ self::throws(() → dynamic => f2b{dynamic}.call(""));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C3}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = tearoff self::Class1::_#new#tearOff
+ #C2 = tearoff self::Class2::_#new#tearOff
+ #C3 = false
+}
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.weak.outline.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.weak.outline.expect
new file mode 100644
index 0000000..802525c
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.weak.outline.expect
@@ -0,0 +1,32 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int field;
+ constructor •(core::int field) → self::Class1
+ ;
+ static method _#new#tearOff(core::int field) → self::Class1
+ return new self::Class1::•(field);
+}
+abstract class Interface2 extends core::Object {
+ synthetic constructor •() → self::Interface2
+ ;
+ abstract get field() → core::int;
+}
+class Class2 extends core::Object implements self::Interface2 {
+ final field core::int field;
+ constructor •(core::int field) → self::Class2
+ ;
+ static method _#new#tearOff(core::int field) → self::Class2
+ return new self::Class2::•(field);
+}
+static final field core::bool inSoundMode;
+static method main() → dynamic
+ ;
+static method testInferred() → dynamic
+ ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+ ;
+static method throws(() → dynamic f, {core::bool inSoundModeOnly}) → dynamic
+ ;
diff --git a/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.weak.transformed.expect b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.weak.transformed.expect
new file mode 100644
index 0000000..9297490
--- /dev/null
+++ b/pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart.weak.transformed.expect
@@ -0,0 +1,95 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:35:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+// f1a(''); // error
+// ^
+//
+// pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:49:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+// f2a(''); // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+ field core::int field;
+ constructor •(core::int field) → self::Class1
+ : self::Class1::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff(core::int field) → self::Class1
+ return new self::Class1::•(field);
+}
+abstract class Interface2 extends core::Object {
+ synthetic constructor •() → self::Interface2
+ : super core::Object::•()
+ ;
+ abstract get field() → core::int;
+}
+class Class2 extends core::Object implements self::Interface2 {
+ final field core::int field;
+ constructor •(core::int field) → self::Class2
+ : self::Class2::field = field, super core::Object::•()
+ ;
+ static method _#new#tearOff(core::int field) → self::Class2
+ return new self::Class2::•(field);
+}
+static final field core::bool inSoundMode = !(core::_GrowableList::•<core::int?>(0) is{ForNonNullableByDefault} core::List<core::int>);
+static method main() → dynamic {
+ core::print("inSoundMode: ${self::inSoundMode}");
+ self::testInferred();
+}
+static method testInferred() → dynamic {
+ (core::int) → self::Class1 f1a = #C1;
+ self::expect(true, f1a is{ForNonNullableByDefault} (core::int) → self::Class1);
+ self::expect(false, f1a is{ForNonNullableByDefault} (core::String) → self::Class1);
+ self::Class1 c1a = f1a(0){(core::int) → self::Class1};
+ self::expect(true, c1a is{ForNonNullableByDefault} self::Class1);
+ () → Null {
+ f1a(let final Never #t1 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:35:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+ f1a(''); // error
+ ^" in "" as{TypeError,ForNonNullableByDefault} core::int){(core::int) → self::Class1};
+ };
+ dynamic f1b = #C1;
+ dynamic c1b = f1b{dynamic}.call(0);
+ self::expect(true, c1b is{ForNonNullableByDefault} self::Class1);
+ self::throws(() → dynamic => f1b{dynamic}.call(""));
+ (core::int) → self::Class2 f2a = #C2;
+ self::expect(true, f2a is{ForNonNullableByDefault} (core::int) → self::Class2);
+ self::expect(false, f2a is{ForNonNullableByDefault} (core::String) → self::Class2);
+ self::Class2 c2a = f2a(0){(core::int) → self::Class2};
+ self::expect(true, c2a is{ForNonNullableByDefault} self::Class2);
+ () → Null {
+ f2a(let final Never #t2 = invalid-expression "pkg/front_end/testcases/constructor_tearoffs/lowering/inferred_constructor_tear_off.dart:49:9: Error: The argument type 'String' can't be assigned to the parameter type 'int'.
+ f2a(''); // error
+ ^" in "" as{TypeError,ForNonNullableByDefault} core::int){(core::int) → self::Class2};
+ };
+ dynamic f2b = #C2;
+ dynamic c2b = f2b{dynamic}.call(0);
+ self::expect(true, c2b is{ForNonNullableByDefault} self::Class2);
+ self::throws(() → dynamic => f2b{dynamic}.call(""));
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+ if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual))
+ throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, {core::bool inSoundModeOnly = #C3}) → dynamic {
+ try {
+ f(){() → dynamic};
+ }
+ on core::Object catch(final core::Object e) {
+ core::print("Thrown: ${e}");
+ return;
+ }
+ if(!self::inSoundMode && inSoundModeOnly) {
+ return;
+ }
+ throw "Expected exception";
+}
+
+constants {
+ #C1 = tearoff self::Class1::_#new#tearOff
+ #C2 = tearoff self::Class2::_#new#tearOff
+ #C3 = false
+}
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 322bacf..a694e4f 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -6,6 +6,7 @@
# the round trip for Kernel textual serialization where the initial binary
# Kernel files are produced by compiling Dart code via Fasta.
+constructor_tearoffs/abstract_class_constructor_tear_off: TextSerializationFailure
constructor_tearoffs/generic_tearoff_with_context: TextSerializationFailure
constructor_tearoffs/generic_tearoff_without_context: TextSerializationFailure
constructor_tearoffs/instantiation: TypeCheckError