Chromium Code Reviews| 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, |