Use AbstractValue in KernelToTypeInferenceMap and KernelTypeGraphBuilder

Change-Id: I0af69d10223364256852248228cdbbcbca3f83fa
Reviewed-on: https://dart-review.googlesource.com/56484
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Johnni Winther 2018-05-31 07:26:52 +00:00 committed by commit-bot@chromium.org
parent 032925c4ff
commit aecf8e8dc4
7 changed files with 127 additions and 106 deletions

View file

@ -18,7 +18,7 @@ import '../kernel/element_map.dart';
import '../native/behavior.dart';
import '../options.dart';
import '../types/constants.dart';
import '../types/masks.dart';
import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../universe/selector.dart';
import '../universe/side_effects.dart';
@ -125,7 +125,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
/// If an instance field matched with a [selector] that is _not_ a setter, the
/// field is considered to have been read before initialization and the field
/// is assumed to be potentially `null`.
void _checkIfExposesThis(Selector selector, TypeMask mask) {
void _checkIfExposesThis(Selector selector, AbstractValue mask) {
if (_isThisExposed) {
// We already consider `this` to have been exposed.
return;
@ -296,7 +296,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
ArgumentsTypes arguments = analyzeArguments(node.arguments);
Selector selector = new Selector(SelectorKind.CALL, constructor.memberName,
_elementMap.getCallStructure(node.arguments));
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
handleConstructorInvoke(
node, node.arguments, selector, mask, constructor, arguments);
@ -312,7 +312,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
ArgumentsTypes arguments = analyzeArguments(node.arguments);
Selector selector = new Selector(SelectorKind.CALL, constructor.memberName,
_elementMap.getCallStructure(node.arguments));
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
handleConstructorInvoke(
node, node.arguments, selector, mask, constructor, arguments);
@ -725,7 +725,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
@override
TypeInformation visitMethodInvocation(ir.MethodInvocation node) {
Selector selector = _elementMap.getSelector(node);
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
ir.TreeNode receiver = node.receiver;
if (receiver is ir.VariableGet &&
@ -767,7 +767,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
CallType callType,
ir.Node node,
Selector selector,
TypeMask mask,
AbstractValue mask,
TypeInformation receiverType,
ArgumentsTypes arguments) {
assert(receiverType != null);
@ -811,13 +811,17 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
}
TypeInformation handleDynamicGet(ir.Node node, Selector selector,
TypeMask mask, TypeInformation receiverType) {
AbstractValue mask, TypeInformation receiverType) {
return _handleDynamic(
CallType.access, node, selector, mask, receiverType, null);
}
TypeInformation handleDynamicSet(ir.Node node, Selector selector,
TypeMask mask, TypeInformation receiverType, TypeInformation rhsType) {
TypeInformation handleDynamicSet(
ir.Node node,
Selector selector,
AbstractValue mask,
TypeInformation receiverType,
TypeInformation rhsType) {
ArgumentsTypes arguments = new ArgumentsTypes([rhsType], null);
return _handleDynamic(
CallType.access, node, selector, mask, receiverType, arguments);
@ -827,7 +831,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
CallType callType,
ir.Node node,
Selector selector,
TypeMask mask,
AbstractValue mask,
TypeInformation receiverType,
ArgumentsTypes arguments) {
return _handleDynamic(
@ -896,8 +900,8 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
_markThisAsExposed();
}
TypeMask currentMask;
TypeMask moveNextMask;
AbstractValue currentMask;
AbstractValue moveNextMask;
TypeInformation iteratorType;
if (node.isAsync) {
TypeInformation expressionType = visit(node.iterable);
@ -914,7 +918,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
} else {
TypeInformation expressionType = visit(node.iterable);
Selector iteratorSelector = Selectors.iterator;
TypeMask iteratorMask = _memberData.typeOfIterator(node);
AbstractValue iteratorMask = _memberData.typeOfIterator(node);
currentMask = _memberData.typeOfIteratorCurrent(node);
moveNextMask = _memberData.typeOfIteratorMoveNext(node);
@ -998,7 +1002,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
ConstructorEntity constructor = _elementMap.getConstructor(node.target);
ArgumentsTypes arguments = analyzeArguments(node.arguments);
Selector selector = _elementMap.getSelector(node);
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
return handleConstructorInvoke(
node, node.arguments, selector, mask, constructor, arguments);
}
@ -1038,7 +1042,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
ir.Node node,
ir.Arguments arguments,
Selector selector,
TypeMask mask,
AbstractValue mask,
ConstructorEntity constructor,
ArgumentsTypes argumentsTypes) {
TypeInformation returnType =
@ -1089,13 +1093,13 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
}
TypeInformation handleStaticInvoke(ir.Node node, Selector selector,
TypeMask mask, MemberEntity element, ArgumentsTypes arguments) {
AbstractValue mask, MemberEntity element, ArgumentsTypes arguments) {
return _inferrer.registerCalledMember(node, selector, mask, _analyzedMember,
element, arguments, _sideEffectsBuilder, inLoop);
}
TypeInformation handleClosureCall(ir.Node node, Selector selector,
TypeMask mask, MemberEntity member, ArgumentsTypes arguments) {
AbstractValue mask, MemberEntity member, ArgumentsTypes arguments) {
return _inferrer.registerCalledClosure(
node,
selector,
@ -1112,7 +1116,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
FunctionEntity function,
ArgumentsTypes arguments,
Selector selector,
TypeMask mask) {
AbstractValue mask) {
String name = function.name;
handleStaticInvoke(node, selector, mask, function, arguments);
if (name == JavaScriptBackend.JS) {
@ -1143,7 +1147,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
MemberEntity member = _elementMap.getMember(node.target);
ArgumentsTypes arguments = analyzeArguments(node.arguments);
Selector selector = _elementMap.getSelector(node);
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
if (_closedWorld.commonElements.isForeign(member)) {
return handleForeignInvoke(node, member, arguments, selector, mask);
} else if (member.isConstructor) {
@ -1165,7 +1169,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
@override
TypeInformation visitStaticGet(ir.StaticGet node) {
MemberEntity member = _elementMap.getMember(node.target);
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
return handleStaticInvoke(
node, new Selector.getter(member.memberName), mask, member, null);
}
@ -1177,7 +1181,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
_markThisAsExposed();
}
MemberEntity member = _elementMap.getMember(node.target);
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
handleStaticInvoke(node, new Selector.setter(member.memberName), mask,
member, new ArgumentsTypes([rhsType], null));
return rhsType;
@ -1187,7 +1191,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
TypeInformation visitPropertyGet(ir.PropertyGet node) {
TypeInformation receiverType = visit(node.receiver);
Selector selector = _elementMap.getSelector(node);
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
// TODO(johnniwinther): Use `node.interfaceTarget` to narrow the receiver
// type for --trust-type-annotations/strong-mode.
if (node.receiver is ir.ThisExpression) {
@ -1201,7 +1205,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
TypeInformation visitDirectPropertyGet(ir.DirectPropertyGet node) {
TypeInformation receiverType = thisType;
MemberEntity member = _elementMap.getMember(node.target);
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
// TODO(johnniwinther): Use `node.target` to narrow the receiver type.
Selector selector = new Selector.getter(member.memberName);
_checkIfExposesThis(selector, _types.newTypedSelector(receiverType, mask));
@ -1212,7 +1216,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
TypeInformation visitPropertySet(ir.PropertySet node) {
TypeInformation receiverType = visit(node.receiver);
Selector selector = _elementMap.getSelector(node);
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
TypeInformation rhsType = visit(node.value);
if (node.value is ir.ThisExpression) {
@ -1220,7 +1224,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
}
if (_inGenerativeConstructor && node.receiver is ir.ThisExpression) {
TypeMask typedMask = _types.newTypedSelector(receiverType, mask);
AbstractValue typedMask = _types.newTypedSelector(receiverType, mask);
if (!_closedWorld.includesClosureCall(selector, typedMask)) {
Iterable<MemberEntity> targets =
_closedWorld.locateMembers(selector, typedMask);
@ -1608,7 +1612,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
}
TypeInformation handleSuperNoSuchMethod(ir.Node node, Selector selector,
TypeMask mask, ArgumentsTypes arguments) {
AbstractValue mask, ArgumentsTypes arguments) {
// Ensure we create a node, to make explicit the call to the
// `noSuchMethod` handler.
FunctionEntity noSuchMethod =
@ -1624,7 +1628,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
MemberEntity member = _elementMap.getSuperMember(
_analyzedMember, node.name, node.interfaceTarget);
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
Selector selector = new Selector.getter(_elementMap.getName(node.name));
if (member == null) {
return handleSuperNoSuchMethod(node, selector, mask, null);
@ -1643,7 +1647,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
MemberEntity member = _elementMap.getSuperMember(
_analyzedMember, node.name, node.interfaceTarget,
setter: true);
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
Selector selector = new Selector.setter(_elementMap.getName(node.name));
ArgumentsTypes arguments = new ArgumentsTypes([rhsType], null);
if (member == null) {
@ -1664,7 +1668,7 @@ class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> {
_analyzedMember, node.name, node.interfaceTarget);
ArgumentsTypes arguments = analyzeArguments(node.arguments);
Selector selector = _elementMap.getSelector(node);
TypeMask mask = _memberData.typeOfSend(node);
AbstractValue mask = _memberData.typeOfSend(node);
if (member == null) {
return handleSuperNoSuchMethod(node, selector, mask, arguments);
} else if (member.isFunction) {
@ -1720,7 +1724,7 @@ class IsCheck {
class Refinement {
final Selector selector;
final TypeMask mask;
final AbstractValue mask;
Refinement(this.selector, this.mask);
}

View file

@ -20,7 +20,7 @@ import '../js_model/closure.dart' show JRecordField, KernelScopeInfo;
import '../js_model/elements.dart' show JGeneratorBody;
import '../native/native.dart' as native;
import '../ssa/type_builder.dart';
import '../types/masks.dart';
import '../types/abstract_value_domain.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
import '../world.dart';
@ -369,58 +369,55 @@ enum ForeignKind {
/// Interface for type inference results for kernel IR nodes.
abstract class KernelToTypeInferenceMap {
/// Returns the inferred return type of [function].
TypeMask getReturnTypeOf(FunctionEntity function);
AbstractValue getReturnTypeOf(FunctionEntity function);
/// Returns the inferred receiver type of the dynamic [invocation].
TypeMask receiverTypeOfInvocation(
ir.MethodInvocation invocation, ClosedWorld closedWorld);
AbstractValue receiverTypeOfInvocation(
ir.MethodInvocation invocation, AbstractValueDomain abstractValueDomain);
/// Returns the inferred receiver type of the dynamic [read].
TypeMask receiverTypeOfGet(ir.PropertyGet read);
AbstractValue receiverTypeOfGet(ir.PropertyGet read);
/// Returns the inferred receiver type of the direct [read].
TypeMask receiverTypeOfDirectGet(ir.DirectPropertyGet read);
AbstractValue receiverTypeOfDirectGet(ir.DirectPropertyGet read);
/// Returns the inferred receiver type of the dynamic [write].
TypeMask receiverTypeOfSet(ir.PropertySet write, ClosedWorld closedWorld);
AbstractValue receiverTypeOfSet(
ir.PropertySet write, AbstractValueDomain abstractValueDomain);
/// Returns the inferred type of [listLiteral].
TypeMask typeOfListLiteral(covariant MemberEntity owner,
ir.ListLiteral listLiteral, ClosedWorld closedWorld);
AbstractValue typeOfListLiteral(MemberEntity owner,
ir.ListLiteral listLiteral, AbstractValueDomain abstractValueDomain);
/// Returns the inferred type of iterator in [forInStatement].
TypeMask typeOfIterator(ir.ForInStatement forInStatement);
AbstractValue typeOfIterator(ir.ForInStatement forInStatement);
/// Returns the inferred type of `current` in [forInStatement].
TypeMask typeOfIteratorCurrent(ir.ForInStatement forInStatement);
AbstractValue typeOfIteratorCurrent(ir.ForInStatement forInStatement);
/// Returns the inferred type of `moveNext` in [forInStatement].
TypeMask typeOfIteratorMoveNext(ir.ForInStatement forInStatement);
AbstractValue typeOfIteratorMoveNext(ir.ForInStatement forInStatement);
/// Returns `true` if [forInStatement] is inferred to be a JavaScript
/// indexable iterator.
bool isJsIndexableIterator(
ir.ForInStatement forInStatement, ClosedWorld closedWorld);
/// Returns `true` if [mask] is inferred to have a JavaScript `length`
/// property.
bool isFixedLength(TypeMask mask, ClosedWorld closedWorld);
bool isJsIndexableIterator(ir.ForInStatement forInStatement,
AbstractValueDomain abstractValueDomain);
/// Returns the inferred index type of [forInStatement].
TypeMask inferredIndexType(ir.ForInStatement forInStatement);
AbstractValue inferredIndexType(ir.ForInStatement forInStatement);
/// Returns the inferred type of [member].
TypeMask getInferredTypeOf(MemberEntity member);
AbstractValue getInferredTypeOf(MemberEntity member);
/// Returns the inferred type of the [parameter].
TypeMask getInferredTypeOfParameter(Local parameter);
AbstractValue getInferredTypeOfParameter(Local parameter);
/// Returns the inferred type of a dynamic [selector] access on a receiver of
/// type [mask].
TypeMask selectorTypeOf(Selector selector, TypeMask mask);
/// Returns the inferred type of a dynamic [selector] access on the
/// [receiver].
AbstractValue selectorTypeOf(Selector selector, AbstractValue receiver);
/// Returns the returned type annotation in the [nativeBehavior].
TypeMask typeFromNativeBehavior(
AbstractValue typeFromNativeBehavior(
native.NativeBehavior nativeBehavior, ClosedWorld closedWorld);
}

View file

@ -25,7 +25,7 @@ import '../ssa/builder_kernel.dart';
import '../ssa/nodes.dart';
import '../ssa/ssa.dart';
import '../ssa/types.dart';
import '../types/masks.dart';
import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../universe/selector.dart';
import '../universe/world_impact.dart';
@ -125,92 +125,74 @@ class KernelToTypeInferenceMapImpl implements KernelToTypeInferenceMap {
_globalInferenceResults
.resultOfMember(e is ConstructorBodyEntity ? e.constructor : e);
TypeMask getReturnTypeOf(FunctionEntity function) {
AbstractValue getReturnTypeOf(FunctionEntity function) {
return TypeMaskFactory.inferredReturnTypeForElement(
function, _globalInferenceResults);
}
TypeMask receiverTypeOfInvocation(
ir.MethodInvocation node, ClosedWorld closedWorld) {
AbstractValue receiverTypeOfInvocation(
ir.MethodInvocation node, AbstractValueDomain abstractValueDomain) {
return _targetResults.typeOfSend(node);
}
TypeMask receiverTypeOfGet(ir.PropertyGet node) {
AbstractValue receiverTypeOfGet(ir.PropertyGet node) {
return _targetResults.typeOfSend(node);
}
TypeMask receiverTypeOfDirectGet(ir.DirectPropertyGet node) {
AbstractValue receiverTypeOfDirectGet(ir.DirectPropertyGet node) {
return _targetResults.typeOfSend(node);
}
TypeMask receiverTypeOfSet(ir.PropertySet node, ClosedWorld closedWorld) {
AbstractValue receiverTypeOfSet(
ir.PropertySet node, AbstractValueDomain abstractValueDomain) {
return _targetResults.typeOfSend(node);
}
TypeMask typeOfListLiteral(
MemberEntity owner, ir.ListLiteral listLiteral, ClosedWorld closedWorld) {
AbstractValue typeOfListLiteral(MemberEntity owner,
ir.ListLiteral listLiteral, AbstractValueDomain abstractValueDomain) {
return _resultOf(owner).typeOfListLiteral(listLiteral) ??
closedWorld.abstractValueDomain.dynamicType;
abstractValueDomain.dynamicType;
}
TypeMask typeOfIterator(ir.ForInStatement node) {
AbstractValue typeOfIterator(ir.ForInStatement node) {
return _targetResults.typeOfIterator(node);
}
TypeMask typeOfIteratorCurrent(ir.ForInStatement node) {
AbstractValue typeOfIteratorCurrent(ir.ForInStatement node) {
return _targetResults.typeOfIteratorCurrent(node);
}
TypeMask typeOfIteratorMoveNext(ir.ForInStatement node) {
AbstractValue typeOfIteratorMoveNext(ir.ForInStatement node) {
return _targetResults.typeOfIteratorMoveNext(node);
}
bool isJsIndexableIterator(ir.ForInStatement node, ClosedWorld closedWorld) {
TypeMask mask = typeOfIterator(node);
return mask != null &&
mask.satisfies(
closedWorld.commonElements.jsIndexableClass, closedWorld) &&
// String is indexable but not iterable.
!mask.satisfies(closedWorld.commonElements.jsStringClass, closedWorld);
bool isJsIndexableIterator(
ir.ForInStatement node, AbstractValueDomain abstractValueDomain) {
AbstractValue mask = typeOfIterator(node);
return abstractValueDomain.isJsIndexableAndIterable(mask);
}
bool isFixedLength(covariant TypeMask mask, ClosedWorld closedWorld) {
if (mask.isContainer && (mask as ContainerTypeMask).length != null) {
// A container on which we have inferred the length.
return true;
}
// TODO(sra): Recognize any combination of fixed length indexables.
if (mask.containsOnly(closedWorld.commonElements.jsFixedArrayClass) ||
mask.containsOnly(
closedWorld.commonElements.jsUnmodifiableArrayClass) ||
mask.containsOnlyString(closedWorld) ||
closedWorld.abstractValueDomain.isTypedArray(mask)) {
return true;
}
return false;
}
TypeMask inferredIndexType(ir.ForInStatement node) {
AbstractValue inferredIndexType(ir.ForInStatement node) {
return TypeMaskFactory.inferredTypeForSelector(
new Selector.index(), typeOfIterator(node), _globalInferenceResults);
}
TypeMask getInferredTypeOf(MemberEntity member) {
AbstractValue getInferredTypeOf(MemberEntity member) {
return TypeMaskFactory.inferredTypeForMember(
member, _globalInferenceResults);
}
TypeMask getInferredTypeOfParameter(Local parameter) {
AbstractValue getInferredTypeOfParameter(Local parameter) {
return TypeMaskFactory.inferredTypeForParameter(
parameter, _globalInferenceResults);
}
TypeMask selectorTypeOf(Selector selector, covariant TypeMask mask) {
AbstractValue selectorTypeOf(Selector selector, AbstractValue mask) {
return TypeMaskFactory.inferredTypeForSelector(
selector, mask, _globalInferenceResults);
}
TypeMask typeFromNativeBehavior(
AbstractValue typeFromNativeBehavior(
NativeBehavior nativeBehavior, ClosedWorld closedWorld) {
return TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld);
}

View file

@ -1494,7 +1494,8 @@ class KernelSsaGraphBuilder extends ir.Visitor
void visitForInStatement(ir.ForInStatement node) {
if (node.isAsync) {
_buildAsyncForIn(node);
} else if (_typeInferenceMap.isJsIndexableIterator(node, closedWorld)) {
} else if (_typeInferenceMap.isJsIndexableIterator(
node, abstractValueDomain)) {
// If the expression being iterated over is a JS indexable type, we can
// generate an optimized version of for-in that uses indexing.
_buildForInIndexable(node);
@ -1561,7 +1562,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
node.iterable.accept(this);
array = pop();
isFixed =
_typeInferenceMap.isFixedLength(array.instructionType, closedWorld);
abstractValueDomain.isFixedLengthJsIndexable(array.instructionType);
localsHandler.updateLocal(
indexVariable, graph.addConstantInt(0, closedWorld),
sourceInformation: sourceInformation);
@ -2686,8 +2687,8 @@ class KernelSsaGraphBuilder extends ir.Visitor
listInstruction, type, sourceInformation);
}
TypeMask type =
_typeInferenceMap.typeOfListLiteral(targetElement, node, closedWorld);
TypeMask type = _typeInferenceMap.typeOfListLiteral(
targetElement, node, abstractValueDomain);
if (!type.containsAll(closedWorld)) {
listInstruction.instructionType = type;
}
@ -2926,7 +2927,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
_pushDynamicInvocation(
node,
_typeInferenceMap.receiverTypeOfSet(node, closedWorld),
_typeInferenceMap.receiverTypeOfSet(node, abstractValueDomain),
new Selector.setter(_elementMap.getName(node.name)),
<HInstruction>[receiver, value],
const <DartType>[],
@ -4234,7 +4235,7 @@ class KernelSsaGraphBuilder extends ir.Visitor
_fillDynamicTypeArguments(selector, node.arguments, typeArguments);
_pushDynamicInvocation(
node,
_typeInferenceMap.receiverTypeOfInvocation(node, closedWorld),
_typeInferenceMap.receiverTypeOfInvocation(node, abstractValueDomain),
selector,
<HInstruction>[receiver]..addAll(_visitArgumentsForDynamicTarget(
selector, node.arguments, typeArguments)),

View file

@ -278,4 +278,14 @@ abstract class AbstractValueDomain {
///
/// Returns `null` if 0 or more than 1 member can be hit at runtime.
MemberEntity locateSingleMember(AbstractValue receiver, Selector selector);
/// Returns `true` if [value] is a indexable and iterable JavaScript value at
/// runtime.
///
/// JavaScript arrays are both indexable and iterable whereas JavaScript
/// strings are indexable but not iterable.
bool isJsIndexableAndIterable(AbstractValue value);
/// Returns `true` if [value] is an JavaScript indexable of fixed length.
bool isFixedLengthJsIndexable(AbstractValue value);
}

View file

@ -453,4 +453,31 @@ class CommonMasks implements AbstractValueDomain {
covariant TypeMask receiver, Selector selector) {
return receiver.locateSingleMember(selector, _closedWorld);
}
@override
bool isJsIndexableAndIterable(covariant TypeMask mask) {
return mask != null &&
mask.satisfies(
_closedWorld.commonElements.jsIndexableClass, _closedWorld) &&
// String is indexable but not iterable.
!mask.satisfies(
_closedWorld.commonElements.jsStringClass, _closedWorld);
}
@override
bool isFixedLengthJsIndexable(covariant TypeMask mask) {
if (mask.isContainer && (mask as ContainerTypeMask).length != null) {
// A container on which we have inferred the length.
return true;
}
// TODO(sra): Recognize any combination of fixed length indexables.
if (mask.containsOnly(_closedWorld.commonElements.jsFixedArrayClass) ||
mask.containsOnly(
_closedWorld.commonElements.jsUnmodifiableArrayClass) ||
mask.containsOnlyString(_closedWorld) ||
_closedWorld.abstractValueDomain.isTypedArray(mask)) {
return true;
}
return false;
}
}

View file

@ -461,7 +461,7 @@ abstract class ClosedWorldBase implements ClosedWorld, ClosedWorldRefiner {
final Set<FunctionEntity> _functionsThatMightBePassedToApply =
new Set<FunctionEntity>();
CommonMasks _commonMasks;
AbstractValueDomain _abstractValueDomain;
final ElementEnvironment elementEnvironment;
final DartTypes dartTypes;
@ -500,14 +500,14 @@ abstract class ClosedWorldBase implements ClosedWorld, ClosedWorldRefiner {
: this._implementedClasses = implementedClasses,
this._classHierarchyNodes = classHierarchyNodes,
this._classSets = classSets {
_commonMasks = new CommonMasks(this);
_abstractValueDomain = new CommonMasks(this);
}
@override
ClosedWorld get closedWorld => this;
CommonMasks get abstractValueDomain {
return _commonMasks;
AbstractValueDomain get abstractValueDomain {
return _abstractValueDomain;
}
bool checkEntity(covariant Entity element);