[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>
This commit is contained in:
Johnni Winther 2021-07-08 12:54:44 +00:00 committed by commit-bot@chromium.org
parent 2a68e31ffb
commit e92cee7833
27 changed files with 907 additions and 14 deletions

View file

@ -11,6 +11,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 =

View file

@ -126,7 +126,8 @@ class ConstructorBuilderImpl extends FunctionBuilderImpl
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 @@ class ConstructorBuilderImpl extends FunctionBuilderImpl
..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);

View file

@ -288,7 +288,8 @@ class EnumBuilder extends SourceClassBuilder {
charOffset,
charOffset,
charEndOffset,
constructorReference);
constructorReference,
forAbstractClassOrEnum: true);
constructors[""] = constructorBuilder;
FieldBuilder valuesBuilder = new SourceFieldBuilder(
/* metadata = */ null,

View file

@ -21,9 +21,11 @@ Name constructorTearOffName(String constructorName, Library library) {
///
/// 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)

View file

@ -3091,6 +3091,7 @@ class TypeUseGenerator extends AbstractReadOnlyAccessGenerator {
@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 @@ class TypeUseGenerator extends AbstractReadOnlyAccessGenerator {
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 @@ class TypeUseGenerator extends AbstractReadOnlyAccessGenerator {
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) {

View file

@ -810,7 +810,9 @@ class KernelTarget extends TargetImplementation {
..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);

View file

@ -105,6 +105,7 @@ class OutlineBuilder extends StackListenerImpl {
final bool enableNative;
final bool stringExpectedAfterNative;
bool inAbstractClass = false;
bool inConstructor = false;
bool inConstructorName = false;
int importIndex = 0;
@ -470,6 +471,7 @@ class OutlineBuilder extends StackListenerImpl {
libraryBuilder.currentTypeParameterScopeBuilder
.markAsClassDeclaration(name.lexeme, name.charOffset, typeVariables);
libraryBuilder.setCurrentClassName(name.lexeme);
inAbstractClass = abstractToken != null;
push(abstractToken != null ? abstractMask : 0);
}
@ -584,6 +586,7 @@ class OutlineBuilder extends StackListenerImpl {
supertype.typeVariables = typeVariables;
}
List<MetadataBuilder>? metadata = pop() as List<MetadataBuilder>?;
inAbstractClass = false;
checkEmpty(beginToken.charOffset);
if (name is ParserRecovery) {
libraryBuilder
@ -1240,7 +1243,8 @@ class OutlineBuilder extends StackListenerImpl {
formalsOffset,
endToken.charOffset,
nativeMethodName,
beginInitializers: beginInitializers);
beginInitializers: beginInitializers,
forAbstractClass: inAbstractClass);
} else {
if (isConst) {
// TODO(danrubel): consider removing this

View file

@ -2324,7 +2324,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
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 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
charOpenParenOffset,
charEndOffset,
referenceFrom,
nativeMethodName);
nativeMethodName: nativeMethodName,
forAbstractClassOrEnum: forAbstractClass);
checkTypeVariables(typeVariables, constructorBuilder);
addBuilder(constructorName, constructorBuilder, charOffset,
getterReference: referenceFrom?.reference);

View file

@ -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

View file

@ -5232,3 +5232,10 @@ InstantiationTooManyArguments:
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;

View file

@ -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() {}

View file

@ -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 {}

View file

@ -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 {}

View file

@ -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() {}

View file

@ -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() {}

View file

@ -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 {}

View file

@ -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
;

View file

@ -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 {}

View file

@ -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';
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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}) {}

View file

@ -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}) {}

View file

@ -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
}

View file

@ -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
;

View file

@ -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
}

View file

@ -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