From b5d4d26abe23b9e0eba8be04c0d7f3b26cfc080e Mon Sep 17 00:00:00 2001 From: Kallen Tu Date: Tue, 6 Apr 2021 19:46:32 +0000 Subject: [PATCH] [cfe] Const factories when const functions enabled. Change-Id: Ifd24678c0ac191c5cc6f1d60443ab96f56cbba7d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/192400 Reviewed-by: Dmitry Stefantsov Reviewed-by: Jake Macdonald Reviewed-by: Jens Johansen Commit-Queue: Kallen Tu --- .../lib/src/parser/forwarding_listener.dart | 5 +++ .../lib/src/parser/listener.dart | 4 ++ .../lib/src/parser/parser_impl.dart | 2 +- pkg/analyzer/lib/src/fasta/ast_builder.dart | 8 ++++ .../lib/src/fasta/kernel/body_builder.dart | 9 +++++ .../src/fasta/kernel/constant_evaluator.dart | 5 +++ .../lib/src/fasta/source/diet_listener.dart | 5 +++ .../lib/src/fasta/source/outline_builder.dart | 8 ++++ .../fasta/util/direct_parser_ast_helper.dart | 19 ++++++++++ pkg/front_end/test/parser_test_listener.dart | 5 +++ .../const_functions_const_factory.dart | 30 +++++++++++++++ ...functions_const_factory.dart.strong.expect | 38 +++++++++++++++++++ ...nst_factory.dart.strong.transformed.expect | 38 +++++++++++++++++++ ..._const_factory.dart.textual_outline.expect | 10 +++++ ...ctory.dart.textual_outline_modelled.expect | 12 ++++++ ...t_functions_const_factory.dart.weak.expect | 38 +++++++++++++++++++ ...ons_const_factory.dart.weak.outline.expect | 25 ++++++++++++ ...const_factory.dart.weak.transformed.expect | 38 +++++++++++++++++++ pkg/front_end/testcases/outline.status | 1 + .../testcases/textual_outline.status | 2 +- ...functions_const_factory_disabled_test.dart | 29 ++++++++++++++ .../const_functions_const_factory_test.dart | 34 +++++++++++++++++ 22 files changed, 363 insertions(+), 2 deletions(-) create mode 100644 pkg/front_end/testcases/const_functions/const_functions_const_factory.dart create mode 100644 pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.expect create mode 100644 pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.transformed.expect create mode 100644 pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline.expect create mode 100644 pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline_modelled.expect create mode 100644 pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.expect create mode 100644 pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.outline.expect create mode 100644 pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.transformed.expect create mode 100644 tests/language/const_functions/const_functions_const_factory_disabled_test.dart create mode 100644 tests/language/const_functions/const_functions_const_factory_test.dart diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart index 0274d640039..14021027f77 100644 --- a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart +++ b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart @@ -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) { diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart index bb635b6ab9f..0e08a2e5df6 100644 --- a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart +++ b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart @@ -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) {} diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart index 1fe9144c7ac..93d7a7b9671 100644 --- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart +++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart @@ -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( diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart index a43c3305c88..00365126a62 100644 --- a/pkg/analyzer/lib/src/fasta/ast_builder.dart +++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart @@ -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) { diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart index ccf323b533b..11692c2eb6d 100644 --- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart +++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart @@ -4768,6 +4768,15 @@ class BodyBuilder extends ScopeListener 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 diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart index 645bbd9f52d..5178dfabbbd 100644 --- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart +++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart @@ -2783,6 +2783,11 @@ class ConstantEvaluator implements ExpressionVisitor { } else { name = '${target.enclosingClass.name}.${name}'; } + + if (enableConstFunctions) { + return _handleFunctionInvocation( + node.target.function, typeArguments, positionals, named); + } } return createInvalidExpressionConstant(node, "Invocation of $name"); } diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart index 3d05b76cd1e..c5664f87a7e 100644 --- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart +++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart @@ -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"); diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart index 96b6ff5f902..6e7b86a947b 100644 --- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart @@ -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"); diff --git a/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart b/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart index cc765768401..fe06b7696e1 100644 --- a/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart +++ b/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart @@ -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 get deprecatedArguments => { + "constKeyword": constKeyword, + }; +} + class DirectParserASTContentForControlFlowBegin extends DirectParserASTContent { final Token awaitToken; final Token forToken; diff --git a/pkg/front_end/test/parser_test_listener.dart b/pkg/front_end/test/parser_test_listener.dart index fca16c885a3..8ffa24f0a8a 100644 --- a/pkg/front_end/test/parser_test_listener.dart +++ b/pkg/front_end/test/parser_test_listener.dart @@ -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); diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart new file mode 100644 index 00000000000..08f2b7667c8 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart @@ -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); +} diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.expect new file mode 100644 index 00000000000..c9674e9e429 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.expect @@ -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) diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.transformed.expect new file mode 100644 index 00000000000..c9674e9e429 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.transformed.expect @@ -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) diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline.expect new file mode 100644 index 00000000000..5caeecac1e6 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline.expect @@ -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() {} diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..cb1859def56 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline_modelled.expect @@ -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() {} diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.expect new file mode 100644 index 00000000000..c9674e9e429 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.expect @@ -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) diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.outline.expect new file mode 100644 index 00000000000..fe4b8633260 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.outline.expect @@ -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 diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.transformed.expect new file mode 100644 index 00000000000..c9674e9e429 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.transformed.expect @@ -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) diff --git a/pkg/front_end/testcases/outline.status b/pkg/front_end/testcases/outline.status index 8c4bb20c50c..dc7cac2ba32 100644 --- a/pkg/front_end/testcases/outline.status +++ b/pkg/front_end/testcases/outline.status @@ -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 diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status index 408c9ce3a90..6dd5ffb2b92 100644 --- a/pkg/front_end/testcases/textual_outline.status +++ b/pkg/front_end/testcases/textual_outline.status @@ -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 diff --git a/tests/language/const_functions/const_functions_const_factory_disabled_test.dart b/tests/language/const_functions/const_functions_const_factory_disabled_test.dart new file mode 100644 index 00000000000..e6bf9c6a965 --- /dev/null +++ b/tests/language/const_functions/const_functions_const_factory_disabled_test.dart @@ -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); +} diff --git a/tests/language/const_functions/const_functions_const_factory_test.dart b/tests/language/const_functions/const_functions_const_factory_test.dart new file mode 100644 index 00000000000..2ff63bc6a75 --- /dev/null +++ b/tests/language/const_functions/const_functions_const_factory_test.dart @@ -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); +}