[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.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.ModifierCheckerCore
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
@@ -561,7 +562,7 @@ class PSICallResolver(
}
}
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) {
LHSResult.Type(qualifier)
}
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
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.model.*
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
@@ -113,6 +114,7 @@ class CallableReferencesCandidateFactory(
val compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit,
val expectedType: UnwrappedType?
) : CandidateFactory<CallableReferenceCandidate> {
private val position = ArgumentConstraintPosition(argument)
fun createCallableProcessor(explicitReceiver: DetailedReceiver?) =
createCallableReferenceProcessor(outerCallContext.scopeTower, argument.rhsName, this, explicitReceiver)
@@ -152,8 +154,11 @@ class CallableReferencesCandidateFactory(
val toFreshSubstitutor = CreateDescriptorWithFreshTypeVariables.createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, it, kotlinCall = null)
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))
}
@@ -161,6 +166,16 @@ class CallableReferencesCandidateFactory(
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(
descriptor: FunctionDescriptor,
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.model.*
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.checker.captureFromExpression
import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor
@@ -202,7 +203,7 @@ internal fun checkExpressionArgument(
isReceiver: Boolean
): KotlinCallDiagnostic? {
// todo run this approximation only once for call
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.stableType, expectedType)
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.receiver.stableType, expectedType)
fun unstableSmartCastOrSubtypeError(
unstableType: UnwrappedType?, expectedType: UnwrappedType, position: ConstraintPosition
@@ -220,17 +221,17 @@ internal fun checkExpressionArgument(
val position = if (isReceiver) ReceiverConstraintPosition(expressionArgument) else ArgumentConstraintPosition(expressionArgument)
if (expressionArgument.isSafeCall) {
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
}
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) {
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)) {
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
private val ExpressionKotlinCallArgument.unstableType: UnwrappedType?
private val ReceiverValueWithSmartCastInfo.unstableType: UnwrappedType?
get() {
if (receiver.isStable || receiver.possibleTypes.isEmpty()) return null
return intersectWrappedTypes(receiver.possibleTypes + receiver.receiverValue.type)
if (isStable || possibleTypes.isEmpty()) return null
return intersectWrappedTypes(possibleTypes + receiverValue.type)
}
// with all smart casts if stable
internal val ExpressionKotlinCallArgument.stableType: UnwrappedType
internal val ReceiverValueWithSmartCastInfo.stableType: UnwrappedType
get() {
if (!receiver.isStable || receiver.possibleTypes.isEmpty()) return receiver.receiverValue.type.unwrap()
return intersectWrappedTypes(receiver.possibleTypes + receiver.receiverValue.type)
if (!isStable || possibleTypes.isEmpty()) return receiverValue.type.unwrap()
return intersectWrappedTypes(possibleTypes + receiverValue.type)
}
@@ -55,9 +55,9 @@ internal object CheckVisibility : ResolutionPart {
val invisibleMember = Visibilities.findInvisibleMember(receiverValue, candidateDescriptor, containingDescriptor) ?: return emptyList()
if (dispatchReceiverArgument is ExpressionKotlinCallArgument) {
val smartCastReceiver = getReceiverValueWithSmartCast(receiverValue, dispatchReceiverArgument.stableType)
val smartCastReceiver = getReceiverValueWithSmartCast(receiverValue, dispatchReceiverArgument.receiver.stableType)
if (Visibilities.findInvisibleMember(smartCastReceiver, candidateDescriptor, containingDescriptor) == null) {
return listOf(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.stableType))
return listOf(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.receiver.stableType))
}
}