diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/callableReferences/CallableReferencesResolutionUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/callableReferences/CallableReferencesResolutionUtils.kt deleted file mode 100644 index 9578ad5fee3..00000000000 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/callableReferences/CallableReferencesResolutionUtils.kt +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.resolve.callableReferences - -import org.jetbrains.kotlin.builtins.ReflectionTypes -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.diagnostics.Errors.CALLABLE_REFERENCE_LHS_NOT_A_CLASS -import org.jetbrains.kotlin.psi.KtCallableReferenceExpression -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.calls.CallResolver -import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode -import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext -import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode -import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext -import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache -import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults -import org.jetbrains.kotlin.resolve.calls.util.CallMaker -import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier -import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver -import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver -import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.expressions.DoubleColonLHS -import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils - -fun resolvePossiblyAmbiguousCallableReference( - callableReferenceExpression: KtCallableReferenceExpression, - lhs: DoubleColonLHS?, - context: ResolutionContext<*>, - resolutionMode: ResolveArgumentsMode, - callResolver: CallResolver -): OverloadResolutionResults? { - val reference = callableReferenceExpression.callableReference - - fun resolveWithReceiver(traceTitle: String?, receiver: Receiver?): OverloadResolutionResults? { - val call = CallMaker.makeCall(reference, receiver, null, reference, emptyList()) - val temporaryTrace = TemporaryTraceAndCache.create(context, traceTitle, reference) - val newContext = - if (resolutionMode == ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS) - context.replaceTraceAndCache(temporaryTrace).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE) - else - context.replaceTraceAndCache(temporaryTrace) - - val resolutionResults = callResolver.resolveCallForMember( - reference, BasicCallResolutionContext.create(newContext, call, CheckArgumentTypesMode.CHECK_CALLABLE_TYPE) - ) - - val shouldCommitTrace = - if (resolutionMode == ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS) resolutionResults.isSingleResult - else !resolutionResults.isNothing - if (shouldCommitTrace) temporaryTrace.commit() - - return if (resolutionResults.isNothing) null else resolutionResults - } - - val lhsType = lhs?.type ?: return resolveWithReceiver("resolve callable reference with empty LHS", null) - - when (lhs) { - is DoubleColonLHS.Type -> { - val classifier = lhsType.constructor.declarationDescriptor - if (classifier !is ClassDescriptor) { - context.trace.report(CALLABLE_REFERENCE_LHS_NOT_A_CLASS.on(callableReferenceExpression)) - return null - } - - val qualifier = context.trace.get(BindingContext.QUALIFIER, callableReferenceExpression.receiverExpression!!) - if (qualifier is ClassQualifier) { - val possibleStatic = resolveWithReceiver("resolve unbound callable reference in static scope", qualifier) - if (possibleStatic != null) return possibleStatic - } - - val possibleWithReceiver = resolveWithReceiver("resolve unbound callable reference with receiver", TransientReceiver(lhsType)) - if (possibleWithReceiver != null) return possibleWithReceiver - } - is DoubleColonLHS.Expression -> { - val result = resolveWithReceiver("resolve bound callable reference", ExpressionReceiver.create( - callableReferenceExpression.receiverExpression!!, lhsType, context.trace.bindingContext - )) - if (result != null) return result - } - } - - return null -} - -fun createKCallableTypeForReference( - descriptor: CallableDescriptor, - lhs: DoubleColonLHS?, - reflectionTypes: ReflectionTypes, - scopeOwnerDescriptor: DeclarationDescriptor -): KotlinType? { - val receiverType = - if (descriptor.extensionReceiverParameter != null || descriptor.dispatchReceiverParameter != null) - (lhs as? DoubleColonLHS.Type)?.type - else null - - return when (descriptor) { - is FunctionDescriptor -> { - val returnType = descriptor.returnType ?: return null - val valueParametersTypes = ExpressionTypingUtils.getValueParametersTypes(descriptor.valueParameters) - return reflectionTypes.getKFunctionType(Annotations.EMPTY, receiverType, valueParametersTypes, returnType) - } - is PropertyDescriptor -> { - val mutable = descriptor.isVar && run { - val setter = descriptor.setter - // TODO: support private-to-this - setter == null || Visibilities.isVisible(null, setter, scopeOwnerDescriptor) - } - reflectionTypes.getKPropertyType(Annotations.EMPTY, receiverType, descriptor.type, mutable) - } - is VariableDescriptor -> null - else -> throw UnsupportedOperationException("Callable reference resolved to an unsupported descriptor: $descriptor") - } -} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java index 55841ca8654..5cbf8018841 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.FunctionTypeResolveUtilsKt; import org.jetbrains.kotlin.resolve.TemporaryBindingTrace; import org.jetbrains.kotlin.resolve.TypeResolver; -import org.jetbrains.kotlin.resolve.callableReferences.CallableReferencesResolutionUtilsKt; import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode; import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext; import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode; @@ -261,7 +260,7 @@ public class ArgumentTypeResolver { OverloadResolutionResultsUtil.getResultingCall(overloadResolutionResults, context.contextDependency); if (resolvedCall == null) return null; - return CallableReferencesResolutionUtilsKt.createKCallableTypeForReference( + return DoubleColonExpressionResolver.Companion.createKCallableTypeForReference( resolvedCall.getResultingDescriptor(), lhs, reflectionTypes, context.scope.getOwnerDescriptor() ); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt index f26e6cb5902..4ef5323e561 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt @@ -26,7 +26,6 @@ import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.* -import org.jetbrains.kotlin.resolve.callableReferences.createKCallableTypeForReference import org.jetbrains.kotlin.resolve.calls.CallTransformer.CallForImplicitInvoke import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS @@ -52,6 +51,7 @@ import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.TypeUtils.noExpectedType import org.jetbrains.kotlin.types.checker.ErrorTypesAreEqualToAnything import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver import java.util.* class CandidateResolver( @@ -157,7 +157,7 @@ class CandidateResolver( private fun CallCandidateResolutionContext.checkExpectedCallableType() = check { if (!noExpectedType(expectedType)) { - val candidateKCallableType = createKCallableTypeForReference( + val candidateKCallableType = DoubleColonExpressionResolver.createKCallableTypeForReference( candidateCall.candidateDescriptor, (call.callElement.parent as? KtCallableReferenceExpression)?.receiverExpression?.let { trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, it) 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 c6dd25d33b0..f4c56cfffcb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -30,17 +30,22 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector import org.jetbrains.kotlin.resolve.* -import org.jetbrains.kotlin.resolve.callableReferences.createKCallableTypeForReference -import org.jetbrains.kotlin.resolve.callableReferences.resolvePossiblyAmbiguousCallableReference import org.jetbrains.kotlin.resolve.calls.CallResolver import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext +import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo +import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject +import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver +import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver import org.jetbrains.kotlin.resolve.source.toSourceElement import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType @@ -425,8 +430,111 @@ class DoubleColonExpressionResolver( else resolveDoubleColonLHS(expression, context) val resolutionResults = - resolvePossiblyAmbiguousCallableReference(expression, lhsResult, context, resolveArgumentsMode, callResolver) + resolveCallableReferenceRHS(expression, lhsResult, context, resolveArgumentsMode) return lhsResult to resolutionResults } + + private fun tryResolveRHSWithReceiver( + traceTitle: String, + receiver: Receiver?, + reference: KtSimpleNameExpression, + outerContext: ResolutionContext<*>, + resolutionMode: ResolveArgumentsMode + ): OverloadResolutionResults? { + val call = CallMaker.makeCall(reference, receiver, null, reference, emptyList()) + val temporaryTrace = TemporaryTraceAndCache.create(outerContext, traceTitle, reference) + val newContext = + if (resolutionMode == ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS) + outerContext.replaceTraceAndCache(temporaryTrace).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE) + else + outerContext.replaceTraceAndCache(temporaryTrace) + + val resolutionResults = callResolver.resolveCallForMember( + reference, BasicCallResolutionContext.create(newContext, call, CheckArgumentTypesMode.CHECK_CALLABLE_TYPE) + ) + + val shouldCommitTrace = + if (resolutionMode == ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS) resolutionResults.isSingleResult + else !resolutionResults.isNothing + if (shouldCommitTrace) temporaryTrace.commit() + + return if (resolutionResults.isNothing) null else resolutionResults + } + + private fun resolveCallableReferenceRHS( + expression: KtCallableReferenceExpression, + lhs: DoubleColonLHS?, + c: ResolutionContext<*>, + mode: ResolveArgumentsMode + ): OverloadResolutionResults? { + val reference = expression.callableReference + + val lhsType = lhs?.type ?: + return tryResolveRHSWithReceiver("resolve callable reference with empty LHS", null, reference, c, mode) + + when (lhs) { + is DoubleColonLHS.Type -> { + val classifier = lhsType.constructor.declarationDescriptor + if (classifier !is ClassDescriptor) { + c.trace.report(CALLABLE_REFERENCE_LHS_NOT_A_CLASS.on(expression)) + return null + } + + val qualifier = c.trace.get(BindingContext.QUALIFIER, expression.receiverExpression!!) + if (qualifier is ClassQualifier) { + val possibleStatic = tryResolveRHSWithReceiver( + "resolve unbound callable reference in static scope", qualifier, reference, c, mode + ) + if (possibleStatic != null) return possibleStatic + } + + val possibleWithReceiver = tryResolveRHSWithReceiver( + "resolve unbound callable reference with receiver", TransientReceiver(lhsType), reference, c, mode + ) + if (possibleWithReceiver != null) return possibleWithReceiver + } + is DoubleColonLHS.Expression -> { + val expressionReceiver = ExpressionReceiver.create(expression.receiverExpression!!, lhsType, c.trace.bindingContext) + val result = tryResolveRHSWithReceiver( + "resolve bound callable reference", expressionReceiver, reference, c, mode + ) + if (result != null) return result + } + } + + return null + } + + companion object { + fun createKCallableTypeForReference( + descriptor: CallableDescriptor, + lhs: DoubleColonLHS?, + reflectionTypes: ReflectionTypes, + scopeOwnerDescriptor: DeclarationDescriptor + ): KotlinType? { + val receiverType = + if (descriptor.extensionReceiverParameter != null || descriptor.dispatchReceiverParameter != null) + (lhs as? DoubleColonLHS.Type)?.type + else null + + return when (descriptor) { + is FunctionDescriptor -> { + val returnType = descriptor.returnType ?: return null + val valueParametersTypes = ExpressionTypingUtils.getValueParametersTypes(descriptor.valueParameters) + return reflectionTypes.getKFunctionType(Annotations.EMPTY, receiverType, valueParametersTypes, returnType) + } + is PropertyDescriptor -> { + val mutable = descriptor.isVar && run { + val setter = descriptor.setter + // TODO: support private-to-this + setter == null || Visibilities.isVisible(null, setter, scopeOwnerDescriptor) + } + reflectionTypes.getKPropertyType(Annotations.EMPTY, receiverType, descriptor.type, mutable) + } + is VariableDescriptor -> null + else -> throw UnsupportedOperationException("Callable reference resolved to an unsupported descriptor: $descriptor") + } + } + } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt index 187139ae38c..f00efef0cc8 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt @@ -35,8 +35,8 @@ import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.PossiblyBareType -import org.jetbrains.kotlin.resolve.callableReferences.createKCallableTypeForReference import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver import org.jetbrains.kotlin.types.expressions.DoubleColonLHS import org.jetbrains.kotlin.types.typeUtil.TypeNullability import org.jetbrains.kotlin.types.typeUtil.isNothing @@ -252,7 +252,7 @@ private fun MutableCollection.addLookupElementsForNullable(factor fun CallableDescriptor.callableReferenceType(resolutionFacade: ResolutionFacade, lhs: DoubleColonLHS?): FuzzyType? { if (!CallType.CALLABLE_REFERENCE.descriptorKindFilter.accepts(this)) return null // not supported by callable references - return createKCallableTypeForReference( + return DoubleColonExpressionResolver.createKCallableTypeForReference( this, lhs, resolutionFacade.getFrontendService(ReflectionTypes::class.java),