Index: sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart |
=================================================================== |
--- sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart (revision 26339) |
+++ sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart (working copy) |
@@ -122,6 +122,15 @@ |
TypeMask simplifyPhi(Node node, Element element, TypeMask phiType) { |
return phiType; |
} |
+ |
+ TypeMask refineReceiver(Selector selector, TypeMask receiverType) { |
+ // If the receiver is based on an element, we let the type |
+ // inferrer handle it. Otherwise, we might prevent it from finding |
+ // one-level cycles in the inference graph. |
+ if (receiverType.isElement) return receiverType; |
+ TypeMask newType = compiler.world.allFunctions.receiverType(selector); |
+ return receiverType.intersection(newType, compiler); |
+ } |
} |
/** |
@@ -1582,6 +1591,7 @@ |
SideEffects sideEffects = new SideEffects.empty(); |
final Element outermostElement; |
final InferrerEngine<T> inferrer; |
+ final Set<Element> capturedVariables = new Set<Element>(); |
SimpleTypeInferrerVisitor.internal(analyzedElement, |
this.outermostElement, |
@@ -1735,11 +1745,14 @@ |
// same as [newType]. |
ClosureClassMap nestedClosureData = |
compiler.closureToClassMapper.getMappingForNestedFunction(node); |
- nestedClosureData.forEachNonBoxedCapturedVariable((variable, field) { |
- // The type may be null for instance contexts: the 'this' |
- // variable and type parameters. |
- if (locals.locals[variable] == null) return; |
- inferrer.recordType(field, locals.locals[variable]); |
+ nestedClosureData.forEachCapturedVariable((variable, field) { |
+ if (!nestedClosureData.isVariableBoxed(variable)) { |
+ // The type may be null for instance contexts: the 'this' |
+ // variable and type parameters. |
+ if (locals.locals[variable] == null) return; |
+ inferrer.recordType(field, locals.locals[variable]); |
+ } |
+ capturedVariables.add(variable); |
}); |
return types.functionType; |
@@ -2164,17 +2177,32 @@ |
T handleDynamicSend(Node node, |
Selector selector, |
- T receiver, |
+ T receiverType, |
ArgumentsTypes arguments, |
[CallSite constraint]) { |
- if (selector.mask != receiver) { |
- selector = (receiver == types.dynamicType) |
+ if (selector.mask != receiverType) { |
+ selector = (receiverType == types.dynamicType) |
? selector.asUntyped |
- : types.newTypedSelector(receiver, selector); |
+ : types.newTypedSelector(receiverType, selector); |
updateSelectorInTree(node, selector); |
} |
+ |
+ // If the receiver of the call is a local, we may know more about |
+ // its type by refining it with the potential targets of the |
+ // calls. |
+ if (node.asSend() != null) { |
+ Node receiver = node.asSend().receiver; |
+ if (receiver != null) { |
+ Element element = elements[receiver]; |
+ if (Elements.isLocal(element) && !capturedVariables.contains(element)) { |
+ T refinedType = types.refineReceiver(selector, receiverType); |
+ locals.update(element, refinedType, node); |
+ } |
+ } |
+ } |
+ |
return inferrer.registerCalledSelector( |
- node, selector, receiver, outermostElement, arguments, |
+ node, selector, receiverType, outermostElement, arguments, |
constraint, sideEffects, inLoop); |
} |