Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Unified Diff: sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart

Issue 17635006: Add a TypeInformation abstraction in the inferrer, that holds information per element, to get rid o… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tests/compiler/dart2js/call_site_simple_type_inferer_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
===================================================================
--- sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart (revision 24382)
+++ sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart (working copy)
@@ -52,17 +52,82 @@
}
/**
- * Placeholder for type information of final fields of classes.
+ * A [TypeInformation] object contains information from the inferrer
+ * on a specific [Element].
*/
-class ClassInfoForFinalFields {
+abstract class TypeInformation {
/**
- * Maps a final field to a map from generative constructor to the
- * inferred type of the field in that generative constructor.
+ * Assignments on the element and the types inferred at
+ * these assignments.
*/
- final Map<Element, Map<Node, TypeMask>> typesOfFinalFields =
- new Map<Element, Map<Node, TypeMask>>();
+ Map<Node, TypeMask> get assignments => null;
/**
+ * Callers of an element.
+ */
+ Set<Element> get callers => null;
+
+ /**
+ * Number of times the element has been processed.
+ */
+ int get analyzeCount => 0;
+ void set analyzeCount(value) {}
+
+ TypeMask get type => null;
+ void set type(value) {}
+
+ TypeMask get returnType => null;
+ void set returnType(value) {}
+
+ void addCaller(Element element) {
+ callers.add(element);
+ }
+
+ void addAssignment(Node node, TypeMask mask) {
+ assignments[node] = mask;
+ }
+
+ void clear();
+}
+
+class FunctionTypeInformation extends TypeInformation {
+ Set<Element> callers = new Set<Element>();
+ TypeMask returnType;
+ int analyzeCount = 0;
+ bool canBeClosurized = false;
+
+ void clear() {
+ callers = null;
+ }
+}
+
+class ParameterTypeInformation extends TypeInformation {
+ Map<Node, TypeMask> assignments = new Map<Node, TypeMask>();
+ TypeMask type;
+ TypeMask defaultType;
+
+ void clear() {
+ assignments = null;
+ }
+}
+
+class FieldTypeInformation extends TypeInformation {
+ TypeMask type;
+ Set<Element> callers = new Set<Element>();
+ Map<Node, TypeMask> assignments = new Map<Node, TypeMask>();
+ int analyzeCount = 0;
+
+ void clear() {
+ assignments = null;
+ callers = null;
+ }
+}
+
+/**
+ * A class for knowing when can we compute a type for final fields.
+ */
+class ClassTypeInformation {
+ /**
* The number of generative constructors that need to be visited
* before we can take any decision on the type of the fields.
* Given that all generative constructors must be analyzed before
@@ -71,22 +136,9 @@
*/
int constructorsToVisitCount;
- ClassInfoForFinalFields(this.constructorsToVisitCount);
+ ClassTypeInformation(this.constructorsToVisitCount);
/**
- * Records that the generative [constructor] has inferred [type]
- * for the final [field].
- */
- void recordFinalFieldType(Node node,
- Element constructor,
- Element field,
- TypeMask type) {
- Map<Node, TypeMask> typesFor = typesOfFinalFields.putIfAbsent(
- field, () => new Map<Node, TypeMask>());
- typesFor[node] = type;
- }
-
- /**
* Records that [constructor] has been analyzed. If not at 0,
* decrement [constructorsToVisitCount].
*/
@@ -145,13 +197,9 @@
if (compiler.disableTypeInference) return dynamicType;
return internal.getTypeOfSelector(selector);
}
-
Iterable<Element> getCallersOf(Element element) {
if (compiler.disableTypeInference) throw "Don't use me";
- Iterable<Element> result = internal.callersOf[element.implementation];
- return result == null
- ? internal.callersOf[element] = const <Element>[]
- : result;
+ return internal.getCallersOf(element.implementation);
}
bool analyzeMain(Element element) {
@@ -172,67 +220,25 @@
class InternalSimpleTypesInferrer extends TypesInferrer {
/**
- * Maps a node to its type. Currently used for computing element
- * types of lists.
+ * Maps a class to a [ClassTypeInformation] to help collect type
+ * information of final fields.
*/
- final Map<Node, TypeMask> concreteTypes = new Map<Node, TypeMask>();
+ Map<ClassElement, ClassTypeInformation> classInfoForFinalFields =
+ new Map<ClassElement, ClassTypeInformation>();
/**
- * Maps an element to its callers.
+ * Maps an element to its corresponding [TypeInformation].
*/
- final Map<Element, Iterable<Element>> callersOf =
- new Map<Element, Iterable<Element>>();
+ final Map<Element, TypeInformation> typeInfo =
+ new Map<Element, TypeInformation>();
/**
- * Maps an element to its return type.
+ * Maps a node to its type. Currently used for computing element
+ * types of lists.
*/
- final Map<Element, TypeMask> returnTypeOf =
- new Map<Element, TypeMask>();
+ final Map<Node, TypeMask> concreteTypes = new Map<Node, TypeMask>();
/**
- * Maps an element to its type.
- */
- final Map<Element, TypeMask> typeOf = new Map<Element, TypeMask>();
-
- /**
- * Maps an element to its assignments and the types inferred at
- * these assignments.
- */
- final Map<Element, Map<Node, TypeMask>> typeOfFields =
- new Map<Element, Map<Node, TypeMask>>();
-
- /**
- * Maps an element to the type of its parameters at call sites.
- */
- final Map<Element, Map<Node, ArgumentsTypes>> typeOfArguments =
- new Map<Element, Map<Node, ArgumentsTypes>>();
-
- /**
- * Maps an optional parameter to its default type.
- */
- final Map<Element, TypeMask> defaultTypeOfParameter =
- new Map<Element, TypeMask>();
-
- /**
- * Set of methods that the inferrer found could be closurized. We
- * don't compute parameter types for such methods.
- */
- final Set<Element> methodsThatCanBeClosurized = new Set<Element>();
-
- /**
- * Maps an element to the number of times this type inferrer
- * analyzed it.
- */
- final Map<Element, int> analyzeCount = new Map<Element, int>();
-
- /**
- * Maps a class to a [ClassInfoForFinalFields] to help collect type
- * information of final fields.
- */
- final Map<ClassElement, ClassInfoForFinalFields> classInfoForFinalFields =
- new Map<ClassElement, ClassInfoForFinalFields>();
-
- /**
* A map of constraints on a setter. When computing the type
* of a field, these [Node] are initially discarded, and once the
* type is computed, we make sure these constraints are satisfied
@@ -247,12 +253,12 @@
* returns that type.
*
*/
- final Map<Node, CallSite> setterConstraints = new Map<Node, CallSite>();
+ Map<Node, CallSite> setterConstraints = new Map<Node, CallSite>();
/**
* The work list of the inferrer.
*/
- final WorkSet<Element> workSet = new WorkSet<Element>();
+ WorkSet<Element> workSet = new WorkSet<Element>();
/**
* Heuristic for avoiding too many re-analysis of an element.
@@ -320,6 +326,11 @@
*/
int numberOfElementsToAnalyze;
+ /**
+ * The number of analysis already done.
+ */
+ int analyzed = 0;
+
InternalSimpleTypesInferrer(this.compiler, this.optimismState);
/**
@@ -328,7 +339,6 @@
*/
bool analyzeMain(Element element) {
buildWorkQueue();
- int analyzed = 0;
compiler.progress.reset();
int maxReanalysis = (numberOfElementsToAnalyze * 1.5).toInt();
do {
@@ -339,7 +349,7 @@
element = workSet.remove();
if (element.isErroneous()) continue;
- bool wasAnalyzed = analyzeCount.containsKey(element);
+ bool wasAnalyzed = typeInformationOf(element).analyzeCount != 0;
if (wasAnalyzed) {
recompiles++;
if (recompiles >= maxReanalysis) {
@@ -366,15 +376,28 @@
return true;
}
+ TypeInformation typeInformationOf(Element element) {
+ return typeInfo.putIfAbsent(element, () {
+ if (element.isParameter() || element.isFieldParameter()) {
+ return new ParameterTypeInformation();
+ } else if (element.isField() || element.isVariable()) {
+ return new FieldTypeInformation();
+ } else {
+ assert(element is FunctionElement);
+ return new FunctionTypeInformation();
+ }
+ });
+ }
+
/**
* Query method after the analysis to know the type of [element].
*/
TypeMask getReturnTypeOfElement(Element element) {
- return getNonNullType(returnTypeOf[element]);
+ return getNonNullType(typeInformationOf(element).returnType);
}
TypeMask getTypeOfElement(Element element) {
- return getNonNullType(typeOf[element]);
+ return getNonNullType(typeInformationOf(element).type);
}
TypeMask getTypeOfSelector(Selector selector) {
@@ -389,6 +412,10 @@
return returnType != null ? returnType : dynamicType;
}
+ Iterable<Element> getCallersOf(Element element) {
+ return typeInformationOf(element).callers;
+ }
+
/**
* Query method after the analysis to know the type of [node],
* defined in the context of [owner].
@@ -399,29 +426,39 @@
void checkAnalyzedAll() {
if (hasAnalyzedAll) return;
- if (analyzeCount.length != numberOfElementsToAnalyze) return;
+ if (analyzed < numberOfElementsToAnalyze) return;
hasAnalyzedAll = true;
+
// If we have analyzed all the world, we know all assigments to
- // fields and can therefore infer a type for them.
- typeOfFields.keys.forEach(updateNonFinalFieldType);
- // We also know all calls to methods.
- typeOfArguments.keys.forEach(updateArgumentsType);
+ // fields and parameters, and can therefore infer a type for them.
+ typeInfo.forEach((element, TypeInformation info) {
+ if (element.isParameter() || element.isFieldParameter()) {
+ if (updateParameterType(element)) {
+ enqueueAgain(element.enclosingElement);
+ }
+ } else if (element.isField()
+ && !(element.modifiers.isFinal()
+ || element.modifiers.isConst())) {
+ updateNonFinalFieldType(element);
+ } else if (element.isVariable()) {
+ updateNonFinalFieldType(element);
+ }
+ });
}
/**
* Enqueues [e] in the work queue if it is valuable.
*/
void enqueueAgain(Element e) {
- int count = analyzeCount[e];
+ assert(isNotClosure(e));
+ int count = typeInformationOf(e).analyzeCount;
if (count != null && count > MAX_ANALYSIS_COUNT_PER_ELEMENT) return;
workSet.add(e);
}
void enqueueCallersOf(Element element) {
- Set<Element> methodCallers = callersOf[element];
- if (methodCallers != null) {
- methodCallers.forEach(enqueueAgain);
- }
+ assert(isNotClosure(element));
+ typeInformationOf(element).callers.forEach(enqueueAgain);
}
/**
@@ -454,7 +491,9 @@
// Optimistically assume that they return bool. We may need to back
// out of this.
if (optimismState == OPTIMISTIC) {
- returnTypeOf[element.implementation] = boolType;
+ FunctionTypeInformation info =
+ typeInformationOf(element.implementation);
+ info.returnType = boolType;
}
} else {
// Put the other operators in buckets by length, later to be added in
@@ -491,7 +530,7 @@
}
});
classInfoForFinalFields[cls.implementation] =
- new ClassInfoForFinalFields(constructorCount);
+ new ClassTypeInformation(constructorCount);
});
}
@@ -505,13 +544,15 @@
dump() {
int interestingTypes = 0;
- returnTypeOf.forEach((Element element, TypeMask type) {
- if (type != nullType && !isDynamicType(type)) {
+ typeInfo.forEach((element, TypeInformation info) {
+ TypeMask type = info.type;
+ TypeMask returnType = info.returnType;
+ if (type != null && type != nullType && !isDynamicType(type)) {
interestingTypes++;
}
- });
- typeOf.forEach((Element element, TypeMask type) {
- if (type != nullType && !isDynamicType(type)) {
+ if (returnType != null
+ && returnType != nullType
+ && !isDynamicType(returnType)) {
interestingTypes++;
}
});
@@ -526,11 +567,10 @@
* Clear data structures that are not used after the analysis.
*/
void clear() {
- callersOf.clear();
- analyzeCount.clear();
- classInfoForFinalFields.clear();
- typeOfFields.clear();
- setterConstraints.clear();
+ classInfoForFinalFields = null;
+ setterConstraints = null;
+ workSet = null;
+ typeInfo.forEach((_, info) { info.clear(); });
}
bool analyze(Element element) {
@@ -540,11 +580,7 @@
SimpleTypeInferrerVisitor visitor =
new SimpleTypeInferrerVisitor(element, compiler, this);
TypeMask returnType = visitor.run();
- if (analyzeCount.containsKey(element)) {
- analyzeCount[element]++;
- } else {
- analyzeCount[element] = 1;
- }
+ typeInformationOf(element).analyzeCount++;
if (element.isGenerativeConstructor()) {
// We always know the return type of a generative constructor.
return false; // Nothing changed.
@@ -576,11 +612,18 @@
}
bool recordType(Element analyzedElement, TypeMask type) {
+ if (isNativeElement(analyzedElement)) return false;
assert(type != null);
assert(analyzedElement.isField()
|| analyzedElement.isParameter()
|| analyzedElement.isFieldParameter());
- return internalRecordType(analyzedElement, type, typeOf);
+ TypeMask newType = checkTypeAnnotation(analyzedElement, type);
+ TypeMask existing = typeInformationOf(analyzedElement).type;
+ typeInformationOf(analyzedElement).type = newType;
+ // If the type is useful, say it has changed.
+ return existing != newType
+ && !isDynamicType(newType)
+ && newType != nullType;
}
/**
@@ -589,15 +632,23 @@
* [analyzedElement].
*/
bool recordReturnType(Element analyzedElement, TypeMask returnType) {
+ if (isNativeElement(analyzedElement)) return false;
assert(analyzedElement.implementation == analyzedElement);
+ TypeMask existing = typeInformationOf(analyzedElement).returnType;
if (optimismState == OPTIMISTIC
&& shouldOptimisticallyOptimizeToBool(analyzedElement)
- && returnType != returnTypeOf[analyzedElement]) {
+ && returnType != existing) {
// One of the functions turned out not to return what we expected.
// This means we need to restart the analysis.
optimismState = RETRY;
}
- return internalRecordType(analyzedElement, returnType, returnTypeOf);
+ TypeMask newType = checkTypeAnnotation(analyzedElement, returnType);
+ FunctionTypeInformation info = typeInformationOf(analyzedElement);
+ info.returnType = newType;
+ // If the return type is useful, say it has changed.
+ return existing != newType
+ && !isDynamicType(newType)
+ && newType != nullType;
}
bool isNativeElement(Element element) {
@@ -607,43 +658,32 @@
&& element.isField();
}
- bool internalRecordType(Element analyzedElement,
- TypeMask newType,
- Map<Element, TypeMask> types) {
+ TypeMask checkTypeAnnotation(Element analyzedElement, TypeMask newType) {
if (compiler.trustTypeAnnotations
// Parameters are being checked by the method, and we can
// therefore only trust their type after the checks.
|| (compiler.enableTypeAssertions && !analyzedElement.isParameter())) {
var annotation = analyzedElement.computeType(compiler);
- if (types == returnTypeOf) {
+ if (analyzedElement.isGetter()
+ || analyzedElement.isFunction()
+ || analyzedElement.isConstructor()
+ || analyzedElement.isSetter()) {
assert(annotation is FunctionType);
annotation = annotation.returnType;
}
newType = narrowType(newType, annotation, compiler);
}
-
- // Fields and native methods of native classes are handled
- // specially when querying for their type or return type.
- if (isNativeElement(analyzedElement)) return false;
- assert(newType != null);
- TypeMask existing = types[analyzedElement];
- types[analyzedElement] = newType;
- // If the return type is useful, say it has changed.
- return existing != newType
- && !isDynamicType(newType)
- && newType != nullType;
+ return newType;
}
TypeMask fetchReturnType(Element element) {
- return returnTypeOf[element] is ElementTypeMask
- ? dynamicType
- : returnTypeOf[element];
+ TypeMask returnType = typeInformationOf(element).returnType;
+ return returnType is ElementTypeMask ? dynamicType : returnType;
}
TypeMask fetchType(Element element) {
- return typeOf[element] is ElementTypeMask
- ? dynamicType
- : typeOf[element];
+ TypeMask type = typeInformationOf(element).type;
+ return type is ElementTypeMask ? dynamicType : type;
}
/**
@@ -652,22 +692,25 @@
*/
TypeMask returnTypeOfElement(Element element) {
element = element.implementation;
+ TypeInformation info = typeInformationOf(element);
if (element.isGenerativeConstructor()) {
- return returnTypeOf.putIfAbsent(element, () {
- return new TypeMask.nonNullExact(
- rawTypeOf(element.getEnclosingClass()));
- });
+ return info.returnType == null
+ ? info.returnType = new TypeMask.nonNullExact(
+ rawTypeOf(element.getEnclosingClass()))
+ : info.returnType;
} else if (element.isNative()) {
- return returnTypeOf.putIfAbsent(element, () {
+ if (info.returnType == null) {
var elementType = element.computeType(compiler);
if (elementType.kind != TypeKind.FUNCTION) {
- return dynamicType;
+ info.returnType = dynamicType;
+ } else {
+ info.returnType = typeOfNativeBehavior(
+ native.NativeBehavior.ofMethod(element, compiler));
}
- return typeOfNativeBehavior(
- native.NativeBehavior.ofMethod(element, compiler));
- });
+ }
+ return info.returnType;
}
- TypeMask returnType = returnTypeOf[element];
+ TypeMask returnType = info.returnType;
if (returnType == null) {
if ((compiler.trustTypeAnnotations || compiler.enableTypeAssertions)
&& (element.isFunction()
@@ -676,7 +719,7 @@
FunctionType functionType = element.computeType(compiler);
returnType = narrowType(dynamicType, functionType.returnType, compiler);
} else {
- returnType = returnTypeOf[element] =
+ returnType = info.returnType =
new ElementTypeMask(fetchReturnType, element);
}
}
@@ -736,15 +779,18 @@
*/
TypeMask typeOfElement(Element element) {
element = element.implementation;
+ TypeInformation info = typeInformationOf(element);
+ TypeMask type = info.type;
if (isNativeElement(element) && element.isField()) {
- var type = typeOf.putIfAbsent(element, () {
+ if (type == null) {
InterfaceType rawType = element.computeType(compiler).asRaw();
- return rawType.isDynamic ? dynamicType : new TypeMask.subtype(rawType);
- });
+ info.type = type = rawType.isDynamic
+ ? dynamicType
+ : new TypeMask.subtype(rawType);
+ }
assert(type != null);
return type;
}
- TypeMask type = typeOf[element];
if (type == null) {
if ((compiler.trustTypeAnnotations
&& (element.isField()
@@ -756,7 +802,7 @@
&& (element.isField() || element.isVariable()))) {
type = narrowType(dynamicType, element.computeType(compiler), compiler);
} else {
- type = typeOf[element] = new ElementTypeMask(fetchType, element);
+ type = info.type = new ElementTypeMask(fetchType, element);
}
}
return type;
@@ -808,9 +854,8 @@
ContainerTypeMask mask = selector.mask;
TypeMask elementType = mask.elementType;
return elementType == null ? dynamicType : elementType;
- } else if (element.isGetter()) {
- // Closure call.
- assert(selector.isCall());
+ } else if (element.isGetter() || element.isField()) {
+ assert(selector.isCall() || selector.isSetter());
return dynamicType;
} else {
return returnTypeOfElement(element);
@@ -828,19 +873,76 @@
assert(caller.isImplementation);
assert(callee.isImplementation);
assert(isNotClosure(caller));
- Set<Element> callers = callersOf.putIfAbsent(
- callee, () => new Set<Element>());
+ Set<Element> callers = typeInformationOf(callee).callers;
callers.add(caller);
}
- bool addArguments(Node node, Element element, ArgumentsTypes arguments) {
- Map<Node, ArgumentsTypes> types = typeOfArguments.putIfAbsent(
- element, () => new Map<Node, ArgumentsTypes>());
- ArgumentsTypes existing = types[node];
- types[node] = arguments;
- return existing != arguments;
+ bool addArguments(Node node,
+ FunctionElement element,
+ ArgumentsTypes arguments) {
+ FunctionTypeInformation info = typeInformationOf(element);
+ if (info.canBeClosurized) return false;
+ // A [noSuchMethod] method can be the target of any call, with
+ // any number of arguments. For simplicity, we just do not
+ // infer any parameter types for [noSuchMethod].
+ if (element.name == Compiler.NO_SUCH_METHOD) return false;
+
+ FunctionSignature signature = element.computeSignature(compiler);
+ int parameterIndex = 0;
+ bool changed = false;
+ bool visitingOptionalParameter = false;
+ signature.forEachParameter((Element parameter) {
+ if (parameter == signature.firstOptionalParameter) {
+ visitingOptionalParameter = true;
+ }
+ TypeMask type;
+ ParameterTypeInformation info = typeInformationOf(parameter);
+ if (!visitingOptionalParameter) {
+ type = arguments.positional[parameterIndex];
+ } else {
+ type = signature.optionalParametersAreNamed
+ ? arguments.named[parameter.name]
+ : parameterIndex < arguments.positional.length
+ ? arguments.positional[parameterIndex]
+ : info.defaultType;
+ }
+ TypeMask oldType = info.assignments[node];
+ info.addAssignment(node, type);
+ changed = changed || (oldType != type);
+ parameterIndex++;
+ });
+ return changed;
}
+ bool updateParameterType(Element parameter) {
+ FunctionTypeInformation functionInfo =
+ typeInformationOf(parameter.enclosingElement);
+ if (functionInfo.canBeClosurized) return false;
+ if (!isNotClosure(parameter.enclosingElement)) return false;
+
+ ParameterTypeInformation info = typeInformationOf(parameter);
+ TypeMask elementType;
+ info.assignments.forEach((Node node, TypeMask mask) {
+ if (mask == null) {
+ // Now that we know we have analyzed the function holding
+ // [parameter], we have a default type for that [parameter].
+ mask = info.defaultType;
+ info.addAssignment(node, mask);
+ }
+ elementType = computeLubFor(elementType, mask, parameter);
+ });
+ if (elementType == null) {
+ elementType = dynamicType;
+ }
+ return recordType(parameter, elementType);
+ }
+
+ void updateAllParametersOf(FunctionElement function) {
+ function.computeSignature(compiler).forEachParameter((Element parameter) {
+ updateParameterType(parameter);
+ });
+ }
+
void updateSideEffects(SideEffects sideEffects,
Selector selector,
Element callee) {
@@ -907,9 +1009,8 @@
assert(isNotClosure(caller));
callee = callee.implementation;
- if (!analyzeCount.containsKey(caller)) {
- addCaller(caller, callee);
- }
+ TypeInformation info = typeInformationOf(callee);
+ info.addCaller(caller);
if (selector.isSetter() && callee.isField()) {
recordNonFinalFieldElementType(
@@ -921,7 +1022,8 @@
} else if (selector.isGetter()) {
assert(arguments == null);
if (callee.isFunction()) {
- methodsThatCanBeClosurized.add(callee);
+ FunctionTypeInformation functionInfo = info;
+ functionInfo.canBeClosurized = true;
}
return;
} else if (callee.isField()) {
@@ -947,18 +1049,22 @@
Element callee) {
if (callee.isField()) {
if (selector.isSetter()) {
- Map<Node, TypeMask> types = typeOfFields[callee];
- if (types == null || !types.containsKey(node)) return;
- types.remove(node);
+ Map<Node, TypeMask> assignments = typeInformationOf(callee).assignments;
+ if (assignments == null || !assignments.containsKey(node)) return;
+ assignments.remove(node);
if (hasAnalyzedAll) updateNonFinalFieldType(callee);
}
} else if (callee.isGetter()) {
return;
} else {
- Map<Node, ArgumentsTypes> types = typeOfArguments[callee];
- if (types == null || !types.containsKey(node)) return;
- types.remove(node);
- if (hasAnalyzedAll) enqueueAgain(callee);
+ FunctionElement element = callee;
+ element.computeSignature(compiler).forEachParameter((Element parameter) {
+ Map<Node, TypeMask> assignments =
+ typeInformationOf(parameter).assignments;
+ if (assignments == null || !assignments.containsKey(node)) return;
+ assignments.remove(node);
+ if (hasAnalyzedAll) enqueueAgain(callee);
+ });
}
}
@@ -976,62 +1082,6 @@
return computeLUB(firstType, secondType, compiler);
}
- /**
- * Computes the parameter types of [element], based on all call sites we
- * have collected on that [element]. This method can only be called after
- * we have analyzed all elements in the world.
- */
- void updateArgumentsType(FunctionElement element) {
- assert(hasAnalyzedAll);
- if (methodsThatCanBeClosurized.contains(element)) return;
- // A [noSuchMethod] method can be the target of any call, with
- // any number of arguments. For simplicity, we just do not
- // infer any parameter types for [noSuchMethod].
- if (element.name == Compiler.NO_SUCH_METHOD) return;
- FunctionSignature signature = element.computeSignature(compiler);
-
- if (typeOfArguments[element] == null || typeOfArguments[element].isEmpty) {
- signature.forEachParameter((Element parameter) {
- typeOf.remove(parameter);
- });
- return;
- }
-
- int parameterIndex = 0;
- bool changed = false;
- bool visitingOptionalParameter = false;
- signature.forEachParameter((Element parameter) {
- if (parameter == signature.firstOptionalParameter) {
- visitingOptionalParameter = true;
- }
- TypeMask type;
- typeOfArguments[element].forEach((_, ArgumentsTypes arguments) {
- if (!visitingOptionalParameter) {
- type = computeLubFor(
- type, arguments.positional[parameterIndex], parameter);
- } else {
- TypeMask argumentType = signature.optionalParametersAreNamed
- ? arguments.named[parameter.name]
- : parameterIndex < arguments.positional.length
- ? arguments.positional[parameterIndex]
- : null;
- if (argumentType == null) {
- argumentType = defaultTypeOfParameter[parameter];
- }
- assert(argumentType != null);
- type = computeLubFor(type, argumentType, parameter);
- }
- });
- if (type == null) type = new TypeMask.nonNullEmpty();
- if (recordType(parameter, type)) {
- changed = true;
- }
- parameterIndex++;
- });
-
- if (changed) enqueueAgain(element);
- }
-
TypeMask handleIntrisifiedSelector(Selector selector,
ArgumentsTypes arguments) {
if (selector.mask != intType) return null;
@@ -1116,10 +1166,9 @@
Element element,
TypeMask argumentType,
CallSite constraint) {
- Map<Node, TypeMask> map =
- typeOfFields.putIfAbsent(element, () => new Map<Node, TypeMask>());
- map[node] = argumentType;
- bool changed = typeOf[element] != argumentType;
+ TypeInformation info = typeInformationOf(element);
+ info.addAssignment(node, argumentType);
+ bool changed = info.type != argumentType;
if (constraint != null && constraint != setterConstraints[node]) {
changed = true;
setterConstraints[node] = constraint;
@@ -1131,9 +1180,10 @@
}
}
- TypeMask computeFieldTypeWithConstraints(Element element, Map types) {
+ TypeMask computeTypeWithConstraints(Element element,
+ Map<Node, TypeMask> types) {
List<CallSite> constraints = <CallSite>[];
- TypeMask fieldType;
+ TypeMask elementType;
types.forEach((Node node, TypeMask mask) {
CallSite constraint = setterConstraints[node];
if (constraint != null) {
@@ -1141,17 +1191,18 @@
// use its type.
constraints.add(constraint);
} else {
- fieldType = computeLubFor(fieldType, mask, element);
+ elementType = computeLubFor(elementType, mask, element);
}
});
- if (!constraints.isEmpty && !isDynamicType(fieldType)) {
+ if (!constraints.isEmpty && !isDynamicType(elementType)) {
// Now that we have found a type, we go over the collected
// constraints, and make sure they apply to the found type. We
// update [typeOf] to make sure [typeOfSelector] knows the field
// type.
- TypeMask existing = typeOf[element];
- typeOf[element] = fieldType;
+ TypeInformation info = typeInformationOf(element);
+ TypeMask existing = info.type;
+ info.type = elementType;
for (CallSite constraint in constraints) {
Selector selector = constraint.selector;
@@ -1159,8 +1210,8 @@
if (selector.isOperator()) {
// If the constraint is on an operator, we type the receiver
// to be the field.
- if (fieldType != null) {
- selector = new TypedSelector(fieldType, selector);
+ if (elementType != null) {
+ selector = new TypedSelector(elementType, selector);
}
type = handleIntrisifiedSelector(selector, constraint.arguments);
if (type == null) type = typeOfSelector(selector);
@@ -1169,18 +1220,14 @@
assert(selector.isGetter());
type = typeOfSelector(selector);
}
- fieldType = computeLUB(fieldType, type, compiler);
+ elementType = computeLUB(elementType, type, compiler);
}
- if (existing == null) {
- typeOf.remove(element);
- } else {
- typeOf[element] = existing;
- }
+ info.type = existing;
}
- if (fieldType == null) {
- fieldType = new TypeMask.nonNullEmpty();
+ if (elementType == null) {
+ elementType = new TypeMask.nonNullEmpty();
}
- return fieldType;
+ return elementType;
}
/**
@@ -1192,13 +1239,11 @@
if (isNativeElement(element)) return;
assert(hasAnalyzedAll);
- if (typeOfFields[element] == null || typeOfFields[element].isEmpty) {
- typeOf.remove(element);
- return;
- }
+ TypeInformation info = typeInformationOf(element);
+ Map<Node, TypeMask> assignments = info.assignments;
+ if (assignments.isEmpty) return;
- TypeMask fieldType = computeFieldTypeWithConstraints(
- element, typeOfFields[element]);
+ TypeMask fieldType = computeTypeWithConstraints(element, assignments);
// If the type of [element] has changed, re-analyze its users.
if (recordType(element, fieldType)) {
@@ -1222,9 +1267,8 @@
// being tracked in the [classInfoForFinalFields] map.
if (constructor == field) return;
assert(field.modifiers.isFinal() || field.modifiers.isConst());
- ClassElement cls = constructor.getEnclosingClass();
- ClassInfoForFinalFields info = classInfoForFinalFields[cls.implementation];
- info.recordFinalFieldType(node, constructor, field, type);
+ TypeInformation info = typeInformationOf(field);
+ info.addAssignment(node, type);
}
/**
@@ -1234,23 +1278,26 @@
*/
void doneAnalyzingGenerativeConstructor(Element constructor) {
ClassElement cls = constructor.getEnclosingClass();
- ClassInfoForFinalFields info = classInfoForFinalFields[cls.implementation];
+ ClassTypeInformation info = classInfoForFinalFields[cls.implementation];
info.doneAnalyzingGenerativeConstructor(constructor);
if (info.isDone) {
- updateFinalFieldsType(info);
+ updateFinalFieldsType(info, constructor.getEnclosingClass());
}
}
/**
* Updates types of final fields listed in [info].
*/
- void updateFinalFieldsType(ClassInfoForFinalFields info) {
+ void updateFinalFieldsType(ClassTypeInformation info, ClassElement cls) {
assert(info.isDone);
- info.typesOfFinalFields.forEach((Element field,
- Map<Node, TypeMask> types) {
+ cls.forEachInstanceField((_, Element field) {
if (isNativeElement(field)) return;
- assert(field.modifiers.isFinal());
- TypeMask fieldType = computeFieldTypeWithConstraints(field, types);
+ if (!field.modifiers.isFinal()) return;
+ // If the field is being set at its declaration site, it is not
+ // being tracked in the [classInfoForFinalFields] map.
+ if (field.parseNode(compiler).asSendSet() != null) return;
+ TypeInformation info = typeInformationOf(field);
+ TypeMask fieldType = computeTypeWithConstraints(field, info.assignments);
if (recordType(field, fieldType)) {
enqueueCallersOf(field);
}
@@ -1349,16 +1396,16 @@
FunctionElement function = analyzedElement;
if (inferrer.hasAnalyzedAll) {
- inferrer.updateArgumentsType(function);
+ inferrer.updateAllParametersOf(function);
}
FunctionSignature signature = function.computeSignature(compiler);
signature.forEachOptionalParameter((element) {
Node node = element.parseNode(compiler);
Send send = node.asSendSet();
- inferrer.defaultTypeOfParameter[element] = (send == null)
+ ParameterTypeInformation info = inferrer.typeInformationOf(element);
+ info.defaultType = (send == null)
? inferrer.nullType
: visit(send.arguments.head);
- assert(inferrer.defaultTypeOfParameter[element] != null);
});
if (analyzedElement.isNative()) {
« no previous file with comments | « no previous file | tests/compiler/dart2js/call_site_simple_type_inferer_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698