Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart |
| =================================================================== |
| --- sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart (revision 19615) |
| +++ sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart (working copy) |
| @@ -15,7 +15,7 @@ |
| // of Selector from dart2jslib.dart fail. For now, we work around that |
| // by importing universe.dart explicitly and disabling the re-export. |
| import '../dart2jslib.dart' hide Selector; |
| -import '../universe/universe.dart' show Selector; |
| +import '../universe/universe.dart' show Selector, TypedSelector; |
| /** |
| * A work queue that ensures there are no duplicates, and adds and |
| @@ -254,7 +254,7 @@ |
| if (selector == null || selector.isSetter() || selector.isIndexSet()) { |
| return null; |
| } |
| - return getTypeIfValuable(returnTypeOfSelector(selector)); |
| + return getTypeIfValuable(typeOfSelector(selector)); |
| } |
| /** |
| @@ -319,27 +319,28 @@ |
| void initializeTypes() { |
| // TODO(ngeoffray): Is that the right type? |
| - nullType = new TypeMask.exact(compiler.nullClass.computeType(compiler)); |
| + Backend backend = compiler.backend; |
| + nullType = new TypeMask.exact( |
| + backend.nullImplementation.computeType(compiler)); |
| intType = new TypeMask.nonNullExact( |
| - compiler.intClass.rawType); |
| + compiler.backend.intImplementation.rawType); |
| doubleType = new TypeMask.nonNullExact( |
| - compiler.doubleClass.rawType); |
| - // TODO(ngeoffray): Switch to subtype once we do proper union. |
| - numType = new TypeMask.nonNullExact( |
| - compiler.numClass.rawType); |
| + backend.doubleImplementation.rawType); |
| + numType = new TypeMask.nonNullSubclass( |
| + backend.numImplementation.rawType); |
| stringType = new TypeMask.nonNullExact( |
| - compiler.stringClass.rawType); |
| + backend.stringImplementation.rawType); |
| boolType = new TypeMask.nonNullExact( |
| - compiler.boolClass.rawType); |
| + backend.boolImplementation.rawType); |
| listType = new TypeMask.nonNullExact( |
| - compiler.listClass.rawType); |
| - mapType = new TypeMask.nonNullExact( |
| - compiler.mapClass.rawType); |
| + backend.listImplementation.rawType); |
| + mapType = new TypeMask.nonNullSubtype( |
| + backend.mapImplementation.rawType); |
| functionType = new TypeMask.nonNullSubtype( |
| - compiler.functionClass.rawType); |
| + backend.functionImplementation.rawType); |
| typeType = new TypeMask.nonNullExact( |
| - compiler.typeClass.rawType); |
| + backend.typeImplementation.rawType); |
| } |
| dump() { |
| @@ -461,10 +462,10 @@ |
| } |
| /** |
| - * Returns the union of the return types of all elements that match |
| + * Returns the union of the types of all elements that match |
| * the called [selector]. |
| */ |
| - TypeMask returnTypeOfSelector(Selector selector) { |
| + TypeMask typeOfSelector(Selector selector) { |
| TypeMask result; |
| iterateOverElements(selector, (Element element) { |
| assert(element.isImplementation); |
| @@ -552,22 +553,6 @@ |
| } |
| /** |
| - * Registers that [caller] accesses an element matching [selector] |
| - * through a property access. |
| - */ |
| - void registerGetterOnSelector(Element caller, Selector selector) { |
| - assert(isNotClosure(caller)); |
| - if (analyzeCount.containsKey(caller)) return; |
| - iterateOverElements(selector, (Element element) { |
| - assert(element.isImplementation); |
| - Set<Element> callers = callersOf.putIfAbsent( |
| - element, () => new Set<Element>()); |
| - callers.add(caller); |
| - return true; |
| - }); |
| - } |
| - |
| - /** |
| * Registers that [caller] closurizes [function]. |
| */ |
| void registerGetFunction(Element caller, Element function) { |
| @@ -872,6 +857,26 @@ |
| return returnType; |
| } |
| + TypeMask _thisType; |
| + TypeMask get thisType { |
| + if (_thisType != null) return _thisType; |
| + ClassElement cls = outermostElement.getEnclosingClass(); |
| + if (compiler.world.isUsedAsMixin(cls)) { |
| + return _thisType = new TypeMask.nonNullSubtype(cls.rawType); |
| + } else if (compiler.world.hasAnySubclass(cls)) { |
| + return _thisType = new TypeMask.nonNullSubclass(cls.rawType); |
| + } else { |
| + return _thisType = new TypeMask.nonNullExact(cls.rawType); |
| + } |
| + } |
| + |
| + TypeMask _superType; |
| + TypeMask get superType { |
| + if (_superType != null) return _superType; |
| + return _superType = new TypeMask.nonNullExact( |
| + outermostElement.getEnclosingClass().superclass); |
| + } |
| + |
| void recordReturnType(TypeMask type) { |
| returnType = inferrer.computeLUB(returnType, type); |
| } |
| @@ -1072,9 +1077,11 @@ |
| } |
| TypeMask visitIdentifier(Identifier node) { |
| - if (node.isThis() || node.isSuper()) { |
| - // TODO(ngeoffray): Represent subclasses. |
| + if (node.isThis()) { |
| + // TODO(ngeoffray): use subtypes and subclasses masks when inferring. |
| return inferrer.dynamicType; |
|
kasperl
2013/03/07 14:09:17
Use thisType?
ngeoffray
2013/03/08 11:32:37
Done.
|
| + } else if (node.isSuper()) { |
| + return superType; |
| } |
| return inferrer.dynamicType; |
| } |
| @@ -1125,29 +1132,31 @@ |
| if (typesReturned.isEmpty) return inferrer.dynamicType; |
| TypeMask returnType; |
| for (var type in typesReturned) { |
| - ClassElement mappedType; |
| + TypeMask mappedType; |
| if (type == native.SpecialType.JsObject) { |
| - mappedType = compiler.objectClass; |
| + mappedType = new TypeMask.nonNullExact(compiler.objectClass.rawType); |
| } else if (type == native.SpecialType.JsArray) { |
| - mappedType = compiler.listClass; |
| + mappedType = inferrer.listType; |
| + } else if (type.element == compiler.stringClass) { |
| + mappedType = inferrer.stringType; |
| + } else if (type.element == compiler.intClass) { |
| + mappedType = inferrer.intType; |
| + } else if (type.element == compiler.doubleClass) { |
| + mappedType = inferrer.doubleType; |
| + } else if (type.element == compiler.numClass) { |
| + mappedType = inferrer.numType; |
| + } else if (type.element == compiler.boolClass) { |
| + mappedType = inferrer.boolType; |
| } else { |
| - mappedType = type.element; |
| - // For primitive types, we know how to handle them here and |
| - // in the backend. |
| - if (mappedType != compiler.stringClass |
| - && mappedType != compiler.intClass |
| - && mappedType != compiler.doubleClass |
| - && mappedType != compiler.boolClass |
| - && mappedType != compiler.numClass) { |
| - Set<ClassElement> subtypes = compiler.world.subtypes[mappedType]; |
| - // TODO(ngeoffray): Handle subtypes and subclasses. |
| - if (subtypes != null && !subtypes.isEmpty) { |
| - return inferrer.dynamicType; |
| - } |
| + Set<ClassElement> subtypes = compiler.world.subtypes[type.element]; |
| + // TODO(ngeoffray): Handle subtypes and subclasses. |
|
kasperl
2013/03/07 14:09:17
Isn't this completely trivial?
ngeoffray
2013/03/08 11:32:37
Yes. Done.
|
| + if (subtypes != null && !subtypes.isEmpty) { |
| + return inferrer.dynamicType; |
| } |
| + mappedType = new TypeMask.nonNullExact(type.element.rawType); |
| } |
| if (returnType == null) { |
| - returnType = new TypeMask.nonNullExact(mappedType.rawType); |
| + returnType = mappedType; |
| } else { |
| return inferrer.dynamicType; |
| } |
| @@ -1223,16 +1232,7 @@ |
| inferrer.registerGetterOnElement(outermostElement, element); |
| return inferrer.typeOfElement(element); |
| } else if (Elements.isInstanceSend(node, elements)) { |
| - TypeMask receiverType; |
| - if (node.receiver == null) { |
| - // TODO(ngeoffray): Use subclass or subtype if the class is |
| - // used as a mixin. |
| - receiverType = inferrer.dynamicType; |
| - } else { |
| - receiverType = node.receiver.accept(this); |
| - } |
| - Selector selector = elements.getSelector(node); |
| - return handleDynamicSend(selector, receiverType, null); |
| + return visitDynamicSend(node); |
| } else if (Elements.isStaticOrTopLevelFunction(element)) { |
| inferrer.registerGetFunction(outermostElement, element); |
| return inferrer.functionType; |
| @@ -1263,27 +1263,31 @@ |
| TypeMask handleDynamicSend(Selector selector, |
| TypeMask receiver, |
| ArgumentsTypes arguments) { |
| - if (selector.isGetter()) { |
| - assert(arguments == null); |
| - inferrer.registerGetterOnSelector(outermostElement, selector); |
| - } else if (selector.isSetter()) { |
| + if (selector.isSetter()) { |
| // TODO(ngeoffray): Register called setter. |
| + // We return null to prevent using a type for a called setter. |
| + // The return type is the right hand side of the setter. |
| + return null; |
| } else { |
| inferrer.registerCalledSelector(outermostElement, selector, arguments); |
| } |
| - return inferrer.returnTypeOfSelector(selector); |
| + if (!inferrer.isDynamicType(receiver)) { |
| + selector = new TypedSelector(receiver, selector); |
| + } |
| + return inferrer.typeOfSelector(selector); |
| } |
| TypeMask visitDynamicSend(Send node) { |
| + Element element = elements[node]; |
| TypeMask receiverType; |
| - if (node.receiver == null) { |
| - // TODO(ngeoffray): Use subclass or subtype if the class is |
| - // used as a mixin. |
| - receiverType = inferrer.dynamicType; |
| + if (element != null && element.isInstanceMember()) { |
| + receiverType = thisType; |
| } else { |
| receiverType = visit(node.receiver); |
| } |
| - ArgumentsTypes arguments = analyzeArguments(node.arguments); |
| + ArgumentsTypes arguments = node.isPropertyAccess |
| + ? null |
| + : analyzeArguments(node.arguments); |
| Selector selector = elements.getSelector(node); |
| return handleDynamicSend(selector, receiverType, arguments); |
| } |