Use AbstractValue in much of inference

Change-Id: I38cd4631c099ec6bd16c675804ccc453a6401889
Reviewed-on: https://dart-review.googlesource.com/56670
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 3dd70ce67b
commit 947760f9b2
6 changed files with 140 additions and 95 deletions

View file

@ -7,7 +7,7 @@ library compiler.src.inferrer.closure_tracer;
import '../common/names.dart' show Names;
import '../elements/entities.dart';
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../types/masks.dart' show TypeMask;
import '../types/abstract_value_domain.dart';
import '../universe/selector.dart' show Selector;
import 'debug.dart' as debug;
import 'inferrer_engine.dart';
@ -56,7 +56,7 @@ class ClosureTracerVisitor extends TracerVisitor {
void _analyzeCall(CallSiteTypeInformation info) {
Selector selector = info.selector;
TypeMask mask = info.mask;
AbstractValue mask = info.mask;
tracedElements.forEach((FunctionEntity functionElement) {
if (!selector.callStructure
.signatureApplies(functionElement.parameterStructure)) {

View file

@ -19,7 +19,6 @@ import '../native/behavior.dart' as native;
import '../options.dart';
import '../types/abstract_value_domain.dart';
import '../types/constants.dart';
import '../types/masks.dart';
import '../types/types.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
@ -87,7 +86,7 @@ abstract class InferrerEngine<T> {
/// Applies [f] to all elements in the universe that match [selector] and
/// [mask]. If [f] returns false, aborts the iteration.
void forEachElementMatching(
Selector selector, TypeMask mask, bool f(MemberEntity element));
Selector selector, AbstractValue mask, bool f(MemberEntity element));
/// Returns the [TypeInformation] node for the default value of a parameter.
/// If this is queried before it is set by [setDefaultTypeOfParameter], a
@ -147,7 +146,7 @@ abstract class InferrerEngine<T> {
TypeInformation registerCalledClosure(
T node,
Selector selector,
TypeMask mask,
AbstractValue mask,
TypeInformation closure,
MemberEntity caller,
ArgumentsTypes arguments,
@ -165,7 +164,7 @@ abstract class InferrerEngine<T> {
TypeInformation registerCalledMember(
Object node,
Selector selector,
TypeMask mask,
AbstractValue mask,
MemberEntity caller,
MemberEntity callee,
ArgumentsTypes arguments,
@ -183,7 +182,7 @@ abstract class InferrerEngine<T> {
CallType callType,
T node,
Selector selector,
TypeMask mask,
AbstractValue mask,
TypeInformation receiverType,
MemberEntity caller,
ArgumentsTypes arguments,
@ -195,11 +194,11 @@ abstract class InferrerEngine<T> {
/// assignments must be added or removed. If [init] is false, parameters are
/// added to the work queue.
void updateParameterAssignments(TypeInformation caller, MemberEntity callee,
ArgumentsTypes arguments, Selector selector, TypeMask mask,
ArgumentsTypes arguments, Selector selector, AbstractValue mask,
{bool remove, bool addToQueue: true});
void updateSelectorInMember(MemberEntity owner, CallType callType, T node,
Selector selector, TypeMask mask);
Selector selector, AbstractValue mask);
/// Returns the return type of [element].
TypeInformation returnTypeOfMember(MemberEntity element);
@ -218,9 +217,9 @@ abstract class InferrerEngine<T> {
/// [native.NativeBehavior].
TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior);
bool returnsListElementType(Selector selector, TypeMask mask);
bool returnsListElementType(Selector selector, AbstractValue mask);
bool returnsMapValueType(Selector selector, TypeMask mask);
bool returnsMapValueType(Selector selector, AbstractValue mask);
void clear();
@ -304,7 +303,7 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
: this.types = new TypeSystem<T>(closedWorld, typeSystemStrategy);
void forEachElementMatching(
Selector selector, TypeMask mask, bool f(MemberEntity element)) {
Selector selector, AbstractValue mask, bool f(MemberEntity element)) {
Iterable<MemberEntity> elements = closedWorld.locateMembers(selector, mask);
for (MemberEntity e in elements) {
if (!f(e)) return;
@ -391,7 +390,7 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
}
void updateSelectorInMember(MemberEntity owner, CallType callType, T node,
Selector selector, TypeMask mask) {
Selector selector, AbstractValue mask) {
GlobalTypeInferenceElementData data = dataOfMember(owner);
assert(validCallType(callType, node));
switch (callType) {
@ -421,14 +420,14 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
}
}
bool returnsListElementType(Selector selector, TypeMask mask) {
bool returnsListElementType(Selector selector, AbstractValue mask) {
return mask != null &&
mask.isContainer &&
abstractValueDomain.isContainer(mask) &&
returnsListElementTypeSet.contains(selector);
}
bool returnsMapValueType(Selector selector, TypeMask mask) {
return mask != null && mask.isMap && selector.isIndex;
bool returnsMapValueType(Selector selector, AbstractValue mask) {
return mask != null && abstractValueDomain.isMap(mask) && selector.isIndex;
}
void analyzeListAndEnqueue(ListTypeInformation info) {
@ -441,7 +440,7 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
info.bailedOut = false;
info.elementType.inferred = true;
TypeMask fixedListType = abstractValueDomain.fixedListType;
AbstractValue fixedListType = abstractValueDomain.fixedListType;
if (info.originalType.forwardTo == fixedListType) {
info.checksGrowable = tracer.callsGrowableMethod;
}
@ -711,8 +710,7 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
// Although we might find a better type, we have to keep
// the old type around to ensure that we get a complete view
// of the type graph and do not drop any flow edges.
TypeMask refinedType = computeTypeMask(closedWorld, value);
assert(TypeMask.assertIsNormalized(refinedType, closedWorld));
AbstractValue refinedType = computeTypeMask(closedWorld, value);
type = new NarrowTypeInformation(type, refinedType);
types.allocatedTypes.add(type);
}
@ -784,8 +782,8 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
while (!workQueue.isEmpty) {
progress.showProgress('Inferred ', overallRefineCount, ' types.');
TypeInformation info = workQueue.remove();
TypeMask oldType = info.type;
TypeMask newType = info.refine(this);
AbstractValue oldType = info.type;
AbstractValue newType = info.refine(this);
// Check that refinement has not accidentally changed the type.
assert(oldType == info.type);
if (info.abandonInferencing) info.doNotEnqueue = true;
@ -816,7 +814,7 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
}
void updateParameterAssignments(TypeInformation caller, MemberEntity callee,
ArgumentsTypes arguments, Selector selector, TypeMask mask,
ArgumentsTypes arguments, Selector selector, AbstractValue mask,
{bool remove, bool addToQueue: true}) {
if (callee.name == Identifiers.noSuchMethod_) return;
if (callee.isField) {
@ -962,7 +960,7 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
TypeInformation registerCalledMember(
Object node,
Selector selector,
TypeMask mask,
AbstractValue mask,
MemberEntity caller,
MemberEntity callee,
ArgumentsTypes arguments,
@ -1001,7 +999,7 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
CallType callType,
T node,
Selector selector,
TypeMask mask,
AbstractValue mask,
TypeInformation receiverType,
MemberEntity caller,
ArgumentsTypes arguments,
@ -1057,7 +1055,7 @@ abstract class InferrerEngineImpl<T> extends InferrerEngine<T> {
TypeInformation registerCalledClosure(
T node,
Selector selector,
TypeMask mask,
AbstractValue mask,
TypeInformation closure,
MemberEntity caller,
ArgumentsTypes arguments,

View file

@ -5,7 +5,8 @@
import '../common.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
import '../types/masks.dart';
import '../types/abstract_value_domain.dart';
import '../types/masks.dart' show ContainerTypeMask, MapTypeMask;
import '../universe/selector.dart';
import '../world.dart';
import 'type_graph_nodes.dart';
@ -43,7 +44,7 @@ abstract class TypeSystemStrategy<T> {
* The class [SimpleInferrerVisitor] will use when working on types.
*/
class TypeSystem<T> {
final ClosedWorld closedWorld;
final ClosedWorld _closedWorld;
final TypeSystemStrategy<T> strategy;
/// [parameterTypeInformations] and [memberTypeInformations] ordered by
@ -68,8 +69,8 @@ class TypeSystem<T> {
final Set<TypeInformation> allocatedClosures = new Set<TypeInformation>();
/// Cache of [ConcreteTypeInformation].
final Map<TypeMask, TypeInformation> concreteTypes =
new Map<TypeMask, TypeInformation>();
final Map<AbstractValue, TypeInformation> concreteTypes =
new Map<AbstractValue, TypeInformation>();
/// List of [TypeInformation]s for calls inside method bodies.
final List<CallSiteTypeInformation> allocatedCalls =
@ -95,11 +96,12 @@ class TypeSystem<T> {
allocatedTypes
].expand((x) => x);
TypeSystem(this.closedWorld, this.strategy) {
nonNullEmptyType = getConcreteTypeFor(commonMasks.emptyType);
TypeSystem(this._closedWorld, this.strategy) {
nonNullEmptyType = getConcreteTypeFor(_abstractValueDomain.emptyType);
}
CommonMasks get commonMasks => closedWorld.abstractValueDomain;
AbstractValueDomain get _abstractValueDomain =>
_closedWorld.abstractValueDomain;
/// Used to group [TypeInformation] nodes by the element that triggered their
/// creation.
@ -117,111 +119,120 @@ class TypeSystem<T> {
TypeInformation nullTypeCache;
TypeInformation get nullType {
if (nullTypeCache != null) return nullTypeCache;
return nullTypeCache = getConcreteTypeFor(commonMasks.nullType);
return nullTypeCache = getConcreteTypeFor(_abstractValueDomain.nullType);
}
TypeInformation intTypeCache;
TypeInformation get intType {
if (intTypeCache != null) return intTypeCache;
return intTypeCache = getConcreteTypeFor(commonMasks.intType);
return intTypeCache = getConcreteTypeFor(_abstractValueDomain.intType);
}
TypeInformation uint32TypeCache;
TypeInformation get uint32Type {
if (uint32TypeCache != null) return uint32TypeCache;
return uint32TypeCache = getConcreteTypeFor(commonMasks.uint32Type);
return uint32TypeCache =
getConcreteTypeFor(_abstractValueDomain.uint32Type);
}
TypeInformation uint31TypeCache;
TypeInformation get uint31Type {
if (uint31TypeCache != null) return uint31TypeCache;
return uint31TypeCache = getConcreteTypeFor(commonMasks.uint31Type);
return uint31TypeCache =
getConcreteTypeFor(_abstractValueDomain.uint31Type);
}
TypeInformation positiveIntTypeCache;
TypeInformation get positiveIntType {
if (positiveIntTypeCache != null) return positiveIntTypeCache;
return positiveIntTypeCache =
getConcreteTypeFor(commonMasks.positiveIntType);
getConcreteTypeFor(_abstractValueDomain.positiveIntType);
}
TypeInformation doubleTypeCache;
TypeInformation get doubleType {
if (doubleTypeCache != null) return doubleTypeCache;
return doubleTypeCache = getConcreteTypeFor(commonMasks.doubleType);
return doubleTypeCache =
getConcreteTypeFor(_abstractValueDomain.doubleType);
}
TypeInformation numTypeCache;
TypeInformation get numType {
if (numTypeCache != null) return numTypeCache;
return numTypeCache = getConcreteTypeFor(commonMasks.numType);
return numTypeCache = getConcreteTypeFor(_abstractValueDomain.numType);
}
TypeInformation boolTypeCache;
TypeInformation get boolType {
if (boolTypeCache != null) return boolTypeCache;
return boolTypeCache = getConcreteTypeFor(commonMasks.boolType);
return boolTypeCache = getConcreteTypeFor(_abstractValueDomain.boolType);
}
TypeInformation functionTypeCache;
TypeInformation get functionType {
if (functionTypeCache != null) return functionTypeCache;
return functionTypeCache = getConcreteTypeFor(commonMasks.functionType);
return functionTypeCache =
getConcreteTypeFor(_abstractValueDomain.functionType);
}
TypeInformation listTypeCache;
TypeInformation get listType {
if (listTypeCache != null) return listTypeCache;
return listTypeCache = getConcreteTypeFor(commonMasks.listType);
return listTypeCache = getConcreteTypeFor(_abstractValueDomain.listType);
}
TypeInformation constListTypeCache;
TypeInformation get constListType {
if (constListTypeCache != null) return constListTypeCache;
return constListTypeCache = getConcreteTypeFor(commonMasks.constListType);
return constListTypeCache =
getConcreteTypeFor(_abstractValueDomain.constListType);
}
TypeInformation fixedListTypeCache;
TypeInformation get fixedListType {
if (fixedListTypeCache != null) return fixedListTypeCache;
return fixedListTypeCache = getConcreteTypeFor(commonMasks.fixedListType);
return fixedListTypeCache =
getConcreteTypeFor(_abstractValueDomain.fixedListType);
}
TypeInformation growableListTypeCache;
TypeInformation get growableListType {
if (growableListTypeCache != null) return growableListTypeCache;
return growableListTypeCache =
getConcreteTypeFor(commonMasks.growableListType);
getConcreteTypeFor(_abstractValueDomain.growableListType);
}
TypeInformation mapTypeCache;
TypeInformation get mapType {
if (mapTypeCache != null) return mapTypeCache;
return mapTypeCache = getConcreteTypeFor(commonMasks.mapType);
return mapTypeCache = getConcreteTypeFor(_abstractValueDomain.mapType);
}
TypeInformation constMapTypeCache;
TypeInformation get constMapType {
if (constMapTypeCache != null) return constMapTypeCache;
return constMapTypeCache = getConcreteTypeFor(commonMasks.constMapType);
return constMapTypeCache =
getConcreteTypeFor(_abstractValueDomain.constMapType);
}
TypeInformation stringTypeCache;
TypeInformation get stringType {
if (stringTypeCache != null) return stringTypeCache;
return stringTypeCache = getConcreteTypeFor(commonMasks.stringType);
return stringTypeCache =
getConcreteTypeFor(_abstractValueDomain.stringType);
}
TypeInformation typeTypeCache;
TypeInformation get typeType {
if (typeTypeCache != null) return typeTypeCache;
return typeTypeCache = getConcreteTypeFor(commonMasks.typeType);
return typeTypeCache = getConcreteTypeFor(_abstractValueDomain.typeType);
}
TypeInformation dynamicTypeCache;
TypeInformation get dynamicType {
if (dynamicTypeCache != null) return dynamicTypeCache;
return dynamicTypeCache = getConcreteTypeFor(commonMasks.dynamicType);
return dynamicTypeCache =
getConcreteTypeFor(_abstractValueDomain.dynamicType);
}
TypeInformation asyncFutureTypeCache;
@ -229,31 +240,32 @@ class TypeSystem<T> {
TypeInformation get asyncFutureType {
if (asyncFutureTypeCache != null) return asyncFutureTypeCache;
return asyncFutureTypeCache =
getConcreteTypeFor(commonMasks.asyncFutureType);
getConcreteTypeFor(_abstractValueDomain.asyncFutureType);
}
TypeInformation syncStarIterableTypeCache;
TypeInformation get syncStarIterableType {
if (syncStarIterableTypeCache != null) return syncStarIterableTypeCache;
return syncStarIterableTypeCache =
getConcreteTypeFor(commonMasks.syncStarIterableType);
getConcreteTypeFor(_abstractValueDomain.syncStarIterableType);
}
TypeInformation asyncStarStreamTypeCache;
TypeInformation get asyncStarStreamType {
if (asyncStarStreamTypeCache != null) return asyncStarStreamTypeCache;
return asyncStarStreamTypeCache =
getConcreteTypeFor(commonMasks.asyncStarStreamType);
getConcreteTypeFor(_abstractValueDomain.asyncStarStreamType);
}
TypeInformation nonNullEmptyType;
TypeInformation stringLiteralType(String value) {
return new StringLiteralTypeInformation(value, commonMasks.stringType);
return new StringLiteralTypeInformation(
value, _abstractValueDomain.stringType);
}
TypeInformation boolLiteralType(bool value) {
return new BoolLiteralTypeInformation(value, commonMasks.boolType);
return new BoolLiteralTypeInformation(value, _abstractValueDomain.boolType);
}
/**
@ -270,14 +282,14 @@ class TypeSystem<T> {
return dynamicType;
}
return getConcreteTypeFor(
firstType.type.union(secondType.type, closedWorld));
firstType.type.union(secondType.type, _closedWorld));
}
/**
* Returns `true` if `selector` should be updated to reflect the new
* `receiverType`.
*/
bool selectorNeedsUpdate(TypeInformation info, TypeMask mask) {
bool selectorNeedsUpdate(TypeInformation info, AbstractValue mask) {
return info.type != mask;
}
@ -290,23 +302,23 @@ class TypeSystem<T> {
* be null.
*/
TypeInformation refineReceiver(
Selector selector, TypeMask mask, TypeInformation receiver,
Selector selector, AbstractValue mask, TypeInformation receiver,
{bool isConditional}) {
if (receiver.type.isExact) return receiver;
TypeMask otherType = closedWorld.computeReceiverType(selector, mask);
AbstractValue otherType = _closedWorld.computeReceiverType(selector, mask);
// Conditional sends (a?.b) can still narrow the possible types of `a`,
// however, we still need to consider that `a` may be null.
if (isConditional) {
// Note: we don't check that receiver.type.isNullable here because this is
// called during the graph construction.
otherType = otherType.nullable();
otherType = _abstractValueDomain.includeNull(otherType);
}
// If this is refining to nullable subtype of `Object` just return
// the receiver. We know the narrowing is useless.
if (otherType.isNullable && otherType.containsAll(closedWorld)) {
if (_abstractValueDomain.canBeNull(otherType) &&
_abstractValueDomain.containsAll(otherType)) {
return receiver;
}
assert(TypeMask.assertIsNormalized(otherType, closedWorld));
TypeInformation newType = new NarrowTypeInformation(receiver, otherType);
allocatedTypes.add(newType);
return newType;
@ -321,16 +333,17 @@ class TypeSystem<T> {
{bool isNullable: true}) {
if (annotation.treatAsDynamic) return type;
if (annotation.isVoid) return type;
TypeMask otherType;
AbstractValue otherType;
if (annotation.isInterfaceType) {
InterfaceType interface = annotation;
if (interface.element == closedWorld.commonElements.objectClass) {
if (interface.element == _closedWorld.commonElements.objectClass) {
if (isNullable) {
return type;
}
otherType = dynamicType.type.nonNullable();
} else {
otherType = new TypeMask.nonNullSubtype(interface.element, closedWorld);
otherType =
_abstractValueDomain.createNonNullSubtype(interface.element);
}
} else if (annotation.isTypedef || annotation.isFunctionType) {
otherType = functionType.type;
@ -342,11 +355,12 @@ class TypeSystem<T> {
// TODO(ngeoffray): Narrow to bound.
return type;
}
if (isNullable) otherType = otherType.nullable();
if (isNullable) {
otherType = _abstractValueDomain.includeNull(otherType);
}
if (type.type.isExact) {
return type;
} else {
assert(TypeMask.assertIsNormalized(otherType, closedWorld));
TypeInformation newType = new NarrowTypeInformation(type, otherType);
allocatedTypes.add(newType);
return newType;
@ -389,7 +403,7 @@ class TypeSystem<T> {
/**
* Returns the internal inferrer representation for [mask].
*/
ConcreteTypeInformation getConcreteTypeFor(TypeMask mask) {
ConcreteTypeInformation getConcreteTypeFor(AbstractValue mask) {
assert(mask != null);
return concreteTypes.putIfAbsent(mask, () {
return new ConcreteTypeInformation(mask);
@ -409,17 +423,17 @@ class TypeSystem<T> {
TypeInformation nonNullSubtype(ClassEntity cls) {
assert(strategy.checkClassEntity(cls));
return getConcreteTypeFor(new TypeMask.nonNullSubtype(cls, closedWorld));
return getConcreteTypeFor(_abstractValueDomain.createNonNullSubtype(cls));
}
TypeInformation nonNullSubclass(ClassEntity cls) {
assert(strategy.checkClassEntity(cls));
return getConcreteTypeFor(new TypeMask.nonNullSubclass(cls, closedWorld));
return getConcreteTypeFor(_abstractValueDomain.createNonNullSubclass(cls));
}
TypeInformation nonNullExact(ClassEntity cls) {
assert(strategy.checkClassEntity(cls));
return getConcreteTypeFor(new TypeMask.nonNullExact(cls, closedWorld));
return getConcreteTypeFor(_abstractValueDomain.createNonNullExact(cls));
}
TypeInformation nonNullEmpty() {
@ -434,17 +448,18 @@ class TypeSystem<T> {
TypeInformation type, T node, MemberEntity enclosing,
[TypeInformation elementType, int length]) {
assert(strategy.checkListNode(node));
ClassEntity typedDataClass = closedWorld.commonElements.typedDataClass;
ClassEntity typedDataClass = _closedWorld.commonElements.typedDataClass;
bool isTypedArray = typedDataClass != null &&
closedWorld.isInstantiated(typedDataClass) &&
type.type.satisfies(typedDataClass, closedWorld);
bool isConst = (type.type == commonMasks.constListType);
bool isFixed =
(type.type == commonMasks.fixedListType) || isConst || isTypedArray;
_closedWorld.isInstantiated(typedDataClass) &&
type.type.satisfies(typedDataClass, _closedWorld);
bool isConst = (type.type == _abstractValueDomain.constListType);
bool isFixed = (type.type == _abstractValueDomain.fixedListType) ||
isConst ||
isTypedArray;
bool isElementInferred = isConst || isTypedArray;
int inferredLength = isFixed ? length : null;
TypeMask elementTypeMask =
AbstractValue elementTypeMask =
isElementInferred ? elementType.type : dynamicType.type;
ContainerTypeMask<T> mask = new ContainerTypeMask<T>(
type.type, node, enclosing, elementTypeMask, inferredLength);
@ -471,14 +486,14 @@ class TypeSystem<T> {
[List<TypeInformation> keyTypes, List<TypeInformation> valueTypes]) {
assert(strategy.checkMapNode(node));
assert(keyTypes.length == valueTypes.length);
bool isFixed = (type.type == commonMasks.constMapType);
bool isFixed = (type.type == _abstractValueDomain.constMapType);
TypeMask keyType, valueType;
AbstractValue keyType, valueType;
if (isFixed) {
keyType = keyTypes.fold(nonNullEmptyType.type,
(type, info) => type.union(info.type, closedWorld));
(type, info) => _abstractValueDomain.union(type, info.type));
valueType = valueTypes.fold(nonNullEmptyType.type,
(type, info) => type.union(info.type, closedWorld));
(type, info) => _abstractValueDomain.union(type, info.type));
} else {
keyType = valueType = dynamicType.type;
}
@ -509,7 +524,7 @@ class TypeSystem<T> {
return map;
}
TypeMask newTypedSelector(TypeInformation info, TypeMask mask) {
AbstractValue newTypedSelector(TypeInformation info, AbstractValue mask) {
// Only type the selector if [info] is concrete, because the other
// kinds of [TypeInformation] have the empty type at this point of
// analysis.
@ -595,32 +610,33 @@ class TypeSystem<T> {
return phiType;
}
TypeMask computeTypeMask(Iterable<TypeInformation> assignments) {
AbstractValue computeTypeMask(Iterable<TypeInformation> assignments) {
return joinTypeMasks(assignments.map((e) => e.type));
}
TypeMask joinTypeMasks(Iterable<TypeMask> masks) {
var dynamicType = commonMasks.dynamicType;
AbstractValue joinTypeMasks(Iterable<AbstractValue> masks) {
var dynamicType = _abstractValueDomain.dynamicType;
// Optimization: we are iterating over masks twice, but because `masks` is a
// mapped iterable, we save the intermediate results to avoid computing them
// again.
var list = [];
for (TypeMask mask in masks) {
for (AbstractValue mask in masks) {
// Don't do any work on computing unions if we know that after all that
// work the result will be `dynamic`.
// TODO(sigmund): change to `mask == dynamicType` so we can continue to
// track the non-nullable bit.
if (mask.containsAll(closedWorld)) return dynamicType;
if (_abstractValueDomain.containsAll(mask)) return dynamicType;
list.add(mask);
}
TypeMask newType = null;
for (TypeMask mask in list) {
newType = newType == null ? mask : newType.union(mask, closedWorld);
AbstractValue newType = null;
for (AbstractValue mask in list) {
newType =
newType == null ? mask : _abstractValueDomain.union(newType, mask);
// Likewise - stop early if we already reach dynamic.
if (newType.containsAll(closedWorld)) return dynamicType;
if (_abstractValueDomain.containsAll(newType)) return dynamicType;
}
return newType ?? const TypeMask.nonNullEmpty();
return newType ?? _abstractValueDomain.emptyType;
}
}

View file

@ -37,7 +37,7 @@ import '../library_loader.dart' show LoadedLibraries;
import '../native/native.dart' as native;
import '../ssa/ssa.dart' show SsaFunctionCompiler;
import '../tracer.dart';
import '../types/masks.dart';
import '../types/masks.dart' show TypeMaskStrategy;
import '../universe/call_structure.dart' show CallStructure;
import '../universe/class_hierarchy_builder.dart'
show ClassHierarchyBuilder, ClassQueries;

View file

@ -91,6 +91,18 @@ abstract class AbstractValueDomain {
/// The [AbstractValue] that represents the empty set of runtime values.
AbstractValue get emptyType;
/// The [AbstractValue] that represents a non-null instance at runtime of the
/// `Iterable` class used for the `sync*` implementation.
AbstractValue get syncStarIterableType;
/// The [AbstractValue] that represents a non-null instance at runtime of the
/// `Future` class used for the `async` implementation.
AbstractValue get asyncFutureType;
/// The [AbstractValue] that represents a non-null instance at runtime of the
/// `Stream` class used for the `async*` implementation.
AbstractValue get asyncStarStreamType;
/// Creates an [AbstractValue] for a non-null exact instance of [cls].
AbstractValue createNonNullExact(ClassEntity cls);
@ -277,10 +289,16 @@ abstract class AbstractValueDomain {
/// Computes the [AbstractValue] corresponding to the constant [value].
AbstractValue computeAbstractValueForConstant(ConstantValue value);
/// Returns `true` if [value] represents a container value at runtime.
bool isContainer(covariant AbstractValue value);
/// Returns the element type of [value] if it represents a container value
/// at runtime. Returns [dynamicType] otherwise.
AbstractValue getContainerElementType(AbstractValue value);
/// Returns `true` if [value] represents a map value at runtime.
bool isMap(covariant AbstractValue value);
/// Returns the value type of [value] if it represents a map value at runtime.
/// Returns [dynamicType] otherwise.
AbstractValue getMapValueType(AbstractValue value);

View file

@ -151,13 +151,16 @@ class CommonMasks implements AbstractValueDomain {
TypeMask get typeType => _typeType ??=
new TypeMask.nonNullExact(commonElements.typeLiteralClass, _closedWorld);
@override
TypeMask get syncStarIterableType => _syncStarIterableType ??=
new TypeMask.nonNullExact(commonElements.syncStarIterable, _closedWorld);
@override
TypeMask get asyncFutureType =>
_asyncFutureType ??= new TypeMask.nonNullExact(
commonElements.futureImplementation, _closedWorld);
@override
TypeMask get asyncStarStreamType => _asyncStarStreamType ??=
new TypeMask.nonNullExact(commonElements.controllerStream, _closedWorld);
@ -596,4 +599,14 @@ class CommonMasks implements AbstractValueDomain {
bool canBeInterceptor(TypeMask value) {
return !interceptorType.isDisjoint(value, _closedWorld);
}
@override
bool isMap(TypeMask value) {
return value.isMap;
}
@override
bool isContainer(TypeMask value) {
return value.isContainer;
}
}