mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 14:32:49 +00:00
[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:
parent
2a68e31ffb
commit
e92cee7833
|
@ -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 =
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -288,7 +288,8 @@ class EnumBuilder extends SourceClassBuilder {
|
|||
charOffset,
|
||||
charOffset,
|
||||
charEndOffset,
|
||||
constructorReference);
|
||||
constructorReference,
|
||||
forAbstractClassOrEnum: true);
|
||||
constructors[""] = constructorBuilder;
|
||||
FieldBuilder valuesBuilder = new SourceFieldBuilder(
|
||||
/* metadata = */ null,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {}
|
|
@ -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 {}
|
|
@ -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 {}
|
|
@ -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() {}
|
|
@ -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() {}
|
|
@ -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 {}
|
|
@ -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
|
||||
;
|
|
@ -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 {}
|
|
@ -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';
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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}) {}
|
|
@ -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}) {}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
;
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue