Resolve right part of equality with given descriptors
This commit is contained in:
@@ -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.
|
||||
|
||||
+36
-22
@@ -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,
|
||||
|
||||
+1
-1
@@ -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!><!>}
|
||||
Reference in New Issue
Block a user