[NI] Check receivers for callable reference resolution.

This commit is contained in:
Stanislav Erokhin
2017-06-13 15:15:59 +03:00
committed by Mikhail Zarechenskiy
parent a5dffafacd
commit c752e1580e
4 changed files with 31 additions and 14 deletions
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.ModifierCheckerCore import org.jetbrains.kotlin.resolve.ModifierCheckerCore
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
@@ -561,7 +562,7 @@ class PSICallResolver(
} }
} }
is DoubleColonLHS.Type -> { is DoubleColonLHS.Type -> {
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, ktExpression.receiverExpression!!) val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, ktExpression.receiverExpression!!.referenceExpression())
if (qualifier is ClassQualifier) { if (qualifier is ClassQualifier) {
LHSResult.Type(qualifier) LHSResult.Type(qualifier)
} }
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
@@ -113,6 +114,7 @@ class CallableReferencesCandidateFactory(
val compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit, val compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit,
val expectedType: UnwrappedType? val expectedType: UnwrappedType?
) : CandidateFactory<CallableReferenceCandidate> { ) : CandidateFactory<CallableReferenceCandidate> {
private val position = ArgumentConstraintPosition(argument)
fun createCallableProcessor(explicitReceiver: DetailedReceiver?) = fun createCallableProcessor(explicitReceiver: DetailedReceiver?) =
createCallableReferenceProcessor(outerCallContext.scopeTower, argument.rhsName, this, explicitReceiver) createCallableReferenceProcessor(outerCallContext.scopeTower, argument.rhsName, this, explicitReceiver)
@@ -152,8 +154,11 @@ class CallableReferencesCandidateFactory(
val toFreshSubstitutor = CreateDescriptorWithFreshTypeVariables.createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, it, kotlinCall = null) val toFreshSubstitutor = CreateDescriptorWithFreshTypeVariables.createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, it, kotlinCall = null)
val reflectionType = toFreshSubstitutor.safeSubstitute(reflectionCandidateType) val reflectionType = toFreshSubstitutor.safeSubstitute(reflectionCandidateType)
it.addSubtypeConstraint(reflectionType, expectedType, position)
it.addUnboundConstraint(toFreshSubstitutor, dispatchCallableReceiver, candidateDescriptor.dispatchReceiverParameter)
it.addUnboundConstraint(toFreshSubstitutor, extensionCallableReceiver, candidateDescriptor.extensionReceiverParameter)
it.addSubtypeConstraint(reflectionType, expectedType, ArgumentConstraintPosition(argument))
if (it.hasContradiction) diagnostics.add(CallableReferenceNotCompatible(argument, candidateDescriptor, expectedType, reflectionType)) if (it.hasContradiction) diagnostics.add(CallableReferenceNotCompatible(argument, candidateDescriptor, expectedType, reflectionType))
} }
@@ -161,6 +166,16 @@ class CallableReferencesCandidateFactory(
explicitReceiverKind, reflectionCandidateType, defaults, ResolutionCandidateStatus(diagnostics)) explicitReceiverKind, reflectionCandidateType, defaults, ResolutionCandidateStatus(diagnostics))
} }
private fun ConstraintSystemOperation.addUnboundConstraint(
toFreshSubstitutor: FreshVariableNewTypeSubstitutor,
receiver: CallableReceiver?,
candidateReceiver: ReceiverParameterDescriptor?
) {
val expectedType = toFreshSubstitutor.safeSubstitute(candidateReceiver?.value?.type?.unwrap() ?: return)
val receiverType = receiver?.receiver?.stableType ?: return
addSubtypeConstraint(receiverType, expectedType, position)
}
private fun getArgumentAndReturnTypeUseMappingByExpectedType( private fun getArgumentAndReturnTypeUseMappingByExpectedType(
descriptor: FunctionDescriptor, descriptor: FunctionDescriptor,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ReceiverConstraintPosi
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.captureFromExpression import org.jetbrains.kotlin.types.checker.captureFromExpression
import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor
@@ -202,7 +203,7 @@ internal fun checkExpressionArgument(
isReceiver: Boolean isReceiver: Boolean
): KotlinCallDiagnostic? { ): KotlinCallDiagnostic? {
// todo run this approximation only once for call // todo run this approximation only once for call
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.stableType, expectedType) val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.receiver.stableType, expectedType)
fun unstableSmartCastOrSubtypeError( fun unstableSmartCastOrSubtypeError(
unstableType: UnwrappedType?, expectedType: UnwrappedType, position: ConstraintPosition unstableType: UnwrappedType?, expectedType: UnwrappedType, position: ConstraintPosition
@@ -220,17 +221,17 @@ internal fun checkExpressionArgument(
val position = if (isReceiver) ReceiverConstraintPosition(expressionArgument) else ArgumentConstraintPosition(expressionArgument) val position = if (isReceiver) ReceiverConstraintPosition(expressionArgument) else ArgumentConstraintPosition(expressionArgument)
if (expressionArgument.isSafeCall) { if (expressionArgument.isSafeCall) {
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) { if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
return unstableSmartCastOrSubtypeError(expressionArgument.unstableType, expectedNullableType, position)?.let { return it } return unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedNullableType, position)?.let { return it }
} }
return null return null
} }
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) { if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) {
if (!isReceiver) { if (!isReceiver) {
return unstableSmartCastOrSubtypeError(expressionArgument.unstableType, expectedType, position)?.let { return it } return unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedType, position)?.let { return it }
} }
val unstableType = expressionArgument.unstableType val unstableType = expressionArgument.receiver.unstableType
if (unstableType != null && csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) { if (unstableType != null && csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) {
return UnstableSmartCast(expressionArgument, unstableType) return UnstableSmartCast(expressionArgument, unstableType)
} }
@@ -279,17 +280,17 @@ private fun captureFromTypeParameterUpperBoundIfNeeded(argumentType: UnwrappedTy
} }
// if expression is not stable and has smart casts, then we create this type // if expression is not stable and has smart casts, then we create this type
private val ExpressionKotlinCallArgument.unstableType: UnwrappedType? private val ReceiverValueWithSmartCastInfo.unstableType: UnwrappedType?
get() { get() {
if (receiver.isStable || receiver.possibleTypes.isEmpty()) return null if (isStable || possibleTypes.isEmpty()) return null
return intersectWrappedTypes(receiver.possibleTypes + receiver.receiverValue.type) return intersectWrappedTypes(possibleTypes + receiverValue.type)
} }
// with all smart casts if stable // with all smart casts if stable
internal val ExpressionKotlinCallArgument.stableType: UnwrappedType internal val ReceiverValueWithSmartCastInfo.stableType: UnwrappedType
get() { get() {
if (!receiver.isStable || receiver.possibleTypes.isEmpty()) return receiver.receiverValue.type.unwrap() if (!isStable || possibleTypes.isEmpty()) return receiverValue.type.unwrap()
return intersectWrappedTypes(receiver.possibleTypes + receiver.receiverValue.type) return intersectWrappedTypes(possibleTypes + receiverValue.type)
} }
@@ -55,9 +55,9 @@ internal object CheckVisibility : ResolutionPart {
val invisibleMember = Visibilities.findInvisibleMember(receiverValue, candidateDescriptor, containingDescriptor) ?: return emptyList() val invisibleMember = Visibilities.findInvisibleMember(receiverValue, candidateDescriptor, containingDescriptor) ?: return emptyList()
if (dispatchReceiverArgument is ExpressionKotlinCallArgument) { if (dispatchReceiverArgument is ExpressionKotlinCallArgument) {
val smartCastReceiver = getReceiverValueWithSmartCast(receiverValue, dispatchReceiverArgument.stableType) val smartCastReceiver = getReceiverValueWithSmartCast(receiverValue, dispatchReceiverArgument.receiver.stableType)
if (Visibilities.findInvisibleMember(smartCastReceiver, candidateDescriptor, containingDescriptor) == null) { if (Visibilities.findInvisibleMember(smartCastReceiver, candidateDescriptor, containingDescriptor) == null) {
return listOf(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.stableType)) return listOf(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.receiver.stableType))
} }
} }