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

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: remove dead code 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
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..0051c409f4b2b5ebfae09fcaebca4c523623a01a 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 jsArrayBaseType;
karlklose 2013/01/23 13:16:55 I would still call this listBaseType and perhaps a
polux 2013/01/24 13:12:22 Done.
+ final ClassBaseType mapBaseType;
+ final ClassBaseType objectBaseType;
+ final ClassBaseType typeBaseType;
+
+ static _getJsArrayClass(Compiler compiler) {
karlklose 2013/01/23 13:16:55 You could call it 'getNativeListClass' and then sw
polux 2013/01/24 13:12:22 Done.
+ // TODO(polux): bail out on non-javascript backends?
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsArrayClass;
+ }
BaseTypes(Compiler compiler) :
intBaseType = new ClassBaseType(compiler.intClass),
@@ -293,7 +299,7 @@ class BaseTypes {
numBaseType = new ClassBaseType(compiler.numClass),
boolBaseType = new ClassBaseType(compiler.boolClass),
stringBaseType = new ClassBaseType(compiler.stringClass),
- listBaseType = new ClassBaseType(compiler.listClass),
+ jsArrayBaseType = new ClassBaseType(_getJsArrayClass(compiler)),
mapBaseType = new ClassBaseType(compiler.mapClass),
objectBaseType = new ClassBaseType(compiler.objectClass),
typeBaseType = new ClassBaseType(compiler.typeClass);
@@ -400,13 +406,34 @@ class ConcreteTypesInferrer {
bool testMode = false;
/**
- * Constants representing builtin base types. Initialized in [analyzeMain]
+ * Constants representing builtin base types. Initialized in [initialize]
karlklose 2013/01/23 13:16:55 The explanation why these are not directly initial
polux 2013/01/24 13:12:22 Wasn't sure what you meant by "shared": I just era
* and not in the constructor because the compiler elements are not yet
* populated.
*/
BaseTypes baseTypes;
/**
+ * Constant representing [:JsArray#[]:]. Initialized in [initialize]
+ * and not in the constructor because the compiler elements are not yet
+ * populated.
+ */
+ FunctionElement jsArrayBrackets;
karlklose 2013/01/23 13:16:55 How about calling this 'listIndex' ...
polux 2013/01/24 13:12:22 Done.
+
+ /**
+ * Constant representing [:JsArray#[]=:]. Initialized in [initialize]
+ * and not in the constructor because the compiler elements are not yet
+ * populated.
+ */
+ FunctionElement jsArrayBracketsEquals;
karlklose 2013/01/23 13:16:55 ... and this one 'listIndexSet'.
polux 2013/01/24 13:12:22 Done.
+
+ /**
+ * Constant representing [:List():]. Initialized in [initialize]
+ * and not in the constructor because the compiler elements are not yet
+ * populated.
+ */
+ 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 +457,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 +475,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 +564,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 +619,15 @@ class ConcreteTypesInferrer {
}
}
+ /** Augment the inferred type of elements stored in Lists. */
karlklose 2013/01/23 13:16:55 You can use /// instead of /** ... */
polux 2013/01/24 13:12:22 Done.
+ void augmentListElementType(ConcreteType type) {
+ ConcreteType newType = union(listElementType, type);
+ if (newType != listElementType) {
+ invalidateCallers(jsArrayBrackets);
+ listElementType = newType;
+ }
+ }
+
/**
* Sets the concrete type associated to [parameter] to the union of the
* inferred concrete type so far and [type].
@@ -626,6 +666,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 +817,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 +836,34 @@ class ConcreteTypesInferrer {
}
}
+ /* Handles external methods that cannot be cached because they depend on some
karlklose 2013/01/23 13:16:55 Make this a valid dart-doc comment.
polux 2013/01/24 13:12:22 Done.
+ * 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 == jsArrayBrackets) {
+ ConcreteType indexType = environment.lookupType(
+ jsArrayBrackets.functionSignature.requiredParameters.head);
+ if (!indexType.baseTypes.contains(baseTypes.intBaseType)) {
+ return new ConcreteType.empty();
+ }
+ return listElementType;
+ } else if (function == jsArrayBracketsEquals) {
+ Link<Element> parameters =
+ jsArrayBracketsEquals.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 +873,19 @@ 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 { // external method
karlklose 2013/01/23 13:16:55 All external functions should be patched when we a
polux 2013/01/24 13:12:22 As discussed, I'll handle this in an upcoming CL.
+ // TODO(polux): we might want to trust the declared type
+ return new ConcreteType.unknown();
+ }
}
ConcreteType analyzeConstructor(FunctionElement element,
@@ -846,8 +936,44 @@ 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.jsArrayBaseType);
+ }
+ }
+
+ /* 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.jsArrayBaseType.element;
+ jsArrayBrackets = jsArrayClass.lookupMember(const SourceString('[]'));
+ jsArrayBracketsEquals =
+ 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,17 +985,7 @@ 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) {
@@ -1133,7 +1249,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,8 +1337,15 @@ class TypeInferrerVisitor extends ResolvedVisitor<ConcreteType> {
}
ConcreteType visitLiteralList(LiteralList node) {
- visitNodeList(node.elements);
- return inferrer.singletonConcreteType(inferrer.baseTypes.listBaseType);
+ 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.jsArrayBaseType);
}
ConcreteType visitNodeList(NodeList node) {

Powered by Google App Engine
This is Rietveld 408576698