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 73f5c0837a9..f8f776e90ab 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 @@ -20,6 +20,8 @@ import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl import org.jetbrains.kotlin.psi.KtExpression @@ -27,23 +29,32 @@ import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo +import org.jetbrains.kotlin.types.typeUtil.asTypeProjection class KotlinResolutionCallbacksImpl( + val topLevelCallContext: BasicCallResolutionContext, val expressionTypingServices: ExpressionTypingServices, - val trace: BindingTrace, val typeApproximator: TypeApproximator, val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer, - val argumentTypeResolver: ArgumentTypeResolver + val argumentTypeResolver: ArgumentTypeResolver, + val doubleColonExpressionResolver: DoubleColonExpressionResolver ): KotlinResolutionCallbacks { + val trace: BindingTrace = topLevelCallContext.trace override fun analyzeAndGetLambdaResultArguments( topLevelCall: KotlinCall, @@ -117,4 +128,53 @@ class KotlinResolutionCallbacksImpl( } } } + + override fun completeCallableReference( + callableReferenceArgument: ResolvedCallableReferenceArgument, + resultTypeParameters: List + ) { + val callableCandidate = callableReferenceArgument.callableResolutionCandidate + val psiCallArgument = callableReferenceArgument.argument.psiCallArgument as CallableReferenceKotlinCallArgumentImpl + val callableReferenceExpression = psiCallArgument.ktCallableReferenceExpression + val resultSubstitutor = IndexedParametersSubstitution(callableCandidate.candidate.typeParameters, resultTypeParameters.map { it.asTypeProjection() }).buildSubstitutor() + + + // write down type for callable reference expression + val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT) + argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter, + resultType, + callableReferenceExpression) + val reference = callableReferenceExpression.callableReference + + val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) { + ExplicitReceiverKind.DISPATCH_RECEIVER -> callableCandidate.dispatchReceiver + ExplicitReceiverKind.EXTENSION_RECEIVER -> callableCandidate.extensionReceiver + else -> null + } + + val explicitReceiver = explicitCallableReceiver?.receiver + val psiCall = CallMaker.makeCall(reference, explicitReceiver?.receiverValue, null, reference, emptyList()) + + val tracing = TracingStrategyImpl.create(reference, psiCall) + val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call") + + val resolvedCall = ResolvedCallImpl(psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue, + callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind, + null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY)) + resolvedCall.setResultingSubstitutor(resultSubstitutor) + + tracing.bindCall(trace, psiCall) + tracing.bindReference(trace, resolvedCall) + tracing.bindResolvedCall(trace, resolvedCall) + + resolvedCall.setStatusToSuccess() + resolvedCall.markCallAsCompleted() + + when (callableCandidate.candidate) { + is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(callableReferenceExpression, resultType, topLevelCallContext) + is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(callableReferenceExpression, resultType, topLevelCallContext) + } + + doubleColonExpressionResolver.checkReferenceIsToAllowedMember(callableCandidate.candidate, topLevelCallContext.trace, callableReferenceExpression) + } } \ No newline at end of file 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 2bf1b613e8d..f6478a0c71b 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 @@ -131,7 +131,7 @@ class PSICallResolver( } private fun createLambdaAnalyzer(context: BasicCallResolutionContext) = - KotlinResolutionCallbacksImpl(expressionTypingServices, context.trace, typeApproximator, kotlinToResolvedCallTransformer, argumentTypeResolver) + KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator, kotlinToResolvedCallTransformer, argumentTypeResolver, doubleColonExpressionResolver) private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? { val expectedType = context.expectedType.unwrap() 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 74bc01ba057..6d9023ba916 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -546,7 +546,7 @@ class DoubleColonExpressionResolver( return type } - private fun checkReferenceIsToAllowedMember( + internal fun checkReferenceIsToAllowedMember( descriptor: CallableDescriptor, trace: BindingTrace, expression: KtCallableReferenceExpression ) { val simpleName = expression.callableReference @@ -570,7 +570,7 @@ class DoubleColonExpressionResolver( return original.extensionReceiverParameter != null && original.dispatchReceiverParameter != null } - private fun bindFunctionReference(expression: KtCallableReferenceExpression, type: KotlinType, context: ResolutionContext<*>) { + internal fun bindFunctionReference(expression: KtCallableReferenceExpression, type: KotlinType, context: ResolutionContext<*>) { val functionDescriptor = AnonymousFunctionDescriptor( context.scope.ownerDescriptor, Annotations.EMPTY, @@ -590,7 +590,7 @@ class DoubleColonExpressionResolver( context.trace.record(BindingContext.FUNCTION, expression, functionDescriptor) } - private fun bindPropertyReference(expression: KtCallableReferenceExpression, referenceType: KotlinType, context: ResolutionContext<*>) { + internal fun bindPropertyReference(expression: KtCallableReferenceExpression, referenceType: KotlinType, context: ResolutionContext<*>) { val localVariable = LocalVariableDescriptor( context.scope.ownerDescriptor, Annotations.EMPTY, Name.special(""), referenceType, /* mutable = */ false, /* isDelegated = */ false, expression.toSourceElement() 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 1cf2d0c45d4..68a0be7b939 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 @@ -29,7 +29,10 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.DISPATCH_RE import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.EXTENSION_RECEIVER import org.jetbrains.kotlin.resolve.calls.tower.* import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns -import org.jetbrains.kotlin.resolve.scopes.receivers.* +import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.UnwrappedType @@ -39,21 +42,15 @@ import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.upperIfFlexible import org.jetbrains.kotlin.utils.SmartList -sealed class CallableReceiver { - class UnboundReference(val qualifier: QualifierReceiver) : CallableReceiver() - class BoundValueReference(val qualifier: QualifierReceiver) : CallableReceiver() - class ScopeReceiver(val receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver() - class ExplicitValueReceiver(val receiver: SimpleKotlinCallArgument) : CallableReceiver() +sealed class CallableReceiver(val receiver: ReceiverValueWithSmartCastInfo) { + class UnboundReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver) + class BoundValueReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver) + class ScopeReceiver(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver) + class ExplicitValueReceiver(val lhsArgument: SimpleKotlinCallArgument, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver) } private val CallableReceiver.asReceiverValueForVisibilityChecks: ReceiverValue - get() = when(this) { - is CallableReceiver.ScopeReceiver -> receiver.receiverValue - is CallableReceiver.ExplicitValueReceiver -> receiver.receiver.receiverValue - is CallableReceiver.BoundValueReference -> qualifier.classValueReceiver ?: Visibilities.ALWAYS_SUITABLE_RECEIVER - is CallableReceiver.UnboundReference -> (qualifier.descriptor as? ClassDescriptor)?.defaultType?.let(::TransientReceiver) - ?: Visibilities.ALWAYS_SUITABLE_RECEIVER - } + get() = receiver.receiverValue /** * Suppose we have class A with staticM, memberM, memberExtM. @@ -67,6 +64,7 @@ class CallableReferenceCandidate( val candidate: CallableDescriptor, val dispatchReceiver: CallableReceiver?, val extensionReceiver: CallableReceiver?, + val explicitReceiverKind: ExplicitReceiverKind, val reflectionCandidateType: UnwrappedType, val numDefaults: Int, override val status: ResolutionCandidateStatus @@ -137,10 +135,11 @@ class CallableReferencesCandidateFactory( if (candidateDescriptor !is CallableMemberDescriptor) { val status = ResolutionCandidateStatus(listOf(NotCallableMemberReference(argument, candidateDescriptor))) return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver, - reflectionCandidateType, defaults, status) + explicitReceiverKind, reflectionCandidateType, defaults, status) } val diagnostics = SmartList() + diagnostics.addAll(towerCandidate.diagnostics) val invisibleMember = Visibilities.findInvisibleMember(dispatchCallableReceiver?.asReceiverValueForVisibilityChecks, candidateDescriptor, outerCallContext.scopeTower.lexicalScope.ownerDescriptor) if (invisibleMember != null) { @@ -159,7 +158,7 @@ class CallableReferencesCandidateFactory( } return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver, - reflectionCandidateType, defaults, ResolutionCandidateStatus(diagnostics)) + explicitReceiverKind, reflectionCandidateType, defaults, ResolutionCandidateStatus(diagnostics)) } private fun getArgumentAndReturnTypeUseMappingByExpectedType( @@ -273,16 +272,16 @@ class CallableReferencesCandidateFactory( val lhsResult = argument.lhsResult return when (lhsResult) { - is LHSResult.Expression -> CallableReceiver.ExplicitValueReceiver(lhsResult.lshCallArgument) + is LHSResult.Expression -> CallableReceiver.ExplicitValueReceiver(lhsResult.lshCallArgument, receiver) is LHSResult.Type -> { if (lhsResult.qualifier.classValueReceiver?.type == receiver.receiverValue.type) { - CallableReceiver.BoundValueReference(lhsResult.qualifier) + CallableReceiver.BoundValueReference(lhsResult.qualifier, receiver) } else { - CallableReceiver.UnboundReference(lhsResult.qualifier) + CallableReceiver.UnboundReference(lhsResult.qualifier, receiver) } } - is LHSResult.Object -> CallableReceiver.BoundValueReference(lhsResult.qualifier) + is LHSResult.Object -> CallableReceiver.BoundValueReference(lhsResult.qualifier, receiver) else -> throw IllegalStateException("Unsupported kind of lhsResult: $lhsResult") } } 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 9eaec0aa5cd..df8dab589e3 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 @@ -38,4 +38,7 @@ interface KotlinResolutionCallbacks { fun completeLambdaReturnType(lambdaArgument: ResolvedLambdaArgument, returnType: KotlinType) + fun completeCallableReference(callableReferenceArgument: ResolvedCallableReferenceArgument, + resultTypeParameters: List) + } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt index f137f65b7f7..4daca9ac863 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt @@ -50,6 +50,7 @@ class KotlinCallCompleter( fun buildCurrentSubstitutor(): NewTypeSubstitutor fun buildResultingSubstitutor(): NewTypeSubstitutor val lambdaArguments: List + val callableReferenceArguments: List // type can be proper if it not contains not fixed type variables fun canBeProper(type: UnwrappedType): Boolean @@ -110,6 +111,9 @@ class KotlinCallCompleter( c.lambdaArguments.forEach { resolutionCallbacks.completeLambdaReturnType(it, currentSubstitutor.safeSubstitute(it.returnType)) } + c.callableReferenceArguments.forEach { + resolutionCallbacks.completeCallableReference(it, it.myTypeVariables.map { currentSubstitutor.safeSubstitute(it.defaultType) }) + } return ResolvedKotlinCall.CompletedResolvedKotlinCall(completedCall, competedCalls) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt index 3719bfa271b..c50e22f3316 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt @@ -250,6 +250,12 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re return storage.lambdaArguments } + override val callableReferenceArguments: List + get() { + checkState(State.COMPLETION) + return storage.callableReferenceArguments + } + // KotlinCallCompleter.Context override fun asResultTypeResolverContext() = apply { checkState(State.COMPLETION) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallElements.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallElements.kt index 7ac774e308e..33b26512df9 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallElements.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallElements.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.resolve.calls.model import org.jetbrains.kotlin.builtins.createFunctionType +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable @@ -55,7 +56,7 @@ class ResolvedLambdaArgument( class ResolvedCallableReferenceArgument( override val outerCall: KotlinCall, override val argument: CallableReferenceKotlinCallArgument, - override val myTypeVariables: Collection, + override val myTypeVariables: List, val callableResolutionCandidate: CallableReferenceCandidate ) : ArgumentWithPostponeResolution() { override val inputType: Collection get() = emptyList()