Resolve right part of equality with given descriptors

This commit is contained in:
Mikhail Zarechenskiy
2017-06-06 18:02:42 +03:00
parent 6680f01cfe
commit fb72726f08
4 changed files with 55 additions and 24 deletions
@@ -263,6 +263,23 @@ public class CallResolver {
callResolutionContext, candidates, TracingStrategyImpl.create(expression, call));
}
@NotNull
public OverloadResolutionResults<FunctionDescriptor> resolveEqualsCallWithGivenDescriptors(
@NotNull ExpressionTypingContext context,
@NotNull KtReferenceExpression expression,
@NotNull ExpressionReceiver receiver,
@NotNull Call call,
@NotNull Collection<FunctionDescriptor> functionDescriptors
) {
BasicCallResolutionContext callResolutionContext = BasicCallResolutionContext.create(context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS);
List<ResolutionCandidate<FunctionDescriptor>> resolutionCandidates = CollectionsKt.map(functionDescriptors, descriptor ->
ResolutionCandidate.create(
call, descriptor, receiver, ExplicitReceiverKind.DISPATCH_RECEIVER, null));
return computeTasksFromCandidatesAndResolvedCall(
callResolutionContext, resolutionCandidates, TracingStrategyImpl.create(expression, call));
}
@NotNull
public OverloadResolutionResults<FunctionDescriptor> resolveFunctionCall(
@NotNull BindingTrace trace,
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import kotlin.TuplesKt;
import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.KtNodeTypes;
@@ -33,6 +34,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.incremental.KotlinLookupLocation;
import org.jetbrains.kotlin.lexer.KtKeywordToken;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.name.Name;
@@ -1113,20 +1115,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
DataFlowInfo dataFlowInfo = leftTypeInfo.getDataFlowInfo();
ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo);
KotlinTypeInfo rightTypeInfo = facade.getTypeInfo(right, contextWithDataFlow);
ExpressionReceiver receiver = createReceiverForEquals(left, contextWithDataFlow);
Collection<FunctionDescriptor> equalsFunctions = findEqualsWithNullableAnyParameter(receiver, left);
TemporaryBindingTrace traceInterpretingRightAsNullableAny = TemporaryBindingTrace.create(
context.trace, "trace to resolve 'equals(Any?)' interpreting as of type Any? an expression:", right);
traceInterpretingRightAsNullableAny.recordType(right, components.builtIns.getNullableAnyType());
// Nothing? has no members, and `equals()` would be unresolved on it
KotlinType leftType = leftTypeInfo.getType();
if (leftType != null && KotlinBuiltIns.isNothingOrNullableNothing(leftType)) {
traceInterpretingRightAsNullableAny.recordType(left, components.builtIns.getNullableAnyType());
}
ExpressionTypingContext newContext = context.replaceBindingTrace(traceInterpretingRightAsNullableAny);
ExpressionReceiver receiver = ExpressionTypingUtils.safeGetExpressionReceiver(facade, left, newContext);
Call call = CallMaker.makeCallWithExpressions(
expression,
receiver,
@@ -1135,19 +1126,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
operationSign,
Collections.singletonList(right)
);
OverloadResolutionResults<FunctionDescriptor> resolutionResults =
components.callResolver.resolveCallWithGivenName(newContext, call, operationSign, OperatorNameConventions.EQUALS);
traceInterpretingRightAsNullableAny.commit((slice, key) -> {
// the type of the right (and sometimes left) expression isn't 'Any?' actually
if ((key == right || key == left) && slice == EXPRESSION_TYPE_INFO) return false;
return true;
}, true);
OverloadResolutionResults<FunctionDescriptor> resolutionResults =
components.callResolver.resolveEqualsCallWithGivenDescriptors(contextWithDataFlow, operationSign, receiver, call, equalsFunctions);
if (resolutionResults.isSuccess()) {
FunctionDescriptor equals = resolutionResults.getResultingCall().getResultingDescriptor();
if (ensureBooleanResult(operationSign, OperatorNameConventions.EQUALS, equals.getReturnType(), context)) {
ensureNonemptyIntersectionOfOperandTypes(expression, context);
if (ensureBooleanResult(operationSign, OperatorNameConventions.EQUALS, equals.getReturnType(), contextWithDataFlow)) {
ensureNonemptyIntersectionOfOperandTypes(expression, contextWithDataFlow);
}
}
else {
@@ -1158,9 +1144,37 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(EQUALS_MISSING.on(operationSign));
}
}
KotlinTypeInfo rightTypeInfo = facade.getTypeInfo(right, contextWithDataFlow);
return rightTypeInfo.replaceType(components.builtIns.getBooleanType());
}
private ExpressionReceiver createReceiverForEquals(KtExpression left, ExpressionTypingContext context) {
KotlinType leftType = ExpressionTypingUtils.safeGetType(facade.safeGetTypeInfo(left, context));
KotlinType receiverType = KotlinBuiltIns.isNothingOrNullableNothing(leftType) ?
components.builtIns.getNullableAnyType() :
leftType;
return ExpressionReceiver.Companion.create(left, receiverType, context.trace.getBindingContext());
}
private List<FunctionDescriptor> findEqualsWithNullableAnyParameter(
@NotNull ExpressionReceiver receiver,
@NotNull KtExpression left
) {
KotlinType refinedType = KotlinBuiltIns.isNothingOrNullableNothing(receiver.getType()) ?
components.builtIns.getNullableAnyType() :
receiver.getType();
Collection<SimpleFunctionDescriptor> equalsMembers =
refinedType.getMemberScope().getContributedFunctions(OperatorNameConventions.EQUALS, new KotlinLookupLocation(left));
return CollectionsKt.filter(equalsMembers, descriptor -> {
if (ErrorUtils.isError(descriptor)) return true;
if (descriptor.getValueParameters().size() != 1) return false;
ValueParameterDescriptor valueParameter = descriptor.getValueParameters().get(0);
return KotlinBuiltIns.isNullableAny(valueParameter.getType());
});
}
@NotNull
private KotlinTypeInfo visitComparison(
@NotNull KtBinaryExpression expression,
@@ -2,5 +2,5 @@
package d
fun foo(a : IntArray) {
if (null == <!FUNCTION_EXPECTED!>a<!>()<!SYNTAX!><!>
if (<!SENSELESS_COMPARISON!>null == <!FUNCTION_EXPECTED!>a<!>()<!><!SYNTAX!><!>
<!SYNTAX!><!>}