@@ -6,6 +6,7 @@ import 'package:front_end/src/api_unstable/dart2js.dart' show Link;
66
77import '../closure.dart' ;
88import '../common.dart' ;
9+ import '../common_elements.dart' ;
910import '../constants/constant_system.dart' as constant_system;
1011import '../constants/values.dart' ;
1112import '../elements/entities.dart' ;
@@ -4367,6 +4368,9 @@ class HIsTest extends HInstruction {
43674368 HInstruction get typeInput => inputs[0 ];
43684369 HInstruction get checkedInput => inputs[1 ];
43694370
4371+ AbstractBool evaluate (JClosedWorld closedWorld) =>
4372+ _isTestResult (checkedInput, dartType, checkedAbstractValue, closedWorld);
4373+
43704374 @override
43714375 accept (HVisitor visitor) => visitor.visitIsTest (this );
43724376
@@ -4398,6 +4402,9 @@ class HIsTestSimple extends HInstruction {
43984402
43994403 HInstruction get checkedInput => inputs[0 ];
44004404
4405+ AbstractBool evaluate (JClosedWorld closedWorld) =>
4406+ _isTestResult (checkedInput, dartType, checkedAbstractValue, closedWorld);
4407+
44014408 @override
44024409 accept (HVisitor visitor) => visitor.visitIsTestSimple (this );
44034410
@@ -4414,6 +4421,75 @@ class HIsTestSimple extends HInstruction {
44144421 String toString () => 'HIsTestSimple()' ;
44154422}
44164423
4424+ AbstractBool _isTestResult (HInstruction expression, DartType dartType,
4425+ AbstractValueWithPrecision checkedAbstractValue, JClosedWorld closedWorld) {
4426+ AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
4427+ AbstractValue subsetType = expression.instructionType;
4428+ AbstractValue supersetType = checkedAbstractValue.abstractValue;
4429+ if (checkedAbstractValue.isPrecise &&
4430+ abstractValueDomain.isIn (subsetType, supersetType).isDefinitelyTrue) {
4431+ return AbstractBool .True ;
4432+ }
4433+
4434+ // TODO(39287): Let the abstract value domain fully handle this.
4435+ // Currently, the abstract value domain cannot (soundly) state that an is-test
4436+ // is definitely false, so we reuse some of the case-by-case logic from the
4437+ // old [HIs] optimization.
4438+ if (dartType.isTop) return AbstractBool .True ;
4439+ if (dartType is ! InterfaceType ) return AbstractBool .Maybe ;
4440+ InterfaceType type = dartType;
4441+ ClassEntity element = type.element;
4442+ if (type.typeArguments.isNotEmpty) return AbstractBool .Maybe ;
4443+ JCommonElements commonElements = closedWorld.commonElements;
4444+ if (expression.isInteger (abstractValueDomain).isDefinitelyTrue) {
4445+ if (element == commonElements.intClass ||
4446+ element == commonElements.numClass ||
4447+ commonElements.isNumberOrStringSupertype (element)) {
4448+ return AbstractBool .True ;
4449+ }
4450+ if (element == commonElements.doubleClass) {
4451+ // We let the JS semantics decide for that check. Currently the code we
4452+ // emit will always return true.
4453+ return AbstractBool .Maybe ;
4454+ }
4455+ return AbstractBool .False ;
4456+ }
4457+ if (expression.isDouble (abstractValueDomain).isDefinitelyTrue) {
4458+ if (element == commonElements.doubleClass ||
4459+ element == commonElements.numClass ||
4460+ commonElements.isNumberOrStringSupertype (element)) {
4461+ return AbstractBool .True ;
4462+ }
4463+ if (element == commonElements.intClass) {
4464+ // We let the JS semantics decide for that check. Currently the code we
4465+ // emit will return true for a double that can be represented as a 31-bit
4466+ // integer and for -0.0.
4467+ return AbstractBool .Maybe ;
4468+ }
4469+ return AbstractBool .False ;
4470+ }
4471+ if (expression.isNumber (abstractValueDomain).isDefinitelyTrue) {
4472+ if (element == commonElements.numClass) {
4473+ return AbstractBool .True ;
4474+ }
4475+ // We cannot just return false, because the expression may be of type int or
4476+ // double.
4477+ return AbstractBool .Maybe ;
4478+ }
4479+ if (expression.isPrimitiveNumber (abstractValueDomain).isPotentiallyTrue &&
4480+ element == commonElements.intClass) {
4481+ // We let the JS semantics decide for that check.
4482+ return AbstractBool .Maybe ;
4483+ }
4484+ // We need the raw check because we don't have the notion of generics in the
4485+ // backend. For example, `this` in a class `A<T>` is currently always
4486+ // considered to have the raw type.
4487+ if (type.treatAsRaw) {
4488+ return abstractValueDomain.isInstanceOf (subsetType, element);
4489+ }
4490+ return AbstractBool .Maybe ;
4491+ }
4492+
44174493/// Type cast or type check using Rti form of type expression.
44184494class HAsCheck extends HCheck {
44194495 final AbstractValueWithPrecision checkedType;
0 commit comments