[cfe] Const factories when const functions enabled.

Change-Id: Ifd24678c0ac191c5cc6f1d60443ab96f56cbba7d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/192400
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
This commit is contained in:
Kallen Tu
2021-04-06 19:46:32 +00:00
committed by commit-bot@chromium.org
parent a38a2dd343
commit b5d4d26abe
22 changed files with 363 additions and 2 deletions
@@ -1173,6 +1173,11 @@ class ForwardingListener implements Listener {
listener?.handleConditionalExpressionColon();
}
@override
void handleConstFactory(Token constKeyword) {
listener?.handleConstFactory(constKeyword);
}
@override
void handleContinueStatement(
bool hasTarget, Token continueKeyword, Token endToken) {
@@ -1360,6 +1360,10 @@ class Listener implements UnescapeErrorListener {
logEvent("ConstExpression");
}
void handleConstFactory(Token constKeyword) {
logEvent("ConstFactory");
}
/// Called before parsing a "for" control flow list, set, or map entry.
/// Ended by either [endForControlFlow] or [endForInControlFlow].
void beginForControlFlow(Token? awaitToken, Token forToken) {}
@@ -4063,7 +4063,7 @@ class Parser {
} else {
if (varFinalOrConst != null && !optional('native', next)) {
if (optional('const', varFinalOrConst)) {
reportRecoverableError(varFinalOrConst, codes.messageConstFactory);
listener.handleConstFactory(varFinalOrConst);
}
}
token = parseFunctionBody(
@@ -11,6 +11,7 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
messageAbstractLateField,
messageAbstractStaticField,
messageConstConstructorWithBody,
messageConstFactory,
messageConstructorWithTypeParameters,
messageDirectiveAfterDeclaration,
messageExpectedStatement,
@@ -2574,6 +2575,13 @@ class AstBuilder extends StackListener {
push(referenceOffset);
}
@override
void handleConstFactory(Token constKeyword) {
debugEvent("ConstFactory");
// TODO(kallentu): Removal of const factory error for const function feature
handleRecoverableError(messageConstFactory, constKeyword, constKeyword);
}
@override
void handleContinueStatement(
bool hasTarget, Token continueKeyword, Token semicolon) {
@@ -4768,6 +4768,15 @@ class BodyBuilder extends ScopeListener<JumpTarget>
inMetadata: false);
}
@override
void handleConstFactory(Token constKeyword) {
debugEvent("ConstFactory");
if (!libraryBuilder.enableConstFunctionsInLibrary) {
handleRecoverableError(
fasta.messageConstFactory, constKeyword, constKeyword);
}
}
@override
void beginIfControlFlow(Token ifToken) {
// TODO(danrubel): consider removing this when control flow support is added
@@ -2783,6 +2783,11 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
} else {
name = '${target.enclosingClass.name}.${name}';
}
if (enableConstFunctions) {
return _handleFunctionInvocation(
node.target.function, typeArguments, positionals, named);
}
}
return createInvalidExpressionConstant(node, "Invocation of $name");
}
@@ -632,6 +632,11 @@ class DietListener extends StackListenerImpl {
_inRedirectingFactory = true;
}
@override
void handleConstFactory(Token constKeyword) {
debugEvent("ConstFactory");
}
@override
void handleNativeFunctionBody(Token nativeToken, Token semicolon) {
debugEvent("NativeFunctionBody");
@@ -2044,6 +2044,14 @@ class OutlineBuilder extends StackListenerImpl {
push(MethodBody.RedirectingFactoryBody);
}
@override
void handleConstFactory(Token constKeyword) {
debugEvent("ConstFactory");
if (!libraryBuilder.enableConstFunctionsInLibrary) {
handleRecoverableError(messageConstFactory, constKeyword, constKeyword);
}
}
@override
void endFieldInitializer(Token assignmentOperator, Token token) {
debugEvent("FieldInitializer");
@@ -1970,6 +1970,13 @@ abstract class AbstractDirectParserASTListener implements Listener {
seen(data);
}
void handleConstFactory(Token constKeyword) {
DirectParserASTContentConstFactoryHandle data =
new DirectParserASTContentConstFactoryHandle(DirectParserASTType.HANDLE,
constKeyword: constKeyword);
seen(data);
}
void beginForControlFlow(Token awaitToken, Token forToken) {
DirectParserASTContentForControlFlowBegin data =
new DirectParserASTContentForControlFlowBegin(DirectParserASTType.BEGIN,
@@ -5814,6 +5821,18 @@ class DirectParserASTContentConstExpressionEnd extends DirectParserASTContent {
};
}
class DirectParserASTContentConstFactoryHandle extends DirectParserASTContent {
final Token constKeyword;
DirectParserASTContentConstFactoryHandle(DirectParserASTType type,
{this.constKeyword})
: super("ConstFactory", type);
Map<String, Object> get deprecatedArguments => {
"constKeyword": constKeyword,
};
}
class DirectParserASTContentForControlFlowBegin extends DirectParserASTContent {
final Token awaitToken;
final Token forToken;
@@ -1765,6 +1765,11 @@ class ParserTestListener implements Listener {
doPrint('endConstExpression(' '$token)');
}
void handleConstFactory(Token constKeyword) {
seen(constKeyword);
doPrint('handleConstFactory(' '$constKeyword)');
}
void beginForControlFlow(Token? awaitToken, Token forToken) {
seen(awaitToken);
seen(forToken);
@@ -0,0 +1,30 @@
// 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.
// Tests const factories with const functions.
import "package:expect/expect.dart";
const printConst = MessageType.parse("print");
class MessageType {
static const print = MessageType._('print');
static const skip = MessageType._('skip');
final String name;
const factory MessageType.parse(String name) {
if (name == 'print') {
return MessageType.print;
}
return MessageType.skip;
}
const MessageType._(this.name);
}
void main() {
Expect.equals(printConst, MessageType.print);
}
@@ -0,0 +1,38 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
class MessageType extends core::Object /*hasConstConstructor*/ {
static const field self::MessageType print = #C2;
static const field self::MessageType skip = #C4;
final field core::String name;
const constructor _(core::String name) → self::MessageType
: self::MessageType::name = name, super core::Object::•()
;
static factory parse(core::String name) → self::MessageType {
if(name.{core::String::==}("print")) {
return #C2;
}
return #C4;
}
}
static const field self::MessageType printConst = #C2;
static method main() → void {
exp::Expect::equals(#C2, #C2);
}
constants {
#C1 = "print"
#C2 = self::MessageType {name:#C1}
#C3 = "skip"
#C4 = self::MessageType {name:#C3}
}
Constructor coverage from constants:
org-dartlang-testcase:///const_functions_const_factory.dart:
- MessageType._ (from org-dartlang-testcase:///const_functions_const_factory.dart:25:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
@@ -0,0 +1,38 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
class MessageType extends core::Object /*hasConstConstructor*/ {
static const field self::MessageType print = #C2;
static const field self::MessageType skip = #C4;
final field core::String name;
const constructor _(core::String name) → self::MessageType
: self::MessageType::name = name, super core::Object::•()
;
static factory parse(core::String name) → self::MessageType {
if(name.{core::String::==}("print")) {
return #C2;
}
return #C4;
}
}
static const field self::MessageType printConst = #C2;
static method main() → void {
exp::Expect::equals(#C2, #C2);
}
constants {
#C1 = "print"
#C2 = self::MessageType {name:#C1}
#C3 = "skip"
#C4 = self::MessageType {name:#C3}
}
Constructor coverage from constants:
org-dartlang-testcase:///const_functions_const_factory.dart:
- MessageType._ (from org-dartlang-testcase:///const_functions_const_factory.dart:25:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
@@ -0,0 +1,10 @@
import "package:expect/expect.dart";
const printConst = MessageType.parse("print");
class MessageType {
static const print = MessageType._('print');
static const skip = MessageType._('skip');
final String name;
const factory MessageType.parse(String name) {}
const MessageType._(this.name);
}
void main() {}
@@ -0,0 +1,12 @@
import "package:expect/expect.dart";
class MessageType {
const MessageType._(this.name);
const factory MessageType.parse(String name) {}
final String name;
static const print = MessageType._('print');
static const skip = MessageType._('skip');
}
const printConst = MessageType.parse("print");
void main() {}
@@ -0,0 +1,38 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
class MessageType extends core::Object /*hasConstConstructor*/ {
static const field self::MessageType print = #C2;
static const field self::MessageType skip = #C4;
final field core::String name;
const constructor _(core::String name) → self::MessageType
: self::MessageType::name = name, super core::Object::•()
;
static factory parse(core::String name) → self::MessageType {
if(name.{core::String::==}("print")) {
return #C2;
}
return #C4;
}
}
static const field self::MessageType printConst = #C2;
static method main() → void {
exp::Expect::equals(#C2, #C2);
}
constants {
#C1 = "print"
#C2 = self::MessageType {name:#C1}
#C3 = "skip"
#C4 = self::MessageType {name:#C3}
}
Constructor coverage from constants:
org-dartlang-testcase:///const_functions_const_factory.dart:
- MessageType._ (from org-dartlang-testcase:///const_functions_const_factory.dart:25:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
@@ -0,0 +1,25 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart";
class MessageType extends core::Object /*hasConstConstructor*/ {
static const field self::MessageType print = const self::MessageType::_("print");
static const field self::MessageType skip = const self::MessageType::_("skip");
final field core::String name;
const constructor _(core::String name) → self::MessageType
: self::MessageType::name = name, super core::Object::•()
;
static const factory parse(core::String name) → self::MessageType
;
}
static const field self::MessageType printConst = const self::MessageType::parse("print");
static method main() → void
;
Extra constant evaluation status:
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_const_factory.dart:12:36 -> InstanceConstant(const MessageType{MessageType.name: "print"})
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_const_factory.dart:14:35 -> InstanceConstant(const MessageType{MessageType.name: "skip"})
Extra constant evaluation: evaluated: 4, effectively constant: 2
@@ -0,0 +1,38 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
class MessageType extends core::Object /*hasConstConstructor*/ {
static const field self::MessageType print = #C2;
static const field self::MessageType skip = #C4;
final field core::String name;
const constructor _(core::String name) → self::MessageType
: self::MessageType::name = name, super core::Object::•()
;
static factory parse(core::String name) → self::MessageType {
if(name.{core::String::==}("print")) {
return #C2;
}
return #C4;
}
}
static const field self::MessageType printConst = #C2;
static method main() → void {
exp::Expect::equals(#C2, #C2);
}
constants {
#C1 = "print"
#C2 = self::MessageType {name:#C1}
#C3 = "skip"
#C4 = self::MessageType {name:#C3}
}
Constructor coverage from constants:
org-dartlang-testcase:///const_functions_const_factory.dart:
- MessageType._ (from org-dartlang-testcase:///const_functions_const_factory.dart:25:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+1
View File
@@ -2,6 +2,7 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE.md file.
const_functions/const_functions_const_factory: VerificationError
extension_types/simple: ExpectationFileMismatchSerialized
extension_types/simple_getter_resolution: ExpectationFileMismatchSerialized
extension_types/simple_method_resolution: ExpectationFileMismatchSerialized
@@ -20,7 +20,7 @@ regress/issue_39035.crash: EmptyOutput
regress/issue_39091_2: EmptyOutput
regress/utf_16_le_content.crash: EmptyOutput
const_functions/const_functions_const_factory: FormatterCrash
extensions/extension_constructor: FormatterCrash
extensions/extension_field_with_type_parameter_usage: FormatterCrash
extensions/issue38600: FormatterCrash
@@ -0,0 +1,29 @@
// 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.
// Tests const factories with const functions disabled.
import "package:expect/expect.dart";
const printConst = MessageType.parse("print");
class MessageType {
static const print = MessageType._('print');
static const skip = MessageType._('skip');
final String name;
const factory MessageType.parse(String name) {
//^^^^^
// [analyzer] SYNTACTIC_ERROR.CONST_FACTORY
// [cfe] Only redirecting factory constructors can be declared to be 'const'.
if (name == 'print') {
return MessageType.print;
}
return MessageType.skip;
}
const MessageType._(this.name);
}
@@ -0,0 +1,34 @@
// 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.
// Tests const factories with const functions.
// SharedOptions=--enable-experiment=const-functions
import "package:expect/expect.dart";
const printConst = MessageType.parse("print");
class MessageType {
static const print = MessageType._('print');
static const skip = MessageType._('skip');
final String name;
const factory MessageType.parse(String name) {
//^^^^^
// [analyzer] SYNTACTIC_ERROR.CONST_FACTORY
if (name == 'print') {
return MessageType.print;
}
return MessageType.skip;
}
const MessageType._(this.name);
}
void main() {
Expect.equals(printConst, MessageType.print);
}