mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 14:59:41 +00:00
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:
parent
3dd70ce67b
commit
947760f9b2
|
@ -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)) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue