Skip to content

Commit c251133

Browse files
johnniwintherCommit Queue
authored and
Commit Queue
committed
[cfe] Handle record constant equality
Closes #50514 Closes #50515 Change-Id: I942867b3a1fc331428108f63e2b97b8b008c1d55 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/271921 Reviewed-by: Chloe Stefantsova <[email protected]> Commit-Queue: Johnni Winther <[email protected]>
1 parent 1a8b137 commit c251133

18 files changed

+387
-1
lines changed

pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1566,7 +1566,7 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
15661566
// ignore: unnecessary_null_comparison
15671567
assert(named != null);
15681568

1569-
return new RecordConstant(positional, named, node.recordType);
1569+
return canonicalize(new RecordConstant(positional, named, node.recordType));
15701570
}
15711571

15721572
@override
@@ -3634,6 +3634,24 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
36343634

36353635
bool hasPrimitiveEqual(Constant constant) {
36363636
if (intFolder.isInt(constant)) return true;
3637+
if (constant is RecordConstant) {
3638+
bool nonPrimitiveEqualsFound = false;
3639+
for (Constant field in constant.positional) {
3640+
if (!hasPrimitiveEqual(field)) {
3641+
nonPrimitiveEqualsFound = true;
3642+
break;
3643+
}
3644+
}
3645+
for (Constant field in constant.named.values) {
3646+
if (!hasPrimitiveEqual(field)) {
3647+
nonPrimitiveEqualsFound = true;
3648+
break;
3649+
}
3650+
}
3651+
if (nonPrimitiveEqualsFound) {
3652+
return false;
3653+
}
3654+
}
36373655
DartType type = constant.getType(_staticTypeContext!);
36383656
return !(type is InterfaceType && !classHasPrimitiveEqual(type.classNode));
36393657
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
class A {
6+
const A();
7+
}
8+
9+
test() => const <Record>{
10+
const (1, 2, A()),
11+
const (1, 2, A())
12+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue50514.dart:9:11: Error: Constant evaluation error:
6+
// test() => const <Record>{
7+
// ^
8+
// pkg/front_end/testcases/records/issue50514.dart:11:9: Context: The element '(1, 2, A {})' conflicts with another existing element in the set.
9+
// - 'A' is from 'pkg/front_end/testcases/records/issue50514.dart'.
10+
// const (1, 2, A())
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
class A extends core::Object /*hasConstConstructor*/ {
17+
const constructor •() → self::A
18+
: super core::Object::•()
19+
;
20+
}
21+
static method test() → dynamic
22+
return invalid-expression "The element '(1, 2, A {})' conflicts with another existing element in the set.
23+
- 'A' is from 'pkg/front_end/testcases/records/issue50514.dart'.";
24+
25+
26+
27+
Constructor coverage from constants:
28+
org-dartlang-testcase:///issue50514.dart:
29+
- A. (from org-dartlang-testcase:///issue50514.dart:6:9)
30+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue50514.dart:9:11: Error: Constant evaluation error:
6+
// test() => const <Record>{
7+
// ^
8+
// pkg/front_end/testcases/records/issue50514.dart:11:9: Context: The element '(1, 2, A {})' conflicts with another existing element in the set.
9+
// - 'A' is from 'pkg/front_end/testcases/records/issue50514.dart'.
10+
// const (1, 2, A())
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
class A extends core::Object /*hasConstConstructor*/ {
17+
const constructor •() → self::A
18+
: super core::Object::•()
19+
;
20+
}
21+
static method test() → dynamic
22+
return invalid-expression "The element '(1, 2, A {})' conflicts with another existing element in the set.
23+
- 'A' is from 'pkg/front_end/testcases/records/issue50514.dart'.";
24+
25+
26+
27+
Constructor coverage from constants:
28+
org-dartlang-testcase:///issue50514.dart:
29+
- A. (from org-dartlang-testcase:///issue50514.dart:6:9)
30+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class A {
2+
const A();
3+
}
4+
test() => const <Record>{ const (1, 2, A()), const (1, 2, A()) };
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue50514.dart:9:11: Error: Constant evaluation error:
6+
// test() => const <Record>{
7+
// ^
8+
// pkg/front_end/testcases/records/issue50514.dart:11:9: Context: The element '(1, 2, A {})' conflicts with another existing element in the set.
9+
// - 'A' is from 'pkg/front_end/testcases/records/issue50514.dart'.
10+
// const (1, 2, A())
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
class A extends core::Object /*hasConstConstructor*/ {
17+
const constructor •() → self::A
18+
: super core::Object::•()
19+
;
20+
}
21+
static method test() → dynamic
22+
return invalid-expression "The element '(1, 2, A {})' conflicts with another existing element in the set.
23+
- 'A' is from 'pkg/front_end/testcases/records/issue50514.dart'.";
24+
25+
26+
27+
Constructor coverage from constants:
28+
org-dartlang-testcase:///issue50514.dart:
29+
- A. (from org-dartlang-testcase:///issue50514.dart:6:9)
30+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue50514.dart:9:11: Error: Constant evaluation error:
6+
// test() => const <Record>{
7+
// ^
8+
// pkg/front_end/testcases/records/issue50514.dart:11:9: Context: The element '(1, 2, A {})' conflicts with another existing element in the set.
9+
// - 'A' is from 'pkg/front_end/testcases/records/issue50514.dart'.
10+
// const (1, 2, A())
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
class A extends core::Object /*hasConstConstructor*/ {
17+
const constructor •() → self::A
18+
: super core::Object::•()
19+
;
20+
}
21+
static method test() → dynamic
22+
return invalid-expression "The element '(1, 2, A {})' conflicts with another existing element in the set.
23+
- 'A' is from 'pkg/front_end/testcases/records/issue50514.dart'.";
24+
25+
26+
27+
Constructor coverage from constants:
28+
org-dartlang-testcase:///issue50514.dart:
29+
- A. (from org-dartlang-testcase:///issue50514.dart:6:9)
30+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class A extends core::Object /*hasConstConstructor*/ {
6+
const constructor •() → self::A
7+
: super core::Object::•()
8+
;
9+
}
10+
static method test() → dynamic
11+
;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue50514.dart:9:11: Error: Constant evaluation error:
6+
// test() => const <Record>{
7+
// ^
8+
// pkg/front_end/testcases/records/issue50514.dart:11:9: Context: The element '(1, 2, A {})' conflicts with another existing element in the set.
9+
// - 'A' is from 'pkg/front_end/testcases/records/issue50514.dart'.
10+
// const (1, 2, A())
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
class A extends core::Object /*hasConstConstructor*/ {
17+
const constructor •() → self::A
18+
: super core::Object::•()
19+
;
20+
}
21+
static method test() → dynamic
22+
return invalid-expression "The element '(1, 2, A {})' conflicts with another existing element in the set.
23+
- 'A' is from 'pkg/front_end/testcases/records/issue50514.dart'.";
24+
25+
26+
27+
Constructor coverage from constants:
28+
org-dartlang-testcase:///issue50514.dart:
29+
- A. (from org-dartlang-testcase:///issue50514.dart:6:9)
30+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
class A {
6+
const A();
7+
8+
bool operator==(Object other) => false;
9+
}
10+
11+
test() => const <(A,)>{ (A(),) };
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue50515.dart:11:11: Error: Constant evaluation error:
6+
// test() => const <(A,)>{ (A(),) };
7+
// ^
8+
// pkg/front_end/testcases/records/issue50515.dart:11:25: Context: The element '(A {})' does not have a primitive operator '=='.
9+
// - 'A' is from 'pkg/front_end/testcases/records/issue50515.dart'.
10+
// test() => const <(A,)>{ (A(),) };
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
class A extends core::Object /*hasConstConstructor*/ {
17+
const constructor •() → self::A
18+
: super core::Object::•()
19+
;
20+
operator ==(core::Object other) → core::bool
21+
return false;
22+
}
23+
static method test() → dynamic
24+
return invalid-expression "The element '(A {})' does not have a primitive operator '=='.
25+
- 'A' is from 'pkg/front_end/testcases/records/issue50515.dart'.";
26+
27+
28+
29+
Constructor coverage from constants:
30+
org-dartlang-testcase:///issue50515.dart:
31+
- A. (from org-dartlang-testcase:///issue50515.dart:6:9)
32+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue50515.dart:11:11: Error: Constant evaluation error:
6+
// test() => const <(A,)>{ (A(),) };
7+
// ^
8+
// pkg/front_end/testcases/records/issue50515.dart:11:25: Context: The element '(A {})' does not have a primitive operator '=='.
9+
// - 'A' is from 'pkg/front_end/testcases/records/issue50515.dart'.
10+
// test() => const <(A,)>{ (A(),) };
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
class A extends core::Object /*hasConstConstructor*/ {
17+
const constructor •() → self::A
18+
: super core::Object::•()
19+
;
20+
operator ==(core::Object other) → core::bool
21+
return false;
22+
}
23+
static method test() → dynamic
24+
return invalid-expression "The element '(A {})' does not have a primitive operator '=='.
25+
- 'A' is from 'pkg/front_end/testcases/records/issue50515.dart'.";
26+
27+
28+
29+
Constructor coverage from constants:
30+
org-dartlang-testcase:///issue50515.dart:
31+
- A. (from org-dartlang-testcase:///issue50515.dart:6:9)
32+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class A {
2+
const A();
3+
bool operator==(Object other) => false;
4+
}
5+
test() => const <(A,)>{ (A(),) };
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue50515.dart:11:11: Error: Constant evaluation error:
6+
// test() => const <(A,)>{ (A(),) };
7+
// ^
8+
// pkg/front_end/testcases/records/issue50515.dart:11:25: Context: The element '(A {})' does not have a primitive operator '=='.
9+
// - 'A' is from 'pkg/front_end/testcases/records/issue50515.dart'.
10+
// test() => const <(A,)>{ (A(),) };
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
class A extends core::Object /*hasConstConstructor*/ {
17+
const constructor •() → self::A
18+
: super core::Object::•()
19+
;
20+
operator ==(core::Object other) → core::bool
21+
return false;
22+
}
23+
static method test() → dynamic
24+
return invalid-expression "The element '(A {})' does not have a primitive operator '=='.
25+
- 'A' is from 'pkg/front_end/testcases/records/issue50515.dart'.";
26+
27+
28+
29+
Constructor coverage from constants:
30+
org-dartlang-testcase:///issue50515.dart:
31+
- A. (from org-dartlang-testcase:///issue50515.dart:6:9)
32+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/records/issue50515.dart:11:11: Error: Constant evaluation error:
6+
// test() => const <(A,)>{ (A(),) };
7+
// ^
8+
// pkg/front_end/testcases/records/issue50515.dart:11:25: Context: The element '(A {})' does not have a primitive operator '=='.
9+
// - 'A' is from 'pkg/front_end/testcases/records/issue50515.dart'.
10+
// test() => const <(A,)>{ (A(),) };
11+
// ^
12+
//
13+
import self as self;
14+
import "dart:core" as core;
15+
16+
class A extends core::Object /*hasConstConstructor*/ {
17+
const constructor •() → self::A
18+
: super core::Object::•()
19+
;
20+
operator ==(core::Object other) → core::bool
21+
return false;
22+
}
23+
static method test() → dynamic
24+
return invalid-expression "The element '(A {})' does not have a primitive operator '=='.
25+
- 'A' is from 'pkg/front_end/testcases/records/issue50515.dart'.";
26+
27+
28+
29+
Constructor coverage from constants:
30+
org-dartlang-testcase:///issue50515.dart:
31+
- A. (from org-dartlang-testcase:///issue50515.dart:6:9)
32+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class A extends core::Object /*hasConstConstructor*/ {
6+
const constructor •() → self::A
7+
: super core::Object::•()
8+
;
9+
operator ==(core::Object other) → core::bool
10+
;
11+
}
12+
static method test() → dynamic
13+
;

0 commit comments

Comments
 (0)