[dart2js] Migrate constants/constant_system.dart

Most of the change is changing `foo.isInt` to `foo is IntConstantValue` to get promotion and avoid downcasts.

Change-Id: Ie38bc5500dcb22ed9e194e6b810702dd94f2f79e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243926
Reviewed-by: Mayank Patke <fishythefish@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
This commit is contained in:
Stephen Adams
2022-05-07 01:05:50 +00:00
committed by Commit Bot
parent 240719eb86
commit daba3529cb
4 changed files with 147 additions and 167 deletions
@@ -375,6 +375,7 @@ abstract class CommonElements
/// The `Type` type defined in 'dart:core'.
InterfaceType get typeType => _getRawType(typeClass);
@override
InterfaceType get typeLiteralType => _getRawType(typeLiteralClass);
/// The `StackTrace` type defined in 'dart:core';
@@ -384,6 +385,7 @@ abstract class CommonElements
/// [elementType] as its type argument.
///
/// If no type argument is provided, the canonical raw type is returned.
@override
InterfaceType listType([DartType elementType]) {
if (elementType == null) {
return _getRawType(listClass);
@@ -406,6 +408,7 @@ abstract class CommonElements
/// [keyType] and [valueType] as its type arguments.
///
/// If no type arguments are provided, the canonical raw type is returned.
@override
InterfaceType mapType([DartType keyType, DartType valueType]) {
if (keyType == null && valueType == null) {
return _getRawType(mapClass);
@@ -487,11 +490,13 @@ abstract class CommonElements
return _env.createInterfaceType(cls, typeArguments);
}
@override
InterfaceType getConstantListTypeFor(InterfaceType sourceType) =>
dartTypes.treatAsRawType(sourceType)
? _env.getRawType(jsArrayClass)
: _env.createInterfaceType(jsArrayClass, sourceType.typeArguments);
@override
InterfaceType getConstantMapTypeFor(InterfaceType sourceType,
{bool onlyStringKeys = false}) {
ClassEntity classElement =
@@ -503,6 +508,7 @@ abstract class CommonElements
}
}
@override
InterfaceType getConstantSetTypeFor(InterfaceType sourceType) =>
dartTypes.treatAsRawType(sourceType)
? _env.getRawType(constSetLiteralClass)
@@ -511,10 +517,12 @@ abstract class CommonElements
/// Returns the field that holds the internal name in the implementation class
/// for `Symbol`.
@override
FieldEntity get symbolField => _symbolImplementationField ??=
_env.lookupLocalClassMember(symbolImplementationClass, '_name',
required: true);
@override
InterfaceType get symbolImplementationType =>
_env.getRawType(symbolImplementationClass);
@@ -2,6 +2,7 @@
// 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 '../elements/entities.dart';
import '../elements/types.dart';
/// This is a facade interface for the members of CommonElements that are
@@ -16,4 +17,15 @@ abstract class CommonElements {
DartType get stringType;
DartTypes get dartTypes;
InterfaceType getConstantListTypeFor(InterfaceType sourceType);
InterfaceType getConstantMapTypeFor(InterfaceType sourceType,
{bool onlyStringKeys = false});
InterfaceType getConstantSetTypeFor(InterfaceType sourceType);
InterfaceType listType([DartType? elementType]);
InterfaceType mapType([DartType? keyType, DartType? valueType]);
InterfaceType get symbolImplementationType;
InterfaceType get typeLiteralType;
FieldEntity get symbolField;
}
@@ -2,19 +2,16 @@
// 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.
// @dart = 2.10
/// Constant system following the semantics for Dart code that has been
/// compiled to JavaScript.
library dart2js.constant_system;
import '../common/elements.dart' show CommonElements;
//import '../common/elements.dart' show CommonElements;
import 'common_elements_for_constants.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
import 'values.dart';
final _BITS32 = BigInt.from(0xFFFFFFFF);
const add = AddOperation();
const bitAnd = BitAndOperation();
const bitNot = BitNotOperation();
@@ -54,21 +51,19 @@ bool _integerBecomesNanOrInfinity(BigInt value) {
}
NumConstantValue _convertToJavaScriptConstant(NumConstantValue constant) {
if (constant.isInt) {
IntConstantValue intConstant = constant;
BigInt intValue = intConstant.intValue;
if (constant is IntConstantValue) {
BigInt intValue = constant.intValue;
if (_integerBecomesNanOrInfinity(intValue)) {
return DoubleConstantValue(intValue.toDouble());
}
// If the integer loses precision with JavaScript numbers, use
// the floored version JavaScript will use.
// the floored value JavaScript will use.
BigInt floorValue = BigInt.from(intValue.toDouble());
if (floorValue != intValue) {
return IntConstantValue(floorValue);
}
} else if (constant.isDouble) {
DoubleConstantValue doubleResult = constant;
double doubleValue = doubleResult.doubleValue;
} else if (constant is DoubleConstantValue) {
double doubleValue = constant.doubleValue;
if (!doubleValue.isInfinite &&
!doubleValue.isNaN &&
!constant.isMinusZero) {
@@ -83,12 +78,18 @@ NumConstantValue _convertToJavaScriptConstant(NumConstantValue constant) {
NumConstantValue createInt(BigInt i) =>
_convertToJavaScriptConstant(IntConstantValue(i));
NumConstantValue createIntFromInt(int i) => createInt(BigInt.from(i));
NumConstantValue _createInt32(BigInt i) => IntConstantValue(i & _BITS32);
NumConstantValue _createInt32(BigInt i) => IntConstantValue(i.toUnsigned(32));
NumConstantValue createDouble(double d) =>
_convertToJavaScriptConstant(DoubleConstantValue(d));
StringConstantValue createString(String string) => StringConstantValue(string);
BoolConstantValue createBool(bool value) => BoolConstantValue(value);
NullConstantValue createNull() => NullConstantValue();
ListConstantValue createList(CommonElements commonElements,
@@ -190,12 +191,12 @@ abstract class Operation {
abstract class UnaryOperation extends Operation {
/// Returns [:null:] if it was unable to fold the operation.
ConstantValue fold(ConstantValue constant);
ConstantValue? fold(ConstantValue constant);
}
abstract class BinaryOperation extends Operation {
/// Returns [:null:] if it was unable to fold the operation.
ConstantValue fold(ConstantValue left, ConstantValue right);
ConstantValue? fold(ConstantValue left, ConstantValue right);
apply(left, right);
}
@@ -206,15 +207,16 @@ class BitNotOperation implements UnaryOperation {
const BitNotOperation();
@override
ConstantValue fold(ConstantValue constant) {
ConstantValue? fold(ConstantValue constant) {
if (isInt(constant)) {
// In JavaScript we don't check for -0 and treat it as if it was zero.
if (constant.isMinusZero) {
constant = createInt(BigInt.zero);
}
IntConstantValue intConstant = constant;
// We convert the result of bit-operations to 32 bit unsigned integers.
return _createInt32(~intConstant.intValue);
if (constant is IntConstantValue) {
// Bit-operations yield 32-bit unsigned integers.
return _createInt32(~constant.intValue);
}
}
return null;
}
@@ -227,22 +229,19 @@ class NegateOperation implements UnaryOperation {
const NegateOperation();
@override
ConstantValue fold(ConstantValue constant) {
ConstantValue _fold(ConstantValue constant) {
if (constant.isInt) {
IntConstantValue intConstant = constant;
return createInt(-intConstant.intValue);
ConstantValue? fold(ConstantValue constant) {
ConstantValue? _fold(ConstantValue constant) {
if (constant is IntConstantValue) {
return createInt(-constant.intValue);
}
if (constant.isDouble) {
DoubleConstantValue doubleConstant = constant;
return createDouble(-doubleConstant.doubleValue);
if (constant is DoubleConstantValue) {
return createDouble(-constant.doubleValue);
}
return null;
}
if (constant.isInt) {
IntConstantValue intConstant = constant;
if (intConstant.intValue == BigInt.zero) {
if (constant is IntConstantValue) {
if (constant.intValue == BigInt.zero) {
return createDouble(-0.0);
}
}
@@ -257,10 +256,9 @@ class NotOperation implements UnaryOperation {
const NotOperation();
@override
ConstantValue fold(ConstantValue constant) {
if (constant.isBool) {
BoolConstantValue boolConstant = constant;
return createBool(!boolConstant.boolValue);
ConstantValue? fold(ConstantValue constant) {
if (constant is BoolConstantValue) {
return createBool(!constant.boolValue);
}
return null;
}
@@ -271,14 +269,12 @@ abstract class BinaryBitOperation implements BinaryOperation {
const BinaryBitOperation();
@override
ConstantValue fold(ConstantValue left, ConstantValue right) {
ConstantValue _fold(ConstantValue left, ConstantValue right) {
if (left.isInt && right.isInt) {
IntConstantValue leftInt = left;
IntConstantValue rightInt = right;
BigInt resultValue = foldInts(leftInt.intValue, rightInt.intValue);
ConstantValue? fold(ConstantValue left, ConstantValue right) {
IntConstantValue? _fold(ConstantValue left, ConstantValue right) {
if (left is IntConstantValue && right is IntConstantValue) {
BigInt? resultValue = foldInts(left.intValue, right.intValue);
if (resultValue == null) return null;
return createInt(resultValue);
return createInt(resultValue) as IntConstantValue;
}
return null;
}
@@ -290,7 +286,7 @@ abstract class BinaryBitOperation implements BinaryOperation {
if (right.isMinusZero) {
right = createInt(BigInt.zero);
}
IntConstantValue result = _fold(left, right);
IntConstantValue? result = _fold(left, right);
if (result != null) {
// We convert the result of bit-operations to 32 bit unsigned integers.
return _createInt32(result.intValue);
@@ -298,7 +294,7 @@ abstract class BinaryBitOperation implements BinaryOperation {
return result;
}
BigInt foldInts(BigInt left, BigInt right);
BigInt? foldInts(BigInt left, BigInt right);
}
class BitAndOperation extends BinaryBitOperation {
@@ -347,7 +343,7 @@ class ShiftLeftOperation extends BinaryBitOperation {
const ShiftLeftOperation();
@override
BigInt foldInts(BigInt left, BigInt right) {
BigInt? foldInts(BigInt left, BigInt right) {
// TODO(floitsch): find a better way to guard against excessive shifts to
// the left.
if (right > BigInt.from(100) || right < BigInt.zero) return null;
@@ -365,35 +361,24 @@ class ShiftRightOperation extends BinaryBitOperation {
const ShiftRightOperation();
@override
ConstantValue fold(ConstantValue left, ConstantValue right) {
// Truncate the input value to 32 bits if necessary.
if (left.isInt) {
IntConstantValue intConstant = left;
BigInt value = intConstant.intValue;
BigInt truncatedValue = value & _BITS32;
if (value < BigInt.zero) {
// Sign-extend if the input was negative. The current semantics don't
// make much sense, since we only look at bit 31.
// TODO(floitsch): we should treat the input to right shifts as
// unsigned.
// A 32 bit complement-two value x can be computed by:
// x_u - 2^32 (where x_u is its unsigned representation).
// Example: 0xFFFFFFFF - 0x100000000 => -1.
// We simply and with the sign-bit and multiply by two. If the sign-bit
// was set, then the result is 0. Otherwise it will become 2^32.
final BigInt SIGN_BIT = BigInt.from(0x80000000);
truncatedValue -= BigInt.two * (truncatedValue & SIGN_BIT);
}
if (value != truncatedValue) {
left = createInt(truncatedValue);
ConstantValue? fold(ConstantValue left, ConstantValue right) {
// Truncate the input value to 32 bits. The web implementation of '>>' is a
// signed shift for negative values, and an unsigned for shift for
// non-negative values.
ConstantValue adjustedLeft = left;
if (left is IntConstantValue) {
BigInt value = left.intValue;
BigInt truncated =
value.isNegative ? value.toSigned(32) : value.toUnsigned(32);
if (value != truncated) {
adjustedLeft = createInt(truncated);
}
}
return super.fold(left, right);
return super.fold(adjustedLeft, right);
}
@override
BigInt foldInts(BigInt left, BigInt right) {
BigInt? foldInts(BigInt left, BigInt right) {
if (right < BigInt.zero) return null;
return left >> right.toInt();
}
@@ -409,7 +394,7 @@ class ShiftRightUnsignedOperation extends BinaryBitOperation {
const ShiftRightUnsignedOperation();
@override
BigInt foldInts(BigInt left, BigInt right) {
BigInt? foldInts(BigInt left, BigInt right) {
if (right < BigInt.zero) return null;
return left.toUnsigned(32) >> right.toInt();
}
@@ -424,11 +409,9 @@ abstract class BinaryBoolOperation implements BinaryOperation {
const BinaryBoolOperation();
@override
ConstantValue fold(ConstantValue left, ConstantValue right) {
if (left.isBool && right.isBool) {
BoolConstantValue leftBool = left;
BoolConstantValue rightBool = right;
bool resultValue = foldBools(leftBool.boolValue, rightBool.boolValue);
ConstantValue? fold(ConstantValue left, ConstantValue right) {
if (left is BoolConstantValue && right is BoolConstantValue) {
bool resultValue = foldBools(left.boolValue, right.boolValue);
return createBool(resultValue);
}
return null;
@@ -467,22 +450,21 @@ abstract class ArithmeticNumOperation implements BinaryOperation {
const ArithmeticNumOperation();
@override
ConstantValue fold(ConstantValue left, ConstantValue right) {
ConstantValue _fold(ConstantValue left, ConstantValue right) {
if (left.isNum && right.isNum) {
NumConstantValue leftNum = left;
NumConstantValue rightNum = right;
ConstantValue? fold(ConstantValue left, ConstantValue right) {
NumConstantValue? _fold(ConstantValue left, ConstantValue right) {
if (left is NumConstantValue && right is NumConstantValue) {
var foldedValue;
if (left.isInt && right.isInt) {
IntConstantValue leftInt = leftNum;
IntConstantValue rightInt = rightNum;
foldedValue = foldInts(leftInt.intValue, rightInt.intValue);
if (left is IntConstantValue && right is IntConstantValue) {
foldedValue = foldInts(left.intValue, right.intValue);
} else {
foldedValue = foldNums(leftNum.doubleValue, rightNum.doubleValue);
foldedValue = foldNums(left.doubleValue, right.doubleValue);
}
// A division by 0 means that we might not have a folded value.
if (foldedValue == null) return null;
if (left.isInt && right.isInt && !isDivide() || isTruncatingDivide()) {
if (left is IntConstantValue &&
right is IntConstantValue &&
!isDivide() ||
isTruncatingDivide()) {
assert(foldedValue is BigInt);
return createInt(foldedValue);
} else {
@@ -492,7 +474,7 @@ abstract class ArithmeticNumOperation implements BinaryOperation {
return null;
}
ConstantValue result = _fold(left, right);
NumConstantValue? result = _fold(left, right);
if (result == null) return result;
return _convertToJavaScriptConstant(result);
}
@@ -542,7 +524,7 @@ class ModuloOperation extends ArithmeticNumOperation {
const ModuloOperation();
@override
BigInt foldInts(BigInt left, BigInt right) {
BigInt? foldInts(BigInt left, BigInt right) {
if (right == BigInt.zero) return null;
return left % right;
}
@@ -561,7 +543,7 @@ class RemainderOperation extends ArithmeticNumOperation {
const RemainderOperation();
@override
BigInt foldInts(BigInt left, BigInt right) {
BigInt? foldInts(BigInt left, BigInt right) {
if (right == BigInt.zero) return null;
return left.remainder(right);
}
@@ -580,13 +562,13 @@ class TruncatingDivideOperation extends ArithmeticNumOperation {
const TruncatingDivideOperation();
@override
BigInt foldInts(BigInt left, BigInt right) {
BigInt? foldInts(BigInt left, BigInt right) {
if (right == BigInt.zero) return null;
return left ~/ right;
}
@override
BigInt foldNums(num left, num right) {
BigInt? foldNums(num left, num right) {
num ratio = left / right;
if (ratio.isNaN || ratio.isInfinite) return null;
return BigInt.from(ratio.truncateToDouble());
@@ -625,30 +607,24 @@ class AddOperation implements BinaryOperation {
const AddOperation();
@override
ConstantValue fold(ConstantValue left, ConstantValue right) {
ConstantValue _fold(ConstantValue left, ConstantValue right) {
if (left.isInt && right.isInt) {
IntConstantValue leftInt = left;
IntConstantValue rightInt = right;
BigInt result = leftInt.intValue + rightInt.intValue;
ConstantValue? fold(ConstantValue left, ConstantValue right) {
ConstantValue? _fold(ConstantValue left, ConstantValue right) {
if (left is IntConstantValue && right is IntConstantValue) {
BigInt result = left.intValue + right.intValue;
return createInt(result);
} else if (left.isNum && right.isNum) {
NumConstantValue leftNum = left;
NumConstantValue rightNum = right;
double result = leftNum.doubleValue + rightNum.doubleValue;
} else if (left is NumConstantValue && right is NumConstantValue) {
double result = left.doubleValue + right.doubleValue;
return createDouble(result);
} else if (left.isString && right.isString) {
StringConstantValue leftString = left;
StringConstantValue rightString = right;
String result = leftString.stringValue + rightString.stringValue;
} else if (left is StringConstantValue && right is StringConstantValue) {
String result = left.stringValue + right.stringValue;
return createString(result);
} else {
return null;
}
}
ConstantValue result = _fold(left, right);
if (result != null && result.isNum) {
ConstantValue? result = _fold(left, right);
if (result is NumConstantValue) {
return _convertToJavaScriptConstant(result);
}
return result;
@@ -662,20 +638,18 @@ abstract class RelationalNumOperation implements BinaryOperation {
const RelationalNumOperation();
@override
ConstantValue fold(ConstantValue left, ConstantValue right) {
if (!left.isNum || !right.isNum) return null;
bool foldedValue;
if (left.isInt && right.isInt) {
IntConstantValue leftInt = left;
IntConstantValue rightInt = right;
foldedValue = foldInts(leftInt.intValue, rightInt.intValue);
} else {
NumConstantValue leftNum = left;
NumConstantValue rightNum = right;
foldedValue = foldNums(leftNum.doubleValue, rightNum.doubleValue);
ConstantValue? fold(ConstantValue left, ConstantValue right) {
if (left is NumConstantValue && right is NumConstantValue) {
bool foldedValue;
if (left is IntConstantValue && right is IntConstantValue) {
foldedValue = foldInts(left.intValue, right.intValue);
} else {
foldedValue = foldNums(left.doubleValue, right.doubleValue);
}
assert((foldedValue as dynamic) != null);
return createBool(foldedValue);
}
assert(foldedValue != null);
return createBool(foldedValue);
return null;
}
bool foldInts(BigInt left, BigInt right);
@@ -753,20 +727,16 @@ class EqualsOperation implements BinaryOperation {
const EqualsOperation();
@override
ConstantValue fold(ConstantValue left, ConstantValue right) {
ConstantValue? fold(ConstantValue left, ConstantValue right) {
// Numbers need to be treated specially because: NaN != NaN, -0.0 == 0.0,
// and 1 == 1.0.
if (left.isInt && right.isInt) {
IntConstantValue leftInt = left;
IntConstantValue rightInt = right;
bool result = leftInt.intValue == rightInt.intValue;
if (left is IntConstantValue && right is IntConstantValue) {
bool result = left.intValue == right.intValue;
return createBool(result);
}
if (left.isNum && right.isNum) {
NumConstantValue leftNum = left;
NumConstantValue rightNum = right;
bool result = leftNum.doubleValue == rightNum.doubleValue;
if (left is NumConstantValue && right is NumConstantValue) {
bool result = left.doubleValue == right.doubleValue;
return createBool(result);
}
@@ -794,31 +764,24 @@ class IdentityOperation implements BinaryOperation {
@override
BoolConstantValue fold(ConstantValue left, ConstantValue right) {
BoolConstantValue _fold(ConstantValue left, ConstantValue right) {
// In order to preserve runtime semantics which says that NaN !== NaN
// don't constant fold NaN === NaN. Otherwise the output depends on
// inlined variables and other optimizations.
if (left.isNaN && right.isNaN) return FalseConstantValue();
return createBool(left == right);
}
// NaNs are not identical to anything. This is a web platform departure from
// standard Dart. If we make `identical(double.nan, double.nan)` be `true`,
// this constant folding will be incorrect. TODOs below for cross-reference.
// TODO(11551): Keep constant-folding consistent with `identical`.
// TODO(42224): Keep constant-folding consistent with `identical`.
if (left.isNaN || right.isNaN) return FalseConstantValue();
BoolConstantValue result = _fold(left, right);
if (result == null || result.boolValue) return result;
// In JavaScript -0.0 === 0 and all doubles are equal to their integer
// values. Furthermore NaN !== NaN.
if (left.isInt && right.isInt) {
IntConstantValue leftInt = left;
IntConstantValue rightInt = right;
return BoolConstantValue(leftInt.intValue == rightInt.intValue);
// values.
if (left is IntConstantValue && right is IntConstantValue) {
return createBool(left.intValue == right.intValue);
}
if (left.isNum && right.isNum) {
NumConstantValue leftNum = left;
NumConstantValue rightNum = right;
double leftDouble = leftNum.doubleValue;
double rightDouble = rightNum.doubleValue;
return BoolConstantValue(leftDouble == rightDouble);
if (left is NumConstantValue && right is NumConstantValue) {
return createBool(left.doubleValue == right.doubleValue);
}
return result;
// For the remaining constants, if they are the same constant, they are
// identical, otherwise not.
return createBool(left == right);
}
@override
@@ -848,12 +811,10 @@ class CodeUnitAtOperation implements BinaryOperation {
const CodeUnitAtOperation();
@override
IntConstantValue fold(ConstantValue left, ConstantValue right) {
if (left.isString && right.isInt) {
StringConstantValue stringConstant = left;
IntConstantValue indexConstant = right;
String string = stringConstant.stringValue;
int index = indexConstant.intValue.toInt();
ConstantValue? fold(ConstantValue left, ConstantValue right) {
if (left is StringConstantValue && right is IntConstantValue) {
String string = left.stringValue;
int index = right.intValue.toInt();
if (index < 0 || index >= string.length) return null;
int value = string.codeUnitAt(index);
return createIntFromInt(value);
@@ -872,10 +833,10 @@ class RoundOperation implements UnaryOperation {
const RoundOperation();
@override
ConstantValue fold(ConstantValue constant) {
ConstantValue? fold(ConstantValue constant) {
// Be careful to round() only values that do not throw on either the host or
// target platform.
ConstantValue tryToRound(double value) {
ConstantValue? tryToRound(double value) {
// Due to differences between browsers, only 'round' easy cases. Avoid
// cases where nudging the value up or down changes the answer.
// 13 digits is safely within the ~15 digit precision of doubles.
@@ -889,16 +850,14 @@ class RoundOperation implements UnaryOperation {
IntConstantValue(BigInt.from(value.round())));
}
if (constant.isInt) {
IntConstantValue intConstant = constant;
double value = intConstant.intValue.toDouble();
if (constant is IntConstantValue) {
double value = constant.intValue.toDouble();
if (value >= -double.maxFinite && value <= double.maxFinite) {
return tryToRound(value);
}
}
if (constant.isDouble) {
DoubleConstantValue doubleConstant = constant;
double value = doubleConstant.doubleValue;
if (constant is DoubleConstantValue) {
double value = constant.doubleValue;
// NaN and infinities will throw.
if (value.isNaN) return null;
if (value.isInfinite) return null;
@@ -915,7 +874,7 @@ class ToIntOperation implements UnaryOperation {
const ToIntOperation();
@override
ConstantValue fold(ConstantValue constant) {
ConstantValue? fold(ConstantValue constant) {
if (constant is IntConstantValue) {
double value = constant.doubleValue;
// The code below is written to work for any `double`, even though
@@ -941,7 +900,7 @@ class _IndexOperation implements BinaryOperation {
const _IndexOperation();
@override
ConstantValue fold(ConstantValue left, ConstantValue right) {
ConstantValue? fold(ConstantValue left, ConstantValue right) {
if (left is ListConstantValue) {
if (right is IntConstantValue) {
List<ConstantValue> entries = left.entries;
@@ -954,7 +913,7 @@ class _IndexOperation implements BinaryOperation {
}
}
if (left is MapConstantValue) {
ConstantValue value = left.lookup(right);
ConstantValue? value = left.lookup(right);
if (value != null) return value;
return const NullConstantValue();
}
@@ -973,7 +932,7 @@ class UnfoldedUnaryOperation implements UnaryOperation {
const UnfoldedUnaryOperation(this.name);
@override
ConstantValue fold(ConstantValue constant) {
ConstantValue? fold(ConstantValue constant) {
return null;
}
}
@@ -74,6 +74,7 @@ abstract class ConstantValue {
/// `true` if this is a valid constant value.
bool get isConstant => true;
// TODO(48974): Clean up all these predicate getters.
bool get isNull => false;
bool get isBool => false;
bool get isTrue => false;