Report INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR instead of INSTANTIATE_ENUM when enhanced-enums.

Change-Id: I634b3e50641b2b696b4d9e164266b43fdc72f137
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/231063
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov
2022-02-01 23:58:45 +00:00
committed by Commit Bot
parent 0d5eec26f1
commit 22a8295295
10 changed files with 232 additions and 17 deletions
+1
View File
@@ -258,6 +258,7 @@ const List<ErrorCode> errorCodeValues = [
CompileTimeErrorCode.INVALID_MODIFIER_ON_CONSTRUCTOR,
CompileTimeErrorCode.INVALID_MODIFIER_ON_SETTER,
CompileTimeErrorCode.INVALID_OVERRIDE,
CompileTimeErrorCode.INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR,
CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS,
CompileTimeErrorCode.INVALID_SUPER_FORMAL_PARAMETER_LOCATION,
CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_LIST,
@@ -14,6 +14,12 @@ extension ClassElementExtension on ClassElement {
}
}
extension ConstructorElementExtension on ConstructorElement {
bool get isGenerative {
return !isFactory;
}
}
extension ElementAnnotationExtensions on ElementAnnotation {
static final Map<String, TargetKind> _targetKindsByName = {
for (final kind in TargetKind.values) kind.toString(): kind,
+9
View File
@@ -6568,6 +6568,7 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
// instantiated:
//
// ```dart
// // @dart = 2.16
// enum E {a}
//
// var e = [!E!]();
@@ -6579,6 +6580,7 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
// constants defined in the enum:
//
// ```dart
// // @dart = 2.16
// enum E {a}
//
// var e = E.a;
@@ -7499,6 +7501,13 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
hasPublishedDocs: true,
);
static const CompileTimeErrorCode
INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR = CompileTimeErrorCode(
'INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR',
"Generative enum constructors can only be used as targets of redirection.",
correctionMessage: "Try using a factory constructor, or an enum constant.",
);
/**
* No parameters.
*/
@@ -22,6 +22,7 @@ import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/element/class_hierarchy.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/extensions.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
@@ -534,6 +535,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
@override
void visitConstructorReference(ConstructorReference node) {
_typeArgumentsVerifier.checkConstructorReference(node);
_checkForInvalidGenerativeConstructorReference(node.constructorName);
}
@override
@@ -842,7 +844,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
DartType type = namedType.typeOrThrow;
if (type is InterfaceType) {
_checkForConstOrNewWithAbstractClass(node, namedType, type);
_checkForConstOrNewWithEnum(node, namedType, type);
_checkForInvalidGenerativeConstructorReference(constructorName);
_checkForConstOrNewWithMixin(node, namedType, type);
_requiredParametersVerifier.visitInstanceCreationExpression(node);
if (node.isConst) {
@@ -2149,21 +2151,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
}
}
/// Verify that the given instance creation [expression] is not being invoked
/// on an enum. The [namedType] is the [NamedType] of the [ConstructorName] from
/// the [InstanceCreationExpression], this is the AST node that the error is
/// attached to. The [type] is the type being constructed with this
/// [InstanceCreationExpression].
///
/// See [CompileTimeErrorCode.INSTANTIATE_ENUM].
void _checkForConstOrNewWithEnum(InstanceCreationExpression expression,
NamedType namedType, InterfaceType type) {
if (type.element.isEnum) {
errorReporter.reportErrorForNode(
CompileTimeErrorCode.INSTANTIATE_ENUM, namedType);
}
}
/// Verify that the given [expression] is not a mixin instantiation.
void _checkForConstOrNewWithMixin(InstanceCreationExpression expression,
NamedType namedType, InterfaceType type) {
@@ -2902,6 +2889,25 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
}
}
void _checkForInvalidGenerativeConstructorReference(ConstructorName node) {
var constructorElement = node.staticElement;
if (constructorElement != null &&
constructorElement.isGenerative &&
constructorElement.enclosingElement.isEnum) {
if (_currentLibrary.featureSet.isEnabled(Feature.enhanced_enums)) {
errorReporter.reportErrorForNode(
CompileTimeErrorCode.INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR,
node,
);
} else {
errorReporter.reportErrorForNode(
CompileTimeErrorCode.INSTANTIATE_ENUM,
node.type2,
);
}
}
}
/// Verify that if the given [identifier] is part of a constructor
/// initializer, then it does not implicitly reference 'this' expression.
///
+5
View File
@@ -5713,6 +5713,7 @@ CompileTimeErrorCode:
instantiated:
```dart
// @dart = 2.16
enum E {a}
var e = [!E!]();
@@ -5724,6 +5725,7 @@ CompileTimeErrorCode:
constants defined in the enum:
```dart
// @dart = 2.16
enum E {a}
var e = E.a;
@@ -6504,6 +6506,9 @@ CompileTimeErrorCode:
void m2(String s) {}
}
```
INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR:
problemMessage: Generative enum constructors can only be used as targets of redirection.
correctionMessage: Try using a factory constructor, or an enum constant.
INVALID_REFERENCE_TO_THIS:
problemMessage: "Invalid reference to 'this' expression."
hasPublishedDocs: true
@@ -440,6 +440,11 @@ mixin WithoutConstructorTearoffsMixin on PubPackageResolutionTest {
String? get testPackageLanguageVersion => '2.14';
}
mixin WithoutEnhancedEnumsMixin on PubPackageResolutionTest {
@override
String? get testPackageLanguageVersion => '2.16';
}
mixin WithoutNullSafetyMixin on PubPackageResolutionTest {
@override
String? get testPackageLanguageVersion => '2.9';
@@ -14,7 +14,8 @@ main() {
}
@reflectiveTest
class InstantiateEnumTest extends PubPackageResolutionTest {
class InstantiateEnumTest extends PubPackageResolutionTest
with WithoutEnhancedEnumsMixin {
test_const() async {
await assertErrorsInCode(r'''
enum E { ONE }
@@ -0,0 +1,177 @@
// Copyright (c) 2022, 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.
import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(InvalidReferenceToGenerativeEnumConstructorTest);
});
}
@reflectiveTest
class InvalidReferenceToGenerativeEnumConstructorTest
extends PubPackageResolutionTest {
test_factory_named() async {
await assertNoErrorsInCode('''
enum E {
v();
factory E.named() => v;
}
void f() {
E.named;
E.named();
}
''');
}
test_factory_unnamed() async {
await assertNoErrorsInCode('''
enum E {
v.named();
const E.named();
factory E() => v;
}
void f() {
E.new;
E();
}
''');
}
test_generative_named_constructorReference() async {
await assertErrorsInCode('''
enum E {
v.named();
const E.named();
}
void f() {
E.named;
}
''', [
error(
CompileTimeErrorCode.INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR,
58,
7),
]);
}
test_generative_named_instanceCreation_implicitNew() async {
await assertErrorsInCode('''
enum E {
v.named();
const E.named();
}
void f() {
E.named();
}
''', [
error(
CompileTimeErrorCode.INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR,
58,
7),
]);
}
test_generative_named_redirectingConstructorInvocation() async {
await assertNoErrorsInCode('''
enum E {
v;
const E() : this.named();
const E.named();
}
''');
}
test_generative_unnamed_constructorReference() async {
await assertErrorsInCode('''
enum E {
v
}
void f() {
E.new;
}
''', [
error(
CompileTimeErrorCode.INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR,
29,
5),
]);
}
test_generative_unnamed_instanceCreation_explicitConst() async {
await assertErrorsInCode('''
enum E {
v
}
void f() {
const E();
}
''', [
error(
CompileTimeErrorCode.INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR,
35,
1),
]);
}
test_generative_unnamed_instanceCreation_explicitNew() async {
await assertErrorsInCode('''
enum E {
v
}
void f() {
new E();
}
''', [
error(
CompileTimeErrorCode.INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR,
33,
1),
]);
}
test_generative_unnamed_instanceCreation_implicitNew() async {
await assertErrorsInCode('''
enum E {
v
}
void f() {
E();
}
''', [
error(
CompileTimeErrorCode.INVALID_REFERENCE_TO_GENERATIVE_ENUM_CONSTRUCTOR,
29,
1),
]);
}
test_generative_unnamed_redirectingConstructorInvocation() async {
await assertNoErrorsInCode('''
enum E {
v;
const E();
const E.named() : this();
}
''');
}
}
@@ -341,6 +341,8 @@ import 'invalid_override_different_default_values_positional_test.dart'
import 'invalid_override_of_non_virtual_member_test.dart'
as invalid_override_of_non_virtual_member;
import 'invalid_override_test.dart' as invalid_override;
import 'invalid_reference_to_generative_enum_constructor_test.dart'
as invalid_reference_to_generative_enum_constructor;
import 'invalid_reference_to_this_test.dart' as invalid_reference_to_this;
import 'invalid_required_named_param_test.dart' as invalid_required_named_param;
import 'invalid_required_optional_positional_param_test.dart'
@@ -976,6 +978,7 @@ main() {
invalid_override_different_default_values_positional.main();
invalid_override_of_non_virtual_member.main();
invalid_override.main();
invalid_reference_to_generative_enum_constructor.main();
invalid_reference_to_this.main();
invalid_required_named_param.main();
invalid_required_optional_positional_param.main();
@@ -6616,6 +6616,7 @@ The following code produces this diagnostic because the enum `E` is being
instantiated:
{% prettify dart tag=pre+code %}
// @dart = 2.16
enum E {a}
var e = [!E!]();
@@ -6627,6 +6628,7 @@ If you intend to use an instance of the enum, then reference one of the
constants defined in the enum:
{% prettify dart tag=pre+code %}
// @dart = 2.16
enum E {a}
var e = E.a;