Use AbstractValue in inference results.
Change-Id: I2a932abd2d8d3236b560721c9d5ec010271d2b85
Reviewed-on: https://dart-review.googlesource.com/55362
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index ca4b7ce..07aa78b 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -17,6 +17,7 @@
import '../js_emitter/sorter.dart';
import '../native/behavior.dart' as native;
import '../options.dart';
+import '../types/abstract_value_domain.dart';
import '../types/constants.dart';
import '../types/types.dart';
import '../universe/call_structure.dart';
@@ -56,7 +57,8 @@
ClosedWorld get closedWorld;
ClosedWorldRefiner get closedWorldRefiner;
DiagnosticReporter get reporter;
- CommonMasks get commonMasks => closedWorld.abstractValueDomain;
+ AbstractValueDomain get abstractValueDomain =>
+ closedWorld.abstractValueDomain;
CommonElements get commonElements => closedWorld.commonElements;
// TODO(johnniwinther): This should be part of [ClosedWorld] or
@@ -438,7 +440,7 @@
info.bailedOut = false;
info.elementType.inferred = true;
- TypeMask fixedListType = commonMasks.fixedListType;
+ TypeMask fixedListType = abstractValueDomain.fixedListType;
if (info.originalType.forwardTo == fixedListType) {
info.checksGrowable = tracer.callsGrowableMethod;
}
diff --git a/pkg/compiler/lib/src/inferrer/kernel_inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/kernel_inferrer_engine.dart
index 3b3754b..7b49435 100644
--- a/pkg/compiler/lib/src/inferrer/kernel_inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/kernel_inferrer_engine.dart
@@ -18,6 +18,7 @@
import '../js_model/locals.dart';
import '../kernel/element_map.dart';
import '../options.dart';
+import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../world.dart';
import 'builder_kernel.dart';
@@ -81,14 +82,13 @@
// for closure elements.
inferrer.inferrer.lookupDataOfMember(member),
inferrer,
- isJsInterop,
- dynamicType);
+ isJsInterop);
}
GlobalTypeInferenceParameterResult<ir.Node> createParameterResult(
TypeGraphInferrer<ir.Node> inferrer, Local parameter) {
return new GlobalTypeInferenceParameterResultImpl<ir.Node>(
- parameter, inferrer, dynamicType);
+ parameter, inferrer);
}
}
@@ -331,62 +331,65 @@
class KernelGlobalTypeInferenceElementData
extends GlobalTypeInferenceElementData<ir.Node> {
// TODO(johnniwinther): Rename this together with [typeOfSend].
- Map<ir.Node, TypeMask> _sendMap;
+ Map<ir.Node, AbstractValue> _sendMap;
- Map<ir.ForInStatement, TypeMask> _iteratorMap;
- Map<ir.ForInStatement, TypeMask> _currentMap;
- Map<ir.ForInStatement, TypeMask> _moveNextMap;
+ Map<ir.ForInStatement, AbstractValue> _iteratorMap;
+ Map<ir.ForInStatement, AbstractValue> _currentMap;
+ Map<ir.ForInStatement, AbstractValue> _moveNextMap;
@override
- TypeMask typeOfSend(ir.Node node) {
+ AbstractValue typeOfSend(ir.Node node) {
if (_sendMap == null) return null;
return _sendMap[node];
}
@override
- void setCurrentTypeMask(covariant ir.ForInStatement node, TypeMask mask) {
- _currentMap ??= <ir.ForInStatement, TypeMask>{};
+ void setCurrentTypeMask(
+ covariant ir.ForInStatement node, AbstractValue mask) {
+ _currentMap ??= <ir.ForInStatement, AbstractValue>{};
_currentMap[node] = mask;
}
@override
- void setMoveNextTypeMask(covariant ir.ForInStatement node, TypeMask mask) {
- _moveNextMap ??= <ir.ForInStatement, TypeMask>{};
+ void setMoveNextTypeMask(
+ covariant ir.ForInStatement node, AbstractValue mask) {
+ _moveNextMap ??= <ir.ForInStatement, AbstractValue>{};
_moveNextMap[node] = mask;
}
@override
- void setIteratorTypeMask(covariant ir.ForInStatement node, TypeMask mask) {
- _iteratorMap ??= <ir.ForInStatement, TypeMask>{};
+ void setIteratorTypeMask(
+ covariant ir.ForInStatement node, AbstractValue mask) {
+ _iteratorMap ??= <ir.ForInStatement, AbstractValue>{};
_iteratorMap[node] = mask;
}
@override
- TypeMask typeOfIteratorCurrent(covariant ir.ForInStatement node) {
+ AbstractValue typeOfIteratorCurrent(covariant ir.ForInStatement node) {
if (_currentMap == null) return null;
return _currentMap[node];
}
@override
- TypeMask typeOfIteratorMoveNext(covariant ir.ForInStatement node) {
+ AbstractValue typeOfIteratorMoveNext(covariant ir.ForInStatement node) {
if (_moveNextMap == null) return null;
return _moveNextMap[node];
}
@override
- TypeMask typeOfIterator(covariant ir.ForInStatement node) {
+ AbstractValue typeOfIterator(covariant ir.ForInStatement node) {
if (_iteratorMap == null) return null;
return _iteratorMap[node];
}
@override
- void setTypeMask(ir.Node node, TypeMask mask) {
- _sendMap ??= <ir.Node, TypeMask>{};
+ void setTypeMask(ir.Node node, AbstractValue mask) {
+ _sendMap ??= <ir.Node, AbstractValue>{};
_sendMap[node] = mask;
}
@override
- TypeMask typeOfGetter(ir.Node node) {
+ AbstractValue typeOfGetter(ir.Node node) {
if (_sendMap == null) return null;
return _sendMap[node];
}
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 87f76a7..d6482a3 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -7,8 +7,7 @@
import 'dart:collection' show Queue;
import '../elements/entities.dart';
-import '../types/masks.dart'
- show CommonMasks, ContainerTypeMask, MapTypeMask, TypeMask;
+import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show ClosedWorld, ClosedWorldRefiner;
@@ -58,9 +57,10 @@
String get name => 'Graph inferrer';
- CommonMasks get commonMasks => closedWorld.abstractValueDomain;
+ AbstractValueDomain get abstractValueDomain =>
+ closedWorld.abstractValueDomain;
- TypeMask get _dynamicType => commonMasks.dynamicType;
+ AbstractValue get _dynamicType => abstractValueDomain.dynamicType;
void analyzeMain(FunctionEntity main) {
inferrer = createInferrerEngineFor(main);
@@ -70,34 +70,34 @@
InferrerEngine<T> createInferrerEngineFor(FunctionEntity main);
- TypeMask getReturnTypeOfMember(MemberEntity element) {
+ AbstractValue getReturnTypeOfMember(MemberEntity element) {
if (_disableTypeInference) return _dynamicType;
// Currently, closure calls return dynamic.
if (element is! FunctionEntity) return _dynamicType;
return inferrer.types.getInferredTypeOfMember(element).type;
}
- TypeMask getReturnTypeOfParameter(Local element) {
+ AbstractValue getReturnTypeOfParameter(Local element) {
if (_disableTypeInference) return _dynamicType;
return _dynamicType;
}
- TypeMask getTypeOfMember(MemberEntity element) {
+ AbstractValue getTypeOfMember(MemberEntity element) {
if (_disableTypeInference) return _dynamicType;
// The inferrer stores the return type for a function, so we have to
// be careful to not return it here.
- if (element is FunctionEntity) return commonMasks.functionType;
+ if (element is FunctionEntity) return abstractValueDomain.functionType;
return inferrer.types.getInferredTypeOfMember(element).type;
}
- TypeMask getTypeOfParameter(Local element) {
+ AbstractValue getTypeOfParameter(Local element) {
if (_disableTypeInference) return _dynamicType;
// The inferrer stores the return type for a function, so we have to
// be careful to not return it here.
return inferrer.types.getInferredTypeOfParameter(element).type;
}
- TypeMask getTypeForNewList(T node) {
+ AbstractValue getTypeForNewList(T node) {
if (_disableTypeInference) return _dynamicType;
return inferrer.types.allocatedLists[node].type;
}
@@ -108,7 +108,7 @@
return info.checksGrowable;
}
- TypeMask getTypeOfSelector(Selector selector, TypeMask mask) {
+ AbstractValue getTypeOfSelector(Selector selector, AbstractValue receiver) {
if (_disableTypeInference) return _dynamicType;
// Bailout for closure calls. We're not tracking types of
// closures.
@@ -116,30 +116,26 @@
if (selector.isSetter || selector.isIndexSet) {
return _dynamicType;
}
- if (inferrer.returnsListElementType(selector, mask)) {
- ContainerTypeMask containerTypeMask = mask;
- TypeMask elementType = containerTypeMask.elementType;
- return elementType == null ? _dynamicType : elementType;
+ if (inferrer.returnsListElementType(selector, receiver)) {
+ return abstractValueDomain.getContainerElementType(receiver);
}
- if (inferrer.returnsMapValueType(selector, mask)) {
- MapTypeMask mapTypeMask = mask;
- TypeMask valueType = mapTypeMask.valueType;
- return valueType == null ? _dynamicType : valueType;
+ if (inferrer.returnsMapValueType(selector, receiver)) {
+ return abstractValueDomain.getMapValueType(receiver);
}
- TypeMask result = const TypeMask.nonNullEmpty();
- if (inferrer.closedWorld.includesClosureCall(selector, mask)) {
- result = inferrer.commonMasks.dynamicType;
+ if (inferrer.closedWorld.includesClosureCall(selector, receiver)) {
+ return abstractValueDomain.dynamicType;
} else {
Iterable<MemberEntity> elements =
- inferrer.closedWorld.locateMembers(selector, mask);
+ inferrer.closedWorld.locateMembers(selector, receiver);
+ List<AbstractValue> types = <AbstractValue>[];
for (MemberEntity element in elements) {
- TypeMask type =
+ AbstractValue type =
inferrer.typeOfMemberWithSelector(element, selector).type;
- result = result.union(type, inferrer.closedWorld);
+ types.add(type);
}
+ return abstractValueDomain.unionOfMany(types);
}
- return result;
}
Iterable<MemberEntity> getCallersOfForTesting(MemberEntity element) {
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index a6f2a77..cb9971a 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -610,19 +610,19 @@
: super._internal(element);
TypeMask handleSpecialCases(InferrerEngine inferrer) {
- CommonMasks commonMasks = inferrer.commonMasks;
+ CommonMasks abstractValueDomain = inferrer.abstractValueDomain;
if (_constructor.isFromEnvironmentConstructor) {
if (_constructor.enclosingClass == inferrer.commonElements.intClass) {
giveUp(inferrer);
- return commonMasks.intType.nullable();
+ return abstractValueDomain.intType.nullable();
} else if (_constructor.enclosingClass ==
inferrer.commonElements.boolClass) {
giveUp(inferrer);
- return commonMasks.boolType.nullable();
+ return abstractValueDomain.boolType.nullable();
} else if (_constructor.enclosingClass ==
inferrer.commonElements.stringClass) {
giveUp(inferrer);
- return commonMasks.stringType.nullable();
+ return abstractValueDomain.stringType.nullable();
}
}
return _handleFunctionCase(_constructor, inferrer);
@@ -1020,7 +1020,7 @@
TypeMask receiverType = receiver.type;
if (mask != receiverType) {
- return receiverType == inferrer.commonMasks.dynamicType
+ return receiverType == inferrer.abstractValueDomain.dynamicType
? null
: receiverType;
} else {
@@ -1198,7 +1198,7 @@
// for all these targets.
TypeMask result;
if (_hasClosureCallTargets) {
- result = inferrer.commonMasks.dynamicType;
+ result = inferrer.abstractValueDomain.dynamicType;
} else {
result = inferrer.types
.joinTypeMasks(_concreteTargets.map((MemberEntity element) {
diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart
index 9de78ef..4b2849d 100644
--- a/pkg/compiler/lib/src/types/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/types/abstract_value_domain.dart
@@ -230,6 +230,10 @@
/// [b].
AbstractValue union(covariant AbstractValue a, covariant AbstractValue b);
+ /// Returns [AbstractValue] for the runtime values contained in at least one
+ /// of [values].
+ AbstractValue unionOfMany(List<AbstractValue> values);
+
/// Returns [AbstractValue] for the runtime values that [a] and [b] have in
/// common.
AbstractValue intersection(
@@ -243,4 +247,12 @@
/// Computes the [AbstractValue] corresponding to the constant [value].
AbstractValue computeAbstractValueForConstant(ConstantValue value);
+
+ /// Returns the element type of [value] if it represents a container value
+ /// at runtime. Returns [dynamicType] otherwise.
+ AbstractValue getContainerElementType(AbstractValue value);
+
+ /// Returns the value type of [value] if it represents a map value at runtime.
+ /// Returns [dynamicType] otherwise.
+ AbstractValue getMapValueType(AbstractValue value);
}
diff --git a/pkg/compiler/lib/src/types/masks.dart b/pkg/compiler/lib/src/types/masks.dart
index 9f5eb67..7039099 100644
--- a/pkg/compiler/lib/src/types/masks.dart
+++ b/pkg/compiler/lib/src/types/masks.dart
@@ -371,4 +371,29 @@
AbstractValue computeAbstractValueForConstant(ConstantValue value) {
return computeTypeMask(_closedWorld, value);
}
+
+ @override
+ AbstractValue getMapValueType(AbstractValue value) {
+ if (value is MapTypeMask) {
+ return value.valueType ?? dynamicType;
+ }
+ return dynamicType;
+ }
+
+ @override
+ AbstractValue getContainerElementType(AbstractValue value) {
+ if (value is ContainerTypeMask) {
+ return value.elementType ?? dynamicType;
+ }
+ return dynamicType;
+ }
+
+ @override
+ AbstractValue unionOfMany(List<AbstractValue> values) {
+ TypeMask result = const TypeMask.nonNullEmpty();
+ for (TypeMask value in values) {
+ result = result.union(value, _closedWorld);
+ }
+ return result;
+ }
}
diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
index c662f5b..26ad97d 100644
--- a/pkg/compiler/lib/src/types/types.dart
+++ b/pkg/compiler/lib/src/types/types.dart
@@ -11,8 +11,8 @@
import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
import '../universe/selector.dart' show Selector;
import '../world.dart' show ClosedWorld, ClosedWorldRefiner;
+import 'abstract_value_domain.dart';
-import 'masks.dart';
export 'masks.dart';
/// Results about a single element (e.g. a method, parameter, or field)
@@ -31,33 +31,33 @@
/// The inferred type when this result belongs to a parameter or field
/// element, null otherwise.
- TypeMask get type;
+ AbstractValue get type;
/// The inferred return type when this result belongs to a function element.
- TypeMask get returnType;
+ AbstractValue get returnType;
/// Returns the type of a list new expression [node].
- TypeMask typeOfNewList(T node);
+ AbstractValue typeOfNewList(T node);
/// Returns the type of a list literal [node].
- TypeMask typeOfListLiteral(T node);
+ AbstractValue typeOfListLiteral(T node);
/// Returns the type of a send [node].
// TODO(johnniwinther): Rename this.
- TypeMask typeOfSend(T node);
+ AbstractValue typeOfSend(T node);
/// Returns the type of the getter in a complex send-set [node], for example,
/// the type of the `a.f` getter in `a.f += b`.
- TypeMask typeOfGetter(T node);
+ AbstractValue typeOfGetter(T node);
/// Returns the type of the iterator in a [loop].
- TypeMask typeOfIterator(T node);
+ AbstractValue typeOfIterator(T node);
/// Returns the type of the `moveNext` call of an iterator in a [loop].
- TypeMask typeOfIteratorMoveNext(T node);
+ AbstractValue typeOfIteratorMoveNext(T node);
/// Returns the type of the `current` getter of an iterator in a [loop].
- TypeMask typeOfIteratorCurrent(T node);
+ AbstractValue typeOfIteratorCurrent(T node);
}
abstract class GlobalTypeInferenceMemberResult<T>
@@ -78,27 +78,27 @@
// TODO(sigmund): store relevant data & drop reference to inference engine.
final TypesInferrer<T> _inferrer;
final bool _isJsInterop;
- final TypeMask _dynamic;
GlobalTypeInferenceElementResultImpl(
- this._data, this._inferrer, this._isJsInterop, this._dynamic);
+ this._data, this._inferrer, this._isJsInterop);
bool get throwsAlways {
- TypeMask mask = this.returnType;
+ AbstractValue mask = this.returnType;
// Always throws if the return type was inferred to be non-null empty.
- return mask != null && mask.isEmpty;
+ return mask != null && _inferrer.abstractValueDomain.isEmpty(mask);
}
- TypeMask typeOfNewList(T node) => _inferrer.getTypeForNewList(node);
+ AbstractValue typeOfNewList(T node) => _inferrer.getTypeForNewList(node);
- TypeMask typeOfListLiteral(T node) => _inferrer.getTypeForNewList(node);
+ AbstractValue typeOfListLiteral(T node) => _inferrer.getTypeForNewList(node);
- TypeMask typeOfSend(T node) => _data?.typeOfSend(node);
- TypeMask typeOfGetter(T node) => _data?.typeOfGetter(node);
- TypeMask typeOfIterator(T node) => _data?.typeOfIterator(node);
- TypeMask typeOfIteratorMoveNext(T node) =>
+ AbstractValue typeOfSend(T node) => _data?.typeOfSend(node);
+ AbstractValue typeOfGetter(T node) => _data?.typeOfGetter(node);
+ AbstractValue typeOfIterator(T node) => _data?.typeOfIterator(node);
+ AbstractValue typeOfIteratorMoveNext(T node) =>
_data?.typeOfIteratorMoveNext(node);
- TypeMask typeOfIteratorCurrent(T node) => _data?.typeOfIteratorCurrent(node);
+ AbstractValue typeOfIteratorCurrent(T node) =>
+ _data?.typeOfIteratorCurrent(node);
}
class GlobalTypeInferenceMemberResultImpl<T>
@@ -111,17 +111,18 @@
this._owner,
GlobalTypeInferenceElementData data,
TypesInferrer inferrer,
- bool isJsInterop,
- TypeMask _dynamic)
- : super(data, inferrer, isJsInterop, _dynamic);
+ bool isJsInterop)
+ : super(data, inferrer, isJsInterop);
bool get isCalledOnce => _inferrer.isMemberCalledOnce(_owner);
- TypeMask get returnType =>
- _isJsInterop ? _dynamic : _inferrer.getReturnTypeOfMember(_owner);
+ AbstractValue get returnType => _isJsInterop
+ ? _inferrer.abstractValueDomain.dynamicType
+ : _inferrer.getReturnTypeOfMember(_owner);
- TypeMask get type =>
- _isJsInterop ? _dynamic : _inferrer.getTypeOfMember(_owner);
+ AbstractValue get type => _isJsInterop
+ ? _inferrer.abstractValueDomain.dynamicType
+ : _inferrer.getTypeOfMember(_owner);
}
class GlobalTypeInferenceParameterResultImpl<T>
@@ -130,48 +131,50 @@
// TODO(sigmund): delete, store data directly here.
final Local _owner;
- GlobalTypeInferenceParameterResultImpl(
- this._owner, TypesInferrer inferrer, TypeMask _dynamic)
- : super(null, inferrer, false, _dynamic);
+ GlobalTypeInferenceParameterResultImpl(this._owner, TypesInferrer inferrer)
+ : super(null, inferrer, false);
- TypeMask get returnType =>
- _isJsInterop ? _dynamic : _inferrer.getReturnTypeOfParameter(_owner);
+ AbstractValue get returnType => _isJsInterop
+ ? _inferrer.abstractValueDomain.dynamicType
+ : _inferrer.getReturnTypeOfParameter(_owner);
- TypeMask get type =>
- _isJsInterop ? _dynamic : _inferrer.getTypeOfParameter(_owner);
+ AbstractValue get type => _isJsInterop
+ ? _inferrer.abstractValueDomain.dynamicType
+ : _inferrer.getTypeOfParameter(_owner);
}
/// Internal data used during type-inference to store intermediate results about
/// a single element.
abstract class GlobalTypeInferenceElementData<T> {
// TODO(johnniwinther): Remove this. Maybe split by access/invoke.
- TypeMask typeOfSend(T node);
- TypeMask typeOfGetter(T node);
+ AbstractValue typeOfSend(T node);
+ AbstractValue typeOfGetter(T node);
- void setTypeMask(T node, TypeMask mask);
+ void setTypeMask(T node, AbstractValue mask);
- TypeMask typeOfIterator(T node);
+ AbstractValue typeOfIterator(T node);
- TypeMask typeOfIteratorMoveNext(T node);
+ AbstractValue typeOfIteratorMoveNext(T node);
- TypeMask typeOfIteratorCurrent(T node);
+ AbstractValue typeOfIteratorCurrent(T node);
- void setIteratorTypeMask(T node, TypeMask mask);
+ void setIteratorTypeMask(T node, AbstractValue mask);
- void setMoveNextTypeMask(T node, TypeMask mask);
+ void setMoveNextTypeMask(T node, AbstractValue mask);
- void setCurrentTypeMask(T node, TypeMask mask);
+ void setCurrentTypeMask(T node, AbstractValue mask);
}
/// API to interact with the global type-inference engine.
abstract class TypesInferrer<T> {
+ AbstractValueDomain get abstractValueDomain;
void analyzeMain(FunctionEntity element);
- TypeMask getReturnTypeOfMember(MemberEntity element);
- TypeMask getReturnTypeOfParameter(Local element);
- TypeMask getTypeOfMember(MemberEntity element);
- TypeMask getTypeOfParameter(Local element);
- TypeMask getTypeForNewList(T node);
- TypeMask getTypeOfSelector(Selector selector, TypeMask mask);
+ AbstractValue getReturnTypeOfMember(MemberEntity element);
+ AbstractValue getReturnTypeOfParameter(Local element);
+ AbstractValue getTypeOfMember(MemberEntity element);
+ AbstractValue getTypeOfParameter(Local element);
+ AbstractValue getTypeForNewList(T node);
+ AbstractValue getTypeOfSelector(Selector selector, AbstractValue receiver);
void clear();
bool isMemberCalledOnce(MemberEntity element);
bool isFixedArrayCheckedForGrowable(T node);
@@ -226,11 +229,9 @@
parameter, () => createParameterResult(_inferrer, parameter));
}
- TypeMask get dynamicType => closedWorld.abstractValueDomain.dynamicType;
-
/// Returns the type of a [selector] when applied to a receiver with the given
/// type [mask].
- TypeMask typeOfSelector(Selector selector, TypeMask mask) =>
+ AbstractValue typeOfSelector(Selector selector, AbstractValue mask) =>
_inferrer.getTypeOfSelector(selector, mask);
/// Returns whether a fixed-length constructor call goes through a growable