diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt index e6a86f1ef40..d58a8c0baed 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/diagnosticUtils.kt @@ -62,7 +62,7 @@ fun ResolutionContext<*>.reportTypeMismatchDueToTypeProjection( val resolvedCall = callPosition.leftPart.getResolvedCall(trace.bindingContext) ?: return false resolvedCall to { f: CallableDescriptor -> (f as? PropertyDescriptor)?.setter?.valueParameters?.get(0)?.type } } - is CallPosition.Unknown -> return false + is CallPosition.Unknown, is CallPosition.CallableReferenceRhs -> return false } val receiverType = resolvedCall.smartCastDispatchReceiverType diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallPosition.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallPosition.kt index 27c9d96354a..42593e738b3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallPosition.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/context/CallPosition.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.types.expressions.DoubleColonLHS sealed class CallPosition { @@ -34,4 +35,6 @@ sealed class CallPosition { ) : CallPosition() class PropertyAssignment(val leftPart: KtExpression?, val isLeft: Boolean) : CallPosition() + + class CallableReferenceRhs(val lhs: DoubleColonLHS?) : CallPosition() } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt index 91e11562efe..b345fd61df5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt @@ -320,6 +320,13 @@ class KotlinResolutionCallbacksImpl( trace.record(BindingContext.NEW_INFERENCE_IS_LAMBDA_FOR_OVERLOAD_RESOLUTION_INLINE, literal, isLambdaInline) } + override fun getLhsResult(call: KotlinCall): LHSResult { + val callableReferenceExpression = call.extractCallableReferenceExpression() + ?: throw IllegalStateException("Not a callable reference") + val (_, lhsResult) = psiCallResolver.getLhsResult(topLevelCallContext, callableReferenceExpression) + return lhsResult + } + private fun convertSignedConstantToUnsigned(expression: KtExpression): IntegerValueTypeConstant? { val constant = trace[BindingContext.COMPILE_TIME_VALUE, expression] if (constant !is IntegerValueTypeConstant || !constantCanBeConvertedToUnsigned(constant)) return null 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 7c99973fca1..616b1a7604e 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.resolve.calls.components.InferenceSession import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext +import org.jetbrains.kotlin.resolve.calls.context.CallPosition import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.inference.buildResultingSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter @@ -771,6 +772,47 @@ class PSICallResolver( return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: createParseErrorElement() } + fun getLhsResult(context: BasicCallResolutionContext, ktExpression: KtCallableReferenceExpression): Pair { + val expressionTypingContext = ExpressionTypingContext.newContext(context) + + if (ktExpression.isEmptyLHS) return null to LHSResult.Empty + + val doubleColonLhs = (context.callPosition as? CallPosition.CallableReferenceRhs)?.lhs + ?: doubleColonExpressionResolver.resolveDoubleColonLHS(ktExpression, expressionTypingContext) + ?: return null to LHSResult.Empty + val lhsResult = when (doubleColonLhs) { + is DoubleColonLHS.Expression -> { + if (doubleColonLhs.isObjectQualifier) { + val classifier = doubleColonLhs.type.constructor.declarationDescriptor + val calleeExpression = ktExpression.receiverExpression?.getCalleeExpressionIfAny() + if (calleeExpression is KtSimpleNameExpression && classifier is ClassDescriptor) { + LHSResult.Object(ClassQualifier(calleeExpression, classifier)) + } else { + LHSResult.Error + } + } else { + val fakeArgument = FakeValueArgumentForLeftCallableReference(ktExpression) + + val kotlinCallArgument = createSimplePSICallArgument(context, fakeArgument, doubleColonLhs.typeInfo) + kotlinCallArgument?.let { LHSResult.Expression(it as SimpleKotlinCallArgument) } ?: LHSResult.Error + } + } + is DoubleColonLHS.Type -> { + val qualifiedExpression = ktExpression.receiverExpression!! + val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression) + val classifier = doubleColonLhs.type.constructor.declarationDescriptor + if (classifier !is ClassDescriptor) { + expressionTypingContext.trace.report(Errors.CALLABLE_REFERENCE_LHS_NOT_A_CLASS.on(ktExpression)) + LHSResult.Error + } else { + LHSResult.Type(qualifier, doubleColonLhs.type.unwrap()) + } + } + } + + return doubleColonLhs to lhsResult + } + fun createCallableReferenceKotlinCallArgument( context: BasicCallResolutionContext, ktExpression: KtCallableReferenceExpression, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt index 3ba098d9392..20361eb3ace 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -720,7 +720,8 @@ class DoubleColonExpressionResolver( receiver: Receiver?, reference: KtSimpleNameExpression, outerContext: ResolutionContext<*>, - resolutionMode: ResolveArgumentsMode + resolutionMode: ResolveArgumentsMode, + lhs: DoubleColonLHS? ): ResolutionResultsAndTraceCommitCallback? { // we should preserve information about `call` because callable references are analyzed two times, // otherwise there will be not completed calls in trace @@ -737,7 +738,12 @@ class DoubleColonExpressionResolver( outerContext.replaceTraceAndCache(temporaryTrace) val resolutionResults = callResolver.resolveCallForMember( - reference, BasicCallResolutionContext.create(newContext, call, CheckArgumentTypesMode.CHECK_CALLABLE_TYPE) + reference, + BasicCallResolutionContext.create( + newContext.replaceCallPosition(CallPosition.CallableReferenceRhs(lhs)), + call, + CheckArgumentTypesMode.CHECK_CALLABLE_TYPE + ) ) return when { @@ -763,7 +769,7 @@ class DoubleColonExpressionResolver( if (lhsType == null) { if (!expression.isEmptyLHS) return null - return tryResolveRHSWithReceiver("resolve callable reference with empty LHS", null, reference, c, mode) + return tryResolveRHSWithReceiver("resolve callable reference with empty LHS", null, reference, c, mode, lhs) ?.apply { commitTrace() }?.results } @@ -780,14 +786,14 @@ class DoubleColonExpressionResolver( if (qualifier is ClassQualifier) { yieldIfNotNull( tryResolveRHSWithReceiver( - "resolve unbound callable reference in static scope", qualifier, reference, c, mode + "resolve unbound callable reference in static scope", qualifier, reference, c, mode, lhs ) ) } yieldIfNotNull( tryResolveRHSWithReceiver( - "resolve unbound callable reference with receiver", TransientReceiver(lhsType), reference, c, mode + "resolve unbound callable reference with receiver", TransientReceiver(lhsType), reference, c, mode, lhs ) ) } @@ -795,7 +801,7 @@ class DoubleColonExpressionResolver( val expressionReceiver = ExpressionReceiver.create(expression.receiverExpression!!, lhsType, c.trace.bindingContext) yieldIfNotNull( tryResolveRHSWithReceiver( - "resolve bound callable reference", expressionReceiver, reference, c, mode + "resolve bound callable reference", expressionReceiver, reference, c, mode, lhs ) ) @@ -806,7 +812,7 @@ class DoubleColonExpressionResolver( val qualifier = ClassQualifier(calleeExpression, classifier) yieldIfNotNull( tryResolveRHSWithReceiver( - "resolve object callable reference in static scope", qualifier, reference, c, mode + "resolve object callable reference in static scope", qualifier, reference, c, mode, lhs ) ) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt index 022fe3ae7aa..7b403c3f688 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ExternalComponents.kt @@ -87,6 +87,8 @@ interface KotlinResolutionCallbacks { fun disableContractsIfNecessary(resolvedAtom: ResolvedCallAtom) + fun getLhsResult(call: KotlinCall): LHSResult + fun convertSignedConstantToUnsigned(argument: KotlinCallArgument): IntegerValueTypeConstant? fun recordInlinabilityOfLambda(atom: Set>)