Use AbstractValue in KernelToTypeInferenceMap and KernelTypeGraphBuilder
Change-Id: I0af69d10223364256852248228cdbbcbca3f83fa
Reviewed-on: https://dart-review.googlesource.com/56484
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index bb5ebdb..afa3b0a 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -18,7 +18,7 @@
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 @@
/// 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 @@
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 @@
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 @@
@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 @@
CallType callType,
ir.Node node,
Selector selector,
- TypeMask mask,
+ AbstractValue mask,
TypeInformation receiverType,
ArgumentsTypes arguments) {
assert(receiverType != null);
@@ -811,13 +811,17 @@
}
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 @@
CallType callType,
ir.Node node,
Selector selector,
- TypeMask mask,
+ AbstractValue mask,
TypeInformation receiverType,
ArgumentsTypes arguments) {
return _handleDynamic(
@@ -896,8 +900,8 @@
_markThisAsExposed();
}
- TypeMask currentMask;
- TypeMask moveNextMask;
+ AbstractValue currentMask;
+ AbstractValue moveNextMask;
TypeInformation iteratorType;
if (node.isAsync) {
TypeInformation expressionType = visit(node.iterable);
@@ -914,7 +918,7 @@
} 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 @@
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 @@
ir.Node node,
ir.Arguments arguments,
Selector selector,
- TypeMask mask,
+ AbstractValue mask,
ConstructorEntity constructor,
ArgumentsTypes argumentsTypes) {
TypeInformation returnType =
@@ -1089,13 +1093,13 @@
}
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 @@
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 @@
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 @@
@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 @@
_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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
_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 Refinement {
final Selector selector;
- final TypeMask mask;
+ final AbstractValue mask;
Refinement(this.selector, this.mask);
}
diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart
index 13adcc4..7c90a63 100644
--- a/pkg/compiler/lib/src/kernel/element_map.dart
+++ b/pkg/compiler/lib/src/kernel/element_map.dart
@@ -20,7 +20,7 @@
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 @@
/// 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);
}
diff --git a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
index ae1b004..b0487db 100644
--- a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
@@ -25,7 +25,7 @@
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 @@
_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);
}
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 65e1636..df419aa 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -1494,7 +1494,8 @@
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 @@
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 @@
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 @@
_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 @@
_fillDynamicTypeArguments(selector, node.arguments, typeArguments);
_pushDynamicInvocation(
node,
- _typeInferenceMap.receiverTypeOfInvocation(node, closedWorld),
+ _typeInferenceMap.receiverTypeOfInvocation(node, abstractValueDomain),
selector,
<HInstruction>[receiver]..addAll(_visitArgumentsForDynamicTarget(
selector, node.arguments, typeArguments)),
diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart
index de04b3d..1130029 100644
--- a/pkg/compiler/lib/src/types/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/types/abstract_value_domain.dart
@@ -278,4 +278,14 @@
///
/// 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);
}
diff --git a/pkg/compiler/lib/src/types/masks.dart b/pkg/compiler/lib/src/types/masks.dart
index 19455cc..c8a17fb 100644
--- a/pkg/compiler/lib/src/types/masks.dart
+++ b/pkg/compiler/lib/src/types/masks.dart
@@ -453,4 +453,31 @@
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;
+ }
}
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 9bd4e8a..46a6d583 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -461,7 +461,7 @@
final Set<FunctionEntity> _functionsThatMightBePassedToApply =
new Set<FunctionEntity>();
- CommonMasks _commonMasks;
+ AbstractValueDomain _abstractValueDomain;
final ElementEnvironment elementEnvironment;
final DartTypes dartTypes;
@@ -500,14 +500,14 @@
: 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);