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

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

Issue 11414130: Naive handling of List#[] and List#[]= (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Sync to head Created 7 years, 11 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 | sdk/lib/_internal/compiler/implementation/types/types.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/concrete_types_inferrer.dart
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
index fae1650fc2fe17e7620f15ff32bf256a8411c612..ee7845c2580009050ea00cd9e4c2fa074dad9208 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -277,15 +277,21 @@ class ConcreteTypeCartesianProductIterator
* [BaseType] Constants.
*/
class BaseTypes {
- final BaseType intBaseType;
- final BaseType doubleBaseType;
- final BaseType numBaseType;
- final BaseType boolBaseType;
- final BaseType stringBaseType;
- final BaseType listBaseType;
- final BaseType mapBaseType;
- final BaseType objectBaseType;
- final BaseType typeBaseType;
+ final ClassBaseType intBaseType;
+ final ClassBaseType doubleBaseType;
+ final ClassBaseType numBaseType;
+ final ClassBaseType boolBaseType;
+ final ClassBaseType stringBaseType;
+ final ClassBaseType listBaseType;
+ final ClassBaseType mapBaseType;
+ final ClassBaseType objectBaseType;
+ final ClassBaseType typeBaseType;
+
+ static _getNativeListClass(Compiler compiler) {
+ // TODO(polux): switch to other implementations on other backends
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsArrayClass;
+ }
BaseTypes(Compiler compiler) :
intBaseType = new ClassBaseType(compiler.intClass),
@@ -293,7 +299,8 @@ class BaseTypes {
numBaseType = new ClassBaseType(compiler.numClass),
boolBaseType = new ClassBaseType(compiler.boolClass),
stringBaseType = new ClassBaseType(compiler.stringClass),
- listBaseType = new ClassBaseType(compiler.listClass),
+ // in the Javascript backend, lists are implemented by JsArray
+ listBaseType = new ClassBaseType(_getNativeListClass(compiler)),
mapBaseType = new ClassBaseType(compiler.mapClass),
objectBaseType = new ClassBaseType(compiler.objectClass),
typeBaseType = new ClassBaseType(compiler.typeClass);
@@ -392,7 +399,7 @@ class ConcreteTypesInferrer {
final Compiler compiler;
/**
- * When true, the string litteral [:"__dynamic_for_test":] is inferred to
+ * When true, the string literal [:"__dynamic_for_test":] is inferred to
* have the unknown type.
*/
// TODO(polux): get rid of this hack once we have a natural way of inferring
@@ -400,13 +407,30 @@ class ConcreteTypesInferrer {
bool testMode = false;
/**
- * Constants representing builtin base types. Initialized in [analyzeMain]
+ * Constants representing builtin base types. Initialized in [initialize]
* and not in the constructor because the compiler elements are not yet
* populated.
*/
BaseTypes baseTypes;
/**
+ * Constant representing [:ConcreteList#[]:] where [:ConcreteList:] is the
+ * concrete implmentation of lists for the selected backend.
+ */
+ FunctionElement listIndex;
+
+ /**
+ * Constant representing [:ConcreteList#[]=:] where [:ConcreteList:] is the
+ * concrete implmentation of lists for the selected backend.
+ */
+ FunctionElement listIndexSet;
+
+ /**
+ * Constant representing [:List():].
+ */
+ FunctionElement listConstructor;
+
+ /**
* A cache from (function x argument base types) to concrete types,
* used to memoize [analyzeMonoSend]. Another way of seeing [cache] is as a
* map from [FunctionElement]s to "templates" in the sense of "The Cartesian
@@ -430,6 +454,9 @@ class ConcreteTypesInferrer {
/** [: readers[field] :] is the list of [: field :]'s possible readers. */
final Map<Element, Set<FunctionElement>> readers;
+ /** The inferred type of elements stored in Lists. */
+ ConcreteType listElementType;
+
/**
* A map from parameters to their inferred concrete types. It plays no role
* in the analysis, it is write only.
@@ -445,7 +472,8 @@ class ConcreteTypesInferrer {
inferredParameterTypes = new Map<VariableElement, ConcreteType>(),
workQueue = new Queue<InferenceWorkItem>(),
callers = new Map<FunctionElement, Set<FunctionElement>>(),
- readers = new Map<Element, Set<FunctionElement>>() {
+ readers = new Map<Element, Set<FunctionElement>>(),
+ listElementType = new ConcreteType.empty() {
unknownConcreteType = new ConcreteType.unknown();
emptyConcreteType = new ConcreteType.empty();
}
@@ -533,7 +561,7 @@ class ConcreteTypesInferrer {
* Returns all the members with name [methodName].
*/
List<Element> getMembersByName(SourceString methodName) {
- // TODO(polux): make this faster!
+ // TODO(polux): memoize?
var result = new List<Element>();
for (ClassElement cls in compiler.enqueuer.resolution.seenClasses) {
Element elem = cls.lookupLocalMember(methodName);
@@ -588,6 +616,15 @@ class ConcreteTypesInferrer {
}
}
+ /// Augment the inferred type of elements stored in Lists.
+ void augmentListElementType(ConcreteType type) {
+ ConcreteType newType = union(listElementType, type);
+ if (newType != listElementType) {
+ invalidateCallers(listIndex);
+ listElementType = newType;
+ }
+ }
+
/**
* Sets the concrete type associated to [parameter] to the union of the
* inferred concrete type so far and [type].
@@ -626,6 +663,24 @@ class ConcreteTypesInferrer {
}
}
+ /**
+ * Add callers of [function] to the workqueue.
+ */
+ void invalidateCallers(FunctionElement function) {
+ Set<FunctionElement> methodCallers = callers[function];
+ if (methodCallers == null) return;
+ for (FunctionElement caller in methodCallers) {
+ Map<ConcreteTypesEnvironment, ConcreteType> callerInstances =
+ cache[caller];
+ if (callerInstances != null) {
+ callerInstances.forEach((environment, _) {
+ workQueue.addLast(
+ new InferenceWorkItem(caller, environment));
+ });
+ }
+ }
+ }
+
// -- query --
/**
@@ -759,6 +814,8 @@ class ConcreteTypesInferrer {
ConcreteType getMonomorphicSendReturnType(
FunctionElement function,
ConcreteTypesEnvironment environment) {
+ ConcreteType specialType = getSpecialCaseReturnType(function, environment);
+ if (specialType != null) return specialType;
Map<ConcreteTypesEnvironment, ConcreteType> template = cache[function];
if (template == null) {
@@ -776,6 +833,35 @@ class ConcreteTypesInferrer {
}
}
+ /**
+ * Handles external methods that cannot be cached because they depend on some
+ * other state of [ConcreteTypesInferrer] like [:List#[]:] and
+ * [:List#[]=:]. Returns null if [function] and [environment] don't form a
+ * special case
+ */
+ ConcreteType getSpecialCaseReturnType(FunctionElement function,
+ ConcreteTypesEnvironment environment) {
+ if (function == listIndex) {
+ ConcreteType indexType = environment.lookupType(
+ listIndex.functionSignature.requiredParameters.head);
+ if (!indexType.baseTypes.contains(baseTypes.intBaseType)) {
+ return new ConcreteType.empty();
+ }
+ return listElementType;
+ } else if (function == listIndexSet) {
+ Link<Element> parameters =
+ listIndexSet.functionSignature.requiredParameters;
+ ConcreteType indexType = environment.lookupType(parameters.head);
+ if (!indexType.baseTypes.contains(baseTypes.intBaseType)) {
+ return new ConcreteType.empty();
+ }
+ ConcreteType elementType = environment.lookupType(parameters.tail.head);
+ augmentListElementType(elementType);
+ return new ConcreteType.empty();
+ }
+ return null;
+ }
+
ConcreteType analyze(FunctionElement element,
ConcreteTypesEnvironment environment) {
return element.isGenerativeConstructor()
@@ -785,17 +871,20 @@ class ConcreteTypesInferrer {
ConcreteType analyzeMethod(FunctionElement element,
ConcreteTypesEnvironment environment) {
- FunctionExpression tree = element.parseNode(compiler);
- // This should never happen since we only deal with concrete types, except
- // for external methods whose typing rules have not been hardcoded yet.
- if (!tree.hasBody()) {
- return unknownConcreteType;
- }
TreeElements elements =
compiler.enqueuer.resolution.resolvedElements[element];
- Visitor visitor =
- new TypeInferrerVisitor(elements, element, this, environment);
- return tree.accept(visitor);
+ ConcreteType specialResult = handleSpecialMethod(element, environment);
+ if (specialResult != null) return specialResult;
+ FunctionExpression tree = element.parseNode(compiler);
+ if (tree.hasBody()) {
+ Visitor visitor =
+ new TypeInferrerVisitor(elements, element, this, environment);
+ return tree.accept(visitor);
+ } else {
+ // TODO(polux): implement visitForeingCall and always use the
+ // implementation element instead of this hack
+ return new ConcreteType.unknown();
+ }
}
ConcreteType analyzeConstructor(FunctionElement element,
@@ -846,8 +935,43 @@ class ConcreteTypesInferrer {
return singletonConcreteType(new ClassBaseType(enclosingClass));
}
- void analyzeMain(Element element) {
+ /**
+ * Hook that performs side effects on some special method calls (like
+ * [:List(length):]) and possibly returns a concrete type
+ * (like [:{JsArray}:]).
+ */
+ ConcreteType handleSpecialMethod(FunctionElement element,
+ ConcreteTypesEnvironment environment) {
+ // When List([length]) is called with some length, we must augment
+ // listElementType with {null}.
+ if (element == listConstructor) {
+ Link<Element> parameters =
+ listConstructor.functionSignature.optionalParameters;
+ ConcreteType lengthType = environment.lookupType(parameters.head);
+ if (lengthType.baseTypes.contains(baseTypes.intBaseType)) {
+ augmentListElementType(singletonConcreteType(new NullBaseType()));
+ }
+ return singletonConcreteType(baseTypes.listBaseType);
+ }
+ }
+
+ /* Initialization code that cannot be run in the constructor because it
+ * requires the compiler's elements to be populated.
+ */
+ void initialize() {
baseTypes = new BaseTypes(compiler);
+ ClassElement jsArrayClass = baseTypes.listBaseType.element;
+ listIndex = jsArrayClass.lookupMember(const SourceString('[]'));
+ listIndexSet =
+ jsArrayClass.lookupMember(const SourceString('[]='));
+ listConstructor =
+ compiler.listClass.lookupConstructor(
+ new Selector.callConstructor(const SourceString(''),
+ compiler.listClass.getLibrary()));
+ }
+
+ void analyzeMain(Element element) {
+ initialize();
cache[element] = new Map<ConcreteTypesEnvironment, ConcreteType>();
populateCacheWithBuiltinRules();
try {
@@ -859,21 +983,11 @@ class ConcreteTypesInferrer {
var template = cache[item.method];
if (template[item.environment] == concreteType) continue;
template[item.environment] = concreteType;
- final methodCallers = callers[item.method];
- if (methodCallers == null) continue;
- for (final caller in methodCallers) {
- final callerInstances = cache[caller];
- if (callerInstances != null) {
- callerInstances.forEach((environment, _) {
- workQueue.addLast(
- new InferenceWorkItem(caller, environment));
- });
- }
- }
+ invalidateCallers(item.method);
}
} on CancelTypeInferenceException catch(e) {
if (LOG_FAILURES) {
- compiler.log("'${e.node}': ${e.reason}");
+ compiler.log("'${e.node.toDebugString()}': ${e.reason}");
}
}
}
@@ -1133,7 +1247,6 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> {
else return Elements.mapToUserOperatorOrNull(op);
}
- // TODO(polux): handle sendset as expression
ConcreteType visitSendSet(SendSet node) {
// Operator []= has a different behaviour than other send sets: it is
// actually a send whose return type is that of its second argument.
@@ -1222,7 +1335,14 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> {
}
ConcreteType visitLiteralList(LiteralList node) {
- visitNodeList(node.elements);
+ ConcreteType elementsType = new ConcreteType.empty();
+ // We compute the union of the types of the list literal's elements.
+ for (Link<Node> link = node.elements.nodes;
+ !link.isEmpty;
+ link = link.tail) {
+ elementsType = inferrer.union(elementsType, analyze(link.head));
+ }
+ inferrer.augmentListElementType(elementsType);
return inferrer.singletonConcreteType(inferrer.baseTypes.listBaseType);
}
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/types/types.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698