Skip to content

Commit 0507f05

Browse files
natebiggsCommit Queue
authored andcommitted
[dart2js] Fix error when comparing constants referenced across deferred import boundaries.
Constant folding was considering strings (or other primitives) unequal if one of them was a DeferredGlobalConstantValue and the other was not. This was producing incorrect results in the cases where the underlying constants were in fact equal. For the purposes of constant folding equality checks, we should just ignore the deferred boundary and compare the constants themselves. Fixes: #61833 Change-Id: Ibbd950ae910ee2377353f5fae8d9bea5c64d9d84 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/460020 Commit-Queue: Nate Biggs <[email protected]> Reviewed-by: Mayank Patke <[email protected]>
1 parent e94cceb commit 0507f05

File tree

3 files changed

+82
-11
lines changed

3 files changed

+82
-11
lines changed

pkg/compiler/lib/src/constants/constant_system.dart

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,24 +113,30 @@ TypeConstantValue createType(CommonElements commonElements, DartType type) {
113113
/// typeof(X) === "number" && Math.floor(X) === X
114114
///
115115
/// We consistently match that runtime semantics at compile time as well.
116-
bool isInt(ConstantValue constant) =>
117-
constant is IntConstantValue ||
118-
constant.isMinusZero ||
119-
constant.isPositiveInfinity ||
120-
constant.isNegativeInfinity;
116+
bool isInt(ConstantValue constant) {
117+
constant = _unwrap(constant);
118+
119+
return constant is IntConstantValue ||
120+
constant.isMinusZero ||
121+
constant.isPositiveInfinity ||
122+
constant.isNegativeInfinity;
123+
}
121124

122125
/// Returns true if the [constant] is a double at runtime.
123-
bool isDouble(ConstantValue constant) =>
124-
constant is DoubleConstantValue && !constant.isMinusZero;
126+
bool isDouble(ConstantValue constant) {
127+
constant = _unwrap(constant);
128+
return constant is DoubleConstantValue && !constant.isMinusZero;
129+
}
125130

126131
/// Returns true if the [constant] is a string at runtime.
127-
bool isString(ConstantValue constant) => constant is StringConstantValue;
132+
bool isString(ConstantValue constant) =>
133+
_unwrap(constant) is StringConstantValue;
128134

129135
/// Returns true if the [constant] is a boolean at runtime.
130-
bool isBool(ConstantValue constant) => constant is BoolConstantValue;
136+
bool isBool(ConstantValue constant) => _unwrap(constant) is BoolConstantValue;
131137

132138
/// Returns true if the [constant] is null at runtime.
133-
bool isNull(ConstantValue constant) => constant is NullConstantValue;
139+
bool isNull(ConstantValue constant) => _unwrap(constant) is NullConstantValue;
134140

135141
bool isSubtype(DartTypes types, DartType s, DartType t) {
136142
// At runtime, an integer is both an integer and a double: the
@@ -277,6 +283,8 @@ class BitNotOperation implements UnaryOperation {
277283

278284
@override
279285
IntConstantValue? fold(ConstantValue constant) {
286+
constant = _unwrap(constant);
287+
280288
if (isInt(constant)) {
281289
// In JavaScript we don't check for -0 and treat it as if it was zero.
282290
if (constant.isMinusZero) {
@@ -299,6 +307,8 @@ class NegateOperation implements UnaryOperation {
299307

300308
@override
301309
NumConstantValue? fold(ConstantValue constant) {
310+
constant = _unwrap(constant);
311+
302312
NumConstantValue? fold(ConstantValue constant) {
303313
if (constant is IntConstantValue) {
304314
return createInt(-constant.intValue);
@@ -326,6 +336,8 @@ class NotOperation implements UnaryOperation {
326336

327337
@override
328338
BoolConstantValue? fold(ConstantValue constant) {
339+
constant = _unwrap(constant);
340+
329341
if (constant is BoolConstantValue) {
330342
return createBool(!constant.boolValue);
331343
}
@@ -339,6 +351,9 @@ abstract class BinaryBitOperation implements BinaryOperation {
339351

340352
@override
341353
IntConstantValue? fold(ConstantValue left, ConstantValue right) {
354+
left = _unwrap(left);
355+
right = _unwrap(right);
356+
342357
IntConstantValue? fold(ConstantValue left, ConstantValue right) {
343358
if (left is IntConstantValue && right is IntConstantValue) {
344359
BigInt? resultValue = foldInts(left.intValue, right.intValue);
@@ -495,6 +510,9 @@ abstract class ArithmeticNumOperation implements BinaryOperation {
495510

496511
@override
497512
NumConstantValue? fold(ConstantValue left, ConstantValue right) {
513+
left = _unwrap(left);
514+
right = _unwrap(right);
515+
498516
NumConstantValue? fold(ConstantValue left, ConstantValue right) {
499517
if (left is NumConstantValue && right is NumConstantValue) {
500518
Object? foldedValue;
@@ -633,6 +651,9 @@ class AddOperation implements BinaryOperation {
633651

634652
@override
635653
ConstantValue? fold(ConstantValue left, ConstantValue right) {
654+
left = _unwrap(left);
655+
right = _unwrap(right);
656+
636657
ConstantValue? fold(ConstantValue left, ConstantValue right) {
637658
if (left is IntConstantValue && right is IntConstantValue) {
638659
BigInt result = left.intValue + right.intValue;
@@ -661,6 +682,8 @@ abstract class RelationalNumOperation implements BinaryOperation {
661682

662683
@override
663684
BoolConstantValue? fold(ConstantValue left, ConstantValue right) {
685+
left = _unwrap(left);
686+
right = _unwrap(right);
664687
if (left is NumConstantValue && right is NumConstantValue) {
665688
bool foldedValue;
666689
if (left is IntConstantValue && right is IntConstantValue) {
@@ -737,6 +760,8 @@ class EqualsOperation implements BinaryOperation {
737760

738761
@override
739762
BoolConstantValue? fold(ConstantValue left, ConstantValue right) {
763+
left = _unwrap(left);
764+
right = _unwrap(right);
740765
// Numbers need to be treated specially because: NaN != NaN, -0.0 == 0.0,
741766
// and 1 == 1.0.
742767
if (left is IntConstantValue && right is IntConstantValue) {
@@ -770,6 +795,8 @@ class IdentityOperation implements BinaryOperation {
770795

771796
@override
772797
BoolConstantValue fold(ConstantValue left, ConstantValue right) {
798+
left = _unwrap(left);
799+
right = _unwrap(right);
773800
// NaNs are not identical to anything. This is a web platform departure from
774801
// standard Dart. If we make `identical(double.nan, double.nan)` be `true`,
775802
// this constant folding will be incorrect. TODOs below for cross-reference.
@@ -799,7 +826,9 @@ class IfNullOperation implements BinaryOperation {
799826

800827
@override
801828
ConstantValue fold(ConstantValue left, ConstantValue right) {
802-
if (left is NullConstantValue) return right;
829+
if (_unwrap(left) is NullConstantValue) {
830+
return right;
831+
}
803832
return left;
804833
}
805834
}
@@ -812,6 +841,8 @@ class CodeUnitAtOperation implements BinaryOperation {
812841

813842
@override
814843
NumConstantValue? fold(ConstantValue left, ConstantValue right) {
844+
left = _unwrap(left);
845+
right = _unwrap(right);
815846
if (left is StringConstantValue && right is IntConstantValue) {
816847
String string = left.stringValue;
817848
int index = right.intValue.toInt();
@@ -831,6 +862,7 @@ class RoundOperation implements UnaryOperation {
831862

832863
@override
833864
NumConstantValue? fold(ConstantValue constant) {
865+
constant = _unwrap(constant);
834866
// Be careful to round() only values that do not throw on either the host or
835867
// target platform.
836868
NumConstantValue? tryToRound(double value) {
@@ -873,6 +905,7 @@ class ToIntOperation implements UnaryOperation {
873905

874906
@override
875907
NumConstantValue? fold(ConstantValue constant) {
908+
constant = _unwrap(constant);
876909
if (constant is IntConstantValue) {
877910
double value = constant.doubleValue;
878911
// The code below is written to work for any `double`, even though
@@ -899,6 +932,9 @@ class _IndexOperation implements BinaryOperation {
899932

900933
@override
901934
ConstantValue? fold(ConstantValue left, ConstantValue right) {
935+
left = _unwrap(left);
936+
right = _unwrap(right);
937+
902938
if (left is ListConstantValue) {
903939
if (right is IntConstantValue) {
904940
List<ConstantValue> entries = left.entries;
@@ -1006,3 +1042,7 @@ class JavaScriptMapConstant extends MapConstantValue {
10061042
}
10071043
}
10081044
}
1045+
1046+
ConstantValue _unwrap(ConstantValue value) {
1047+
return value is DeferredGlobalConstantValue ? value.referenced : value;
1048+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Copyright (c) 2025, 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+
final String str = 'hello';
6+
final bool? nullBool = null;
7+
8+
void foo() {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) 2025, 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+
import 'package:async_helper/async_helper.dart';
6+
import 'package:expect/expect.dart';
7+
8+
import '61833_helper.dart' deferred as d;
9+
10+
final String localStr = 'hello';
11+
12+
Future<void> main() async {
13+
asyncStart();
14+
await d.loadLibrary();
15+
16+
// Don't use 'Expect' APIs since constants have to be direct
17+
// inputs to the operators being tested.
18+
Expect.isTrue(d.str == localStr);
19+
Expect.isTrue(identical(d.str, localStr));
20+
Expect.isTrue(d.nullBool ?? true);
21+
d.foo();
22+
asyncEnd();
23+
}

0 commit comments

Comments
 (0)