From c752e1580ecd3990b78eba8a2b549ec5cdf9efdc Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Tue, 13 Jun 2017 15:15:59 +0300 Subject: [PATCH] [NI] Check receivers for callable reference resolution. --- .../resolve/calls/tower/PSICallResolver.kt | 3 ++- .../components/CallableReferenceResolution.kt | 17 ++++++++++++++- .../CheckArgumentsResolutionPart.kt | 21 ++++++++++--------- .../calls/components/ResolutionParts.kt | 4 ++-- 4 files changed, 31 insertions(+), 14 deletions(-) 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 1d4b2c7dbb0..cf4ba657771 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 @@ -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) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt index 68a0be7b939..5eda45772a7 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt @@ -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 { + 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?, diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CheckArgumentsResolutionPart.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CheckArgumentsResolutionPart.kt index 5036276c56e..35a8777d82b 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CheckArgumentsResolutionPart.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CheckArgumentsResolutionPart.kt @@ -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) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index 36de3568e89..aecc52ba2f4 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -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)) } }