Merge CallableReferencesResolutionUtils.kt into DoubleColonExpressionResolver

This commit is contained in:
Alexander Udalov
2016-07-01 18:52:54 +03:00
parent 2fcd4e955a
commit 969ff43152
5 changed files with 116 additions and 139 deletions
@@ -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<CallableDescriptor>? {
val reference = callableReferenceExpression.callableReference
fun resolveWithReceiver(traceTitle: String?, receiver: Receiver?): OverloadResolutionResults<CallableDescriptor>? {
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")
}
}
@@ -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()
);
}
@@ -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 <D : CallableDescriptor> CallCandidateResolutionContext<D>.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)
@@ -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<CallableDescriptor>? {
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<CallableDescriptor>? {
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")
}
}
}
}
@@ -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<LookupElement>.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),