Check extension receiver properly for property references

Without this, the unrelated type specified on the LHS of a property reference
literal was considered to be an extension receiver of the candidate, and the
resolution was erroneously successul. This is only reproducible for properties,
because if we're trying to resolve an extension, we consider all properties
from the scope, even non-extensions, because there may be a property of an
extension-functional type (T.() -> R). (We don't do this for functions.)

 #KT-7430 Fixed
 #KT-7945 Fixed
This commit is contained in:
Alexander Udalov
2015-06-22 19:53:29 +03:00
parent 25210c0c18
commit 0593b833b5
9 changed files with 109 additions and 44 deletions
@@ -41,10 +41,6 @@ import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage;
@@ -277,6 +273,8 @@ public class JetControlFlowProcessor {
);
if (!status.isSuccess()) continue;
if ((candidate.getExtensionReceiverParameter() == null) == candidateCall.getExtensionReceiver().exists()) continue;
Map<ValueParameterDescriptor, ResolvedValueArgument> candidateArgumentMap = candidateCall.getValueArguments();
List<? extends ValueArgument> callArguments = call.getValueArguments();
for (int i = 0; i < callArguments.size(); i++) {
@@ -26,7 +26,6 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.context.*;
@@ -104,18 +103,16 @@ public class CandidateResolver {
}
if (task.checkArguments == CheckValueArgumentsMode.ENABLED) {
Set<ValueArgument> unmappedArguments = Sets.newLinkedHashSet();
ValueArgumentsToParametersMapper.Status argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
context.call, context.tracing, candidateCall, unmappedArguments);
context.call, context.tracing, candidateCall, Sets.<ValueArgument>newLinkedHashSet()
);
if (!argumentMappingStatus.isSuccess()) {
if (argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) {
candidateCall.addStatus(RECEIVER_PRESENCE_ERROR);
}
else {
candidateCall.addStatus(OTHER_ERROR);
}
candidateCall.addStatus(OTHER_ERROR);
}
}
checkExtensionReceiver(context);
if (!checkDispatchReceiver(context)) {
candidateCall.addStatus(OTHER_ERROR);
}
@@ -174,6 +171,25 @@ public class CandidateResolver {
checkNonExtensionCalledWithReceiver(context);
}
private static <D extends CallableDescriptor> void checkExtensionReceiver(@NotNull CallCandidateResolutionContext<D> context) {
MutableResolvedCall<D> candidateCall = context.candidateCall;
ReceiverParameterDescriptor receiverParameter = candidateCall.getCandidateDescriptor().getExtensionReceiverParameter();
ReceiverValue receiverArgument = candidateCall.getExtensionReceiver();
if (receiverParameter != null &&!receiverArgument.exists()) {
context.tracing.missingReceiver(candidateCall.getTrace(), receiverParameter);
candidateCall.addStatus(OTHER_ERROR);
}
if (receiverParameter == null && receiverArgument.exists()) {
context.tracing.noReceiverAllowed(candidateCall.getTrace());
if (context.call.getCalleeExpression() instanceof JetSimpleNameExpression) {
candidateCall.addStatus(RECEIVER_PRESENCE_ERROR);
}
else {
candidateCall.addStatus(OTHER_ERROR);
}
}
}
private static boolean checkDispatchReceiver(@NotNull CallCandidateResolutionContext<?> context) {
MutableResolvedCall<? extends CallableDescriptor> candidateCall = context.candidateCall;
CallableDescriptor candidateDescriptor = candidateCall.getCandidateDescriptor();
@@ -23,7 +23,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.name.Name;
@@ -31,7 +30,6 @@ import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.model.*;
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import java.util.List;
import java.util.Map;
@@ -46,14 +44,13 @@ import static org.jetbrains.kotlin.resolve.calls.ValueArgumentsToParametersMappe
public class ValueArgumentsToParametersMapper {
public enum Status {
STRONG_ERROR(false),
ERROR(false),
WEAK_ERROR(false),
OK(true);
private final boolean success;
private Status(boolean success) {
Status(boolean success) {
this.success = success;
}
@@ -62,7 +59,6 @@ public class ValueArgumentsToParametersMapper {
}
public Status compose(Status other) {
if (this == STRONG_ERROR || other == STRONG_ERROR) return STRONG_ERROR;
if (this == ERROR || other == ERROR) return ERROR;
if (this == WEAK_ERROR || other == WEAK_ERROR) return WEAK_ERROR;
return this;
@@ -223,7 +219,6 @@ public class ValueArgumentsToParametersMapper {
processFunctionLiteralArguments();
reportUnmappedParameters();
checkReceiverArgument();
}
private void processFunctionLiteralArguments() {
@@ -265,7 +260,6 @@ public class ValueArgumentsToParametersMapper {
}
private void reportUnmappedParameters() {
List<ValueParameterDescriptor> valueParameters = candidateCall.getCandidateDescriptor().getValueParameters();
for (ValueParameterDescriptor valueParameter : valueParameters) {
if (!usedParameters.contains(valueParameter)) {
@@ -283,26 +277,6 @@ public class ValueArgumentsToParametersMapper {
}
}
private void checkReceiverArgument() {
D candidate = candidateCall.getCandidateDescriptor();
ReceiverParameterDescriptor receiverParameter = candidate.getExtensionReceiverParameter();
ReceiverValue receiverArgument = candidateCall.getExtensionReceiver();
if (receiverParameter != null &&!receiverArgument.exists()) {
tracing.missingReceiver(candidateCall.getTrace(), receiverParameter);
setStatus(ERROR);
}
if (receiverParameter == null && receiverArgument.exists()) {
tracing.noReceiverAllowed(candidateCall.getTrace());
if (call.getCalleeExpression() instanceof JetSimpleNameExpression) {
setStatus(STRONG_ERROR);
}
else {
setStatus(ERROR);
}
}
}
private void putVararg(
ValueParameterDescriptor valueParameterDescriptor,
ValueArgument valueArgument