Skip to content

Commit ad15774

Browse files
scheglovCommit Queue
authored and
Commit Queue
committed
Issue 51567. Implement constant equality as primitive equality
Bug: #51567 Change-Id: I7821598a761573519205b0ea06b13f433639282b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286241 Commit-Queue: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 16e935e commit ad15774

File tree

6 files changed

+374
-49
lines changed

6 files changed

+374
-49
lines changed

pkg/analyzer/lib/src/dart/constant/evaluation.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
544544
_substitution = substitution {
545545
_dartObjectComputer = DartObjectComputer(
546546
typeSystem,
547+
_library.featureSet,
547548
_errorReporter,
548549
);
549550
}
@@ -1566,11 +1567,12 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
15661567
/// class and for collecting errors during evaluation.
15671568
class DartObjectComputer {
15681569
final TypeSystemImpl _typeSystem;
1570+
final FeatureSet _featureSet;
15691571

15701572
/// The error reporter that we are using to collect errors.
15711573
final ErrorReporter _errorReporter;
15721574

1573-
DartObjectComputer(this._typeSystem, this._errorReporter);
1575+
DartObjectComputer(this._typeSystem, this._featureSet, this._errorReporter);
15741576

15751577
DartObjectImpl? add(BinaryExpression node, DartObjectImpl? leftOperand,
15761578
DartObjectImpl? rightOperand) {
@@ -1698,7 +1700,7 @@ class DartObjectComputer {
16981700
DartObjectImpl? rightOperand) {
16991701
if (leftOperand != null && rightOperand != null) {
17001702
try {
1701-
return leftOperand.equalEqual(_typeSystem, rightOperand);
1703+
return leftOperand.equalEqual(_typeSystem, _featureSet, rightOperand);
17021704
} on EvaluationException catch (exception) {
17031705
_errorReporter.reportErrorForNode(exception.errorCode, node);
17041706
}
@@ -1770,7 +1772,8 @@ class DartObjectComputer {
17701772
DartObjectImpl? rightOperand) {
17711773
if (leftOperand != null && rightOperand != null) {
17721774
try {
1773-
return leftOperand.lazyEqualEqual(_typeSystem, rightOperand);
1775+
return leftOperand.lazyEqualEqual(
1776+
_typeSystem, _featureSet, rightOperand);
17741777
} on EvaluationException catch (exception) {
17751778
_errorReporter.reportErrorForNode(exception.errorCode, node);
17761779
}
@@ -1878,7 +1881,7 @@ class DartObjectComputer {
18781881
DartObjectImpl? rightOperand) {
18791882
if (leftOperand != null && rightOperand != null) {
18801883
try {
1881-
return leftOperand.notEqual(_typeSystem, rightOperand);
1884+
return leftOperand.notEqual(_typeSystem, _featureSet, rightOperand);
18821885
} on EvaluationException catch (exception) {
18831886
_errorReporter.reportErrorForNode(exception.errorCode, node);
18841887
}

pkg/analyzer/lib/src/dart/constant/value.dart

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,10 @@ class DartObjectImpl implements DartObject {
429429
/// Throws an [EvaluationException] if the operator is not appropriate for an
430430
/// object of this kind.
431431
DartObjectImpl equalEqual(
432-
TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
432+
TypeSystemImpl typeSystem,
433+
FeatureSet featureSet,
434+
DartObjectImpl rightOperand,
435+
) {
433436
if (isNull || rightOperand.isNull) {
434437
return DartObjectImpl(
435438
typeSystem,
@@ -439,12 +442,22 @@ class DartObjectImpl implements DartObject {
439442
: BoolState.FALSE_STATE,
440443
);
441444
}
442-
if (isBoolNumStringOrNull) {
443-
return DartObjectImpl(
444-
typeSystem,
445-
typeSystem.typeProvider.boolType,
446-
state.equalEqual(typeSystem, rightOperand.state),
447-
);
445+
if (featureSet.isEnabled(Feature.patterns)) {
446+
if (state is DoubleState || hasPrimitiveEquality(featureSet)) {
447+
return DartObjectImpl(
448+
typeSystem,
449+
typeSystem.typeProvider.boolType,
450+
state.equalEqual(typeSystem, rightOperand.state),
451+
);
452+
}
453+
} else {
454+
if (isBoolNumStringOrNull) {
455+
return DartObjectImpl(
456+
typeSystem,
457+
typeSystem.typeProvider.boolType,
458+
state.equalEqual(typeSystem, rightOperand.state),
459+
);
460+
}
448461
}
449462
throw EvaluationException(
450463
CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
@@ -598,7 +611,10 @@ class DartObjectImpl implements DartObject {
598611
/// Throws an [EvaluationException] if the operator is not appropriate for an
599612
/// object of this kind.
600613
DartObjectImpl lazyEqualEqual(
601-
TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
614+
TypeSystemImpl typeSystem,
615+
FeatureSet featureSet,
616+
DartObjectImpl rightOperand,
617+
) {
602618
if (isNull || rightOperand.isNull) {
603619
return DartObjectImpl(
604620
typeSystem,
@@ -608,12 +624,22 @@ class DartObjectImpl implements DartObject {
608624
: BoolState.FALSE_STATE,
609625
);
610626
}
611-
if (isBoolNumStringOrNull) {
612-
return DartObjectImpl(
613-
typeSystem,
614-
typeSystem.typeProvider.boolType,
615-
state.lazyEqualEqual(typeSystem, rightOperand.state),
616-
);
627+
if (featureSet.isEnabled(Feature.patterns)) {
628+
if (state is DoubleState || hasPrimitiveEquality(featureSet)) {
629+
return DartObjectImpl(
630+
typeSystem,
631+
typeSystem.typeProvider.boolType,
632+
state.equalEqual(typeSystem, rightOperand.state),
633+
);
634+
}
635+
} else {
636+
if (isBoolNumStringOrNull) {
637+
return DartObjectImpl(
638+
typeSystem,
639+
typeSystem.typeProvider.boolType,
640+
state.equalEqual(typeSystem, rightOperand.state),
641+
);
642+
}
617643
}
618644
throw EvaluationException(
619645
CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
@@ -739,8 +765,12 @@ class DartObjectImpl implements DartObject {
739765
/// Throws an [EvaluationException] if the operator is not appropriate for an
740766
/// object of this kind.
741767
DartObjectImpl notEqual(
742-
TypeSystemImpl typeSystem, DartObjectImpl rightOperand) {
743-
return equalEqual(typeSystem, rightOperand).logicalNot(typeSystem);
768+
TypeSystemImpl typeSystem,
769+
FeatureSet featureSet,
770+
DartObjectImpl rightOperand,
771+
) {
772+
return equalEqual(typeSystem, featureSet, rightOperand)
773+
.logicalNot(typeSystem);
744774
}
745775

746776
/// Return the result of converting this object to a 'String'.

pkg/analyzer/test/src/dart/constant/evaluation_test.dart

Lines changed: 173 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,166 @@ main() {
2929
@reflectiveTest
3030
class ConstantVisitorTest extends ConstantVisitorTestSupport
3131
with ConstantVisitorTestCases {
32+
test_equalEqual_double_object() async {
33+
await assertNoErrorsInCode('''
34+
const v = 1.2 == Object();
35+
''');
36+
final value = _evaluateConstant('v');
37+
assertDartObjectText(value, r'''
38+
bool false
39+
''');
40+
}
41+
42+
test_equalEqual_int_int_false() async {
43+
await assertNoErrorsInCode('''
44+
const v = 1 == 2;
45+
''');
46+
final value = _evaluateConstant('v');
47+
assertDartObjectText(value, r'''
48+
bool false
49+
''');
50+
}
51+
52+
test_equalEqual_int_int_true() async {
53+
await assertNoErrorsInCode('''
54+
const v = 1 == 1;
55+
''');
56+
final value = _evaluateConstant('v');
57+
assertDartObjectText(value, r'''
58+
bool true
59+
''');
60+
}
61+
62+
test_equalEqual_int_null() async {
63+
await assertNoErrorsInCode('''
64+
const int? a = 1;
65+
const v = a == null;
66+
''');
67+
final value = _evaluateConstant('v');
68+
assertDartObjectText(value, r'''
69+
bool false
70+
''');
71+
}
72+
73+
test_equalEqual_int_object() async {
74+
await assertNoErrorsInCode('''
75+
const v = 1 == Object();
76+
''');
77+
final value = _evaluateConstant('v');
78+
assertDartObjectText(value, r'''
79+
bool false
80+
''');
81+
}
82+
83+
test_equalEqual_int_userClass() async {
84+
await assertNoErrorsInCode('''
85+
class A {
86+
const A();
87+
}
88+
89+
const v = 1 == A();
90+
''');
91+
final value = _evaluateConstant('v');
92+
assertDartObjectText(value, r'''
93+
bool false
94+
''');
95+
}
96+
97+
test_equalEqual_null_object() async {
98+
await assertNoErrorsInCode('''
99+
const Object? a = null;
100+
const v = a == Object();
101+
''');
102+
final value = _evaluateConstant('v');
103+
assertDartObjectText(value, r'''
104+
bool false
105+
''');
106+
}
107+
108+
test_equalEqual_string_object() async {
109+
await assertNoErrorsInCode('''
110+
const v = 'foo' == Object();
111+
''');
112+
final value = _evaluateConstant('v');
113+
assertDartObjectText(value, r'''
114+
bool false
115+
''');
116+
}
117+
118+
test_equalEqual_userClass_hasEqEq() async {
119+
await assertErrorsInCode('''
120+
class A {
121+
const A();
122+
bool operator ==(other) => false;
123+
}
124+
125+
const v = A() == 0;
126+
''', [
127+
error(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING, 72, 8),
128+
]);
129+
// TODO(scheglov) check the invalid value
130+
}
131+
132+
test_equalEqual_userClass_hasHashCode() async {
133+
await assertErrorsInCode('''
134+
class A {
135+
const A();
136+
int get hashCode => 0;
137+
}
138+
139+
const v = A() == 0;
140+
''', [
141+
error(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING, 61, 8),
142+
]);
143+
// TODO(scheglov) check the invalid value
144+
}
145+
146+
test_equalEqual_userClass_hasPrimitiveEquality_false() async {
147+
await assertNoErrorsInCode('''
148+
class A {
149+
final int f;
150+
const A(this.f);
151+
}
152+
153+
const v = A(0) == 0;
154+
''');
155+
final value = _evaluateConstant('v');
156+
assertDartObjectText(value, r'''
157+
bool false
158+
''');
159+
}
160+
161+
test_equalEqual_userClass_hasPrimitiveEquality_language219() async {
162+
await assertErrorsInCode('''
163+
// @dart = 2.19
164+
class A {
165+
const A();
166+
}
167+
168+
const v = A() == 0;
169+
''', [
170+
error(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING, 52, 8),
171+
]);
172+
_evaluateConstantOrNull('v', errorCodes: [
173+
CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING,
174+
]);
175+
}
176+
177+
test_equalEqual_userClass_hasPrimitiveEquality_true() async {
178+
await assertNoErrorsInCode('''
179+
class A {
180+
final int f;
181+
const A(this.f);
182+
}
183+
184+
const v = A(0) == A(0);
185+
''');
186+
final value = _evaluateConstant('v');
187+
assertDartObjectText(value, r'''
188+
bool true
189+
''');
190+
}
191+
32192
test_hasPrimitiveEquality_bool() async {
33193
await assertNoErrorsInCode('''
34194
const v = true;
@@ -2314,6 +2474,19 @@ const a = const A<int?>();
23142474
);
23152475
}
23162476

2477+
test_assertInitializer_intInDoubleContext_true() async {
2478+
await assertNoErrorsInCode('''
2479+
class A {
2480+
const A(double x): assert((x + 3) / 2 == 1.5);
2481+
}
2482+
const v = const A(0);
2483+
''');
2484+
final value = _evaluateConstant('v');
2485+
assertDartObjectText(value, r'''
2486+
A
2487+
''');
2488+
}
2489+
23172490
test_fieldInitializer_functionReference_withTypeParameter() async {
23182491
await resolveTestCode('''
23192492
void g<U>(U a) {}
@@ -2519,16 +2692,6 @@ const a = const A(1);
25192692
);
25202693
}
25212694

2522-
test_assertInitializer_intInDoubleContext_true() async {
2523-
await resolveTestCode('''
2524-
class A {
2525-
const A(double x): assert((x + 3) / 2 == 1.5);
2526-
}
2527-
const a = const A(0);
2528-
''');
2529-
_assertValidConstant('a');
2530-
}
2531-
25322695
test_assertInitializer_simple_false() async {
25332696
await resolveTestCode('''
25342697
class A {

0 commit comments

Comments
 (0)