Index: pkg/compiler/lib/src/cps_ir/type_propagation.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
index 73e5871b7d4fa24588b865bb792fce967d76b8b1..95aacabcd349cac4ee3c1c921fd50c94a57d3628 100644 |
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
@@ -74,6 +74,13 @@ class TypeMaskSystem { |
classWorld); |
} |
+ bool methodUsesReceiverArgument(FunctionElement function) { |
+ assert(backend.isInterceptedMethod(function)); |
+ ClassElement clazz = function.enclosingClass.declaration; |
+ return clazz.isSubclassOf(backend.jsInterceptorClass) || |
+ classWorld.isUsedAsMixin(clazz); |
+ } |
+ |
Element locateSingleElement(TypeMask mask, Selector selector) { |
return mask.locateSingleElement(selector, mask, classWorld.compiler); |
} |
@@ -88,7 +95,14 @@ class TypeMaskSystem { |
TypeMask getReceiverType(MethodElement method) { |
assert(method.isInstanceMember); |
- return nonNullSubclass(method.enclosingClass); |
+ if (classWorld.isUsedAsMixin(method.enclosingClass.declaration)) { |
+ // If used as a mixin, the receiver could be any of the classes that mix |
+ // in the class, and these are not considered subclasses. |
+ // TODO(asgerf): Exclude the subtypes that only `implement` the class. |
+ return nonNullSubtype(method.enclosingClass); |
+ } else { |
+ return nonNullSubclass(method.enclosingClass); |
+ } |
} |
TypeMask getParameterType(ParameterElement parameter) { |
@@ -128,6 +142,11 @@ class TypeMaskSystem { |
return new TypeMask.nonNullSubclass(element.declaration, classWorld); |
} |
+ TypeMask nonNullSubtype(ClassElement element) { |
+ if (element.isClosure) return functionType; |
+ return new TypeMask.nonNullSubtype(element.declaration, classWorld); |
+ } |
+ |
bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) { |
if (!allowNull && t.isNullable) return false; |
return t.nonNullable().containsOnlyBool(classWorld); |
@@ -1581,6 +1600,30 @@ class TransformingVisitor extends LeafVisitor { |
AbstractValue receiver = getValue(node.receiver.definition); |
node.receiverIsNotNull = receiver.isDefinitelyNotNull; |
+ |
+ if (isInterceptedSelector(node.selector) && |
+ node.receiver.definition == node.arguments[0].definition) { |
+ // The receiver and first argument are the same; that means we already |
+ // determined in visitInterceptor that we are targeting a non-interceptor. |
+ |
+ // Check if any of the possible targets depend on the extra receiver |
+ // argument. Mixins do this, and tear-offs always needs the extra receiver |
+ // argument because BoundClosure uses it for equality and hash code. |
sra1
2015/08/26 15:04:43
SSA backend has this TODO.
// TODO(1593
|
+ bool needsReceiver(Element target) { |
+ if (target is! FunctionElement) return false; |
+ FunctionElement function = target; |
+ return typeSystem.methodUsesReceiverArgument(function) || |
+ node.selector.isGetter && !function.isGetter; |
+ } |
+ if (!getAllTargets(receiver.type, node.selector).any(needsReceiver)) { |
+ // Replace the extra receiver argument with a dummy value if the |
+ // target definitely does not use it. |
+ Constant dummy = makeConstantPrimitive(new IntConstantValue(0)); |
sra1
2015/08/26 15:04:43
There is a special constant for this purpose.
In c
|
+ insertLetPrim(node, dummy); |
+ node.arguments[0].unlink(); |
+ node.arguments[0] = new Reference<Primitive>(dummy); |
+ } |
+ } |
} |
void visitTypeCast(TypeCast node) { |
@@ -2072,9 +2115,15 @@ class TypePropagationVisitor implements Visitor { |
void visitFunctionDefinition(FunctionDefinition node) { |
int firstActualParameter = 0; |
if (backend.isInterceptedMethod(node.element)) { |
- setValue(node.thisParameter, nonConstant(typeSystem.nonNullType)); |
- setValue(node.parameters[0], |
- nonConstant(typeSystem.getReceiverType(node.element))); |
+ if (typeSystem.methodUsesReceiverArgument(node.element)) { |
+ setValue(node.thisParameter, nonConstant(typeSystem.nonNullType)); |
+ setValue(node.parameters[0], |
+ nonConstant(typeSystem.getReceiverType(node.element))); |
+ } else { |
+ setValue(node.thisParameter, |
+ nonConstant(typeSystem.getReceiverType(node.element))); |
+ setValue(node.parameters[0], nonConstant()); |
+ } |
firstActualParameter = 1; |
} else if (node.thisParameter != null) { |
setValue(node.thisParameter, |