From fb72726f08ed51a56fad91b70fba32648f14f3ba Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Tue, 6 Jun 2017 18:02:42 +0300 Subject: [PATCH] Resolve right part of equality with given descriptors --- .../kotlin/resolve/calls/CallResolver.java | 17 ++++++ .../resolve/calls/tower/PSICallResolver.kt | 2 +- .../BasicExpressionTypingVisitor.java | 58 ++++++++++++------- .../senselessComparisonWithNull.kt | 2 +- 4 files changed, 55 insertions(+), 24 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java index 310584ede3b..2fc185bb10e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java @@ -263,6 +263,23 @@ public class CallResolver { callResolutionContext, candidates, TracingStrategyImpl.create(expression, call)); } + @NotNull + public OverloadResolutionResults resolveEqualsCallWithGivenDescriptors( + @NotNull ExpressionTypingContext context, + @NotNull KtReferenceExpression expression, + @NotNull ExpressionReceiver receiver, + @NotNull Call call, + @NotNull Collection functionDescriptors + ) { + BasicCallResolutionContext callResolutionContext = BasicCallResolutionContext.create(context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS); + List> 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 resolveFunctionCall( @NotNull BindingTrace trace, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index db7d5e5d09d..b00f8447b86 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -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. diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index f03a3e1c714..8cb0c019a10 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -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 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 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 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 findEqualsWithNullableAnyParameter( + @NotNull ExpressionReceiver receiver, + @NotNull KtExpression left + ) { + KotlinType refinedType = KotlinBuiltIns.isNothingOrNullableNothing(receiver.getType()) ? + components.builtIns.getNullableAnyType() : + receiver.getType(); + Collection 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, diff --git a/compiler/testData/diagnostics/tests/incompleteCode/senselessComparisonWithNull.kt b/compiler/testData/diagnostics/tests/incompleteCode/senselessComparisonWithNull.kt index 5cc693264b7..f0e6e46e2bf 100644 --- a/compiler/testData/diagnostics/tests/incompleteCode/senselessComparisonWithNull.kt +++ b/compiler/testData/diagnostics/tests/incompleteCode/senselessComparisonWithNull.kt @@ -2,5 +2,5 @@ package d fun foo(a : IntArray) { - if (null == a() + if (null == a() } \ No newline at end of file