From 9bf5f16bb74d2178cbc956234493b9f4835ece7e Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 18 Jun 2013 19:52:42 +0400 Subject: [PATCH] refactoring extracted checkReceiverTypeError method to avoid 'checkOnlyReceiverTypeError' boolean flag --- .../lang/resolve/calls/CallResolverUtil.java | 24 ++------ .../lang/resolve/calls/CandidateResolver.java | 61 +++++++++++++------ 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java index 34f856a3f4e..f9467fffa71 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java @@ -152,29 +152,15 @@ public class CallResolverUtil { return CallKey.create(context.call.getCallType(), (JetExpression) callElement); } - public static boolean checkArgumentCannotBeReceiver( - @NotNull JetType receiverArgumentType, + @NotNull + public static JetType getErasedReceiverType( + @NotNull ReceiverParameterDescriptor receiverParameterDescriptor, @NotNull CallableDescriptor descriptor ) { - JetType effectiveReceiverArgumentType = TypeUtils.makeNotNullable(receiverArgumentType); - - JetType erasedReceiverType = getErasedReceiverType(descriptor); - if (erasedReceiverType == null) return true; - - return !JetTypeChecker.INSTANCE.isSubtypeOf(effectiveReceiverArgumentType, erasedReceiverType); - } - - @Nullable - private static JetType getErasedReceiverType(@NotNull CallableDescriptor descriptor) { - ReceiverParameterDescriptor receiverDescriptor = descriptor.getReceiverParameter(); - ReceiverParameterDescriptor expectedThisObjectDescriptor = descriptor.getExpectedThisObject(); - JetType receiverType = receiverDescriptor != null ? receiverDescriptor.getType() : - expectedThisObjectDescriptor != null ? expectedThisObjectDescriptor.getType() : null; - if (receiverType == null) return null; - + JetType receiverType = receiverParameterDescriptor.getType(); for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) { if (typeParameter.getTypeConstructor().equals(receiverType.getConstructor())) { - return typeParameter.getUpperBoundsAsType(); + receiverType = typeParameter.getUpperBoundsAsType(); } } List fakeTypeArguments = Lists.newArrayList(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index e2f6585dadd..46f664a140c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -45,6 +45,7 @@ import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.expressions.DataFlowUtils; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; @@ -83,7 +84,7 @@ public class CandidateResolver { ResolvedCallImpl candidateCall = context.candidateCall; D candidate = candidateCall.getCandidateDescriptor(); - candidateCall.addStatus(checkReceiver(context, context.trace, /*checkOnlyReceiverTypeError=*/true)); + candidateCall.addStatus(checkReceiverTypeError(context.candidateCall)); if (ErrorUtils.isError(candidate)) { candidateCall.addStatus(SUCCESS); @@ -578,6 +579,8 @@ public class CandidateResolver { ResolutionStatus resultStatus = SUCCESS; ResolvedCall candidateCall = context.candidateCall; + resultStatus = resultStatus.combine(checkReceiverTypeError(candidateCall)); + // Comment about a very special case. // Call 'b.foo(1)' where class 'Foo' has an extension member 'fun B.invoke(Int)' should be checked two times for safe call (in 'checkReceiver'), because // both 'b' (receiver) and 'foo' (this object) might be nullable. In the first case we mark dot, in the second 'foo'. @@ -586,14 +589,14 @@ public class CandidateResolver { resultStatus = resultStatus.combine(checkReceiver( context, candidateCall, trace, candidateCall.getResultingDescriptor().getReceiverParameter(), - candidateCall.getReceiverArgument(), candidateCall.getExplicitReceiverKind().isReceiver(), false, checkOnlyReceiverTypeError)); + candidateCall.getReceiverArgument(), candidateCall.getExplicitReceiverKind().isReceiver(), false)); resultStatus = resultStatus.combine(checkReceiver( context, candidateCall, trace, candidateCall.getResultingDescriptor().getExpectedThisObject(), candidateCall.getThisObject(), candidateCall.getExplicitReceiverKind().isThisObject(), // for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error - context.call instanceof CallForImplicitInvoke, checkOnlyReceiverTypeError)); + context.call instanceof CallForImplicitInvoke)); return resultStatus; } @@ -673,6 +676,37 @@ public class CandidateResolver { return null; } + private static ResolutionStatus checkReceiverTypeError( + @NotNull ResolvedCall candidateCall + ) { + D candidateDescriptor = candidateCall.getCandidateDescriptor(); + if (candidateDescriptor instanceof ExpressionAsFunctionDescriptor) return SUCCESS; + + ReceiverParameterDescriptor receiverDescriptor = candidateDescriptor.getReceiverParameter(); + ReceiverParameterDescriptor expectedThisObjectDescriptor = candidateDescriptor.getExpectedThisObject(); + ReceiverParameterDescriptor receiverParameterDescriptor; + JetType receiverArgumentType; + if (receiverDescriptor != null && candidateCall.getReceiverArgument().exists()) { + receiverParameterDescriptor = receiverDescriptor; + receiverArgumentType = candidateCall.getReceiverArgument().getType(); + } + else if (expectedThisObjectDescriptor != null && candidateCall.getThisObject().exists()) { + receiverParameterDescriptor = expectedThisObjectDescriptor; + receiverArgumentType = candidateCall.getThisObject().getType(); + } + else { + return SUCCESS; + } + + JetType effectiveReceiverArgumentType = TypeUtils.makeNotNullable(receiverArgumentType); + JetType erasedReceiverType = CallResolverUtil.getErasedReceiverType(receiverParameterDescriptor, candidateDescriptor); + + if (!JetTypeChecker.INSTANCE.isSubtypeOf(effectiveReceiverArgumentType, erasedReceiverType)) { + return RECEIVER_TYPE_ERROR; + } + return SUCCESS; + } + private static ResolutionStatus checkReceiver( @NotNull CallCandidateResolutionContext context, @NotNull ResolvedCall candidateCall, @@ -680,28 +714,18 @@ public class CandidateResolver { @Nullable ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument, boolean isExplicitReceiver, - boolean implicitInvokeCheck, - boolean checkOnlyReceiverTypeError + boolean implicitInvokeCheck ) { if (receiverParameter == null || !receiverArgument.exists()) return SUCCESS; JetType receiverArgumentType = receiverArgument.getType(); JetType effectiveReceiverArgumentType = TypeUtils.makeNotNullable(receiverArgumentType); D candidateDescriptor = candidateCall.getCandidateDescriptor(); - if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(effectiveReceiverArgumentType, receiverParameter.getType())) { - - if (CallResolverUtil.checkArgumentCannotBeReceiver(effectiveReceiverArgumentType, candidateDescriptor) - && !(candidateDescriptor instanceof ExpressionAsFunctionDescriptor)) { - return RECEIVER_TYPE_ERROR; - } - //todo - if (!TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateDescriptor.getTypeParameters()) - && !checkOnlyReceiverTypeError) { - context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument); - return OTHER_ERROR; - } + if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(effectiveReceiverArgumentType, receiverParameter.getType()) + && !TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateDescriptor.getTypeParameters())) { + context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument); + return OTHER_ERROR; } - if (checkOnlyReceiverTypeError) return SUCCESS; BindingContext bindingContext = trace.getBindingContext(); boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.isSafeCall(); @@ -727,7 +751,6 @@ public class CandidateResolver { this.status = status; this.argumentTypes = argumentTypes; } - } @NotNull