Issue 50104. Report when a const Set element or Map key have non-primitive '=='.

Bug: https://github.com/dart-lang/sdk/issues/50104
Change-Id: Ia60fde7873c3cce27cbb46d45087b0e57b42d42f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/262127
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2022-10-03 19:07:15 +00:00 committed by Commit Queue
parent 23b0ac68b2
commit 572c0c3cee
4 changed files with 129 additions and 0 deletions

View file

@ -20,6 +20,7 @@ import 'package:analyzer/src/dart/constant/evaluation.dart';
import 'package:analyzer/src/dart/constant/potentially_constant.dart';
import 'package:analyzer/src/dart/constant/value.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/extensions.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/diagnostic/diagnostic_factory.dart';
import 'package:analyzer/src/error/codes.dart';
@ -380,6 +381,11 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
// there is == that we don't like
return true;
}
if (type is RecordType) {
return type.fields
.map((field) => field.type)
.any(_implementsEqualsWhenNotAllowed);
}
return false;
}

View file

@ -140,6 +140,13 @@ extension RecordTypeExtension on RecordType {
/// A regular expression used to match positional field names.
static final RegExp _positionalName = RegExp(r'^\$(([0-9])|([1-9][0-9]*))$');
List<RecordTypeField> get fields {
return [
...positionalFields,
...namedFields,
];
}
/// The [name] is either an actual name like `foo` in `({int foo})`, or
/// the name of a positional field like `$0` in `(int, String)`.
RecordTypeField? fieldByName(String name) {

View file

@ -130,6 +130,66 @@ main() {
]);
}
test_record_notPrimitiveEqual_named() async {
await assertErrorsInCode(r'''
class A {
const A();
operator ==(other) => false;
}
const x = {
(a: 0, b: const A()): 0,
};
''', [
error(
CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS,
71,
20),
]);
}
test_record_notPrimitiveEqual_positional() async {
await assertErrorsInCode(r'''
class A {
const A();
operator ==(other) => false;
}
const x = {
(0, const A()): 0,
};
''', [
error(
CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS,
71,
14),
]);
}
test_record_primitiveEqual_named() async {
await assertNoErrorsInCode(r'''
class A {
const A();
}
const x = {
(a: 0, b: const A()): 0,
};
''');
}
test_record_primitiveEqual_positional() async {
await assertNoErrorsInCode(r'''
class A {
const A();
}
const x = {
(0, const A()): 0,
};
''');
}
test_super() async {
await assertErrorsInCode(r'''
class A {

View file

@ -111,6 +111,62 @@ main() {
]);
}
test_record_notPrimitiveEqual_named() async {
await assertErrorsInCode(r'''
class A {
const A();
operator ==(other) => false;
}
const x = {
(a: 0, b: const A()),
};
''', [
error(CompileTimeErrorCode.CONST_SET_ELEMENT_TYPE_IMPLEMENTS_EQUALS, 71,
20),
]);
}
test_record_notPrimitiveEqual_positional() async {
await assertErrorsInCode(r'''
class A {
const A();
operator ==(other) => false;
}
const x = {
(0, const A()),
};
''', [
error(CompileTimeErrorCode.CONST_SET_ELEMENT_TYPE_IMPLEMENTS_EQUALS, 71,
14),
]);
}
test_record_primitiveEqual_named() async {
await assertNoErrorsInCode(r'''
class A {
const A();
}
const x = {
(a: 0, b: const A()),
};
''');
}
test_record_primitiveEqual_positional() async {
await assertNoErrorsInCode(r'''
class A {
const A();
}
const x = {
(0, const A()),
};
''');
}
test_spread_intoList_list() async {
await assertNoErrorsInCode(r'''
class A {