Simplify code in callable reference resolution

This commit is contained in:
Alexander Udalov
2016-07-01 18:42:11 +03:00
parent 00f1415ed7
commit 2fcd4e955a
4 changed files with 26 additions and 48 deletions
@@ -21,7 +21,6 @@ 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.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.CallResolver
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode
@@ -40,37 +39,6 @@ import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
private fun <D : CallableDescriptor> ResolveArgumentsMode.acceptResolution(results: OverloadResolutionResults<D>, trace: TemporaryTraceAndCache) {
when (this) {
ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS ->
if (results.isSingleResult) trace.commit()
ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS ->
if (results.isSomething()) trace.commit()
}
}
private fun resolvePossiblyAmbiguousCallableReference(
reference: KtSimpleNameExpression,
receiver: Receiver?,
context: ResolutionContext<*>,
resolutionMode: ResolveArgumentsMode,
callResolver: CallResolver
): OverloadResolutionResults<CallableDescriptor> {
val call = CallMaker.makeCall(reference, receiver, null, reference, emptyList())
val temporaryTrace = TemporaryTraceAndCache.create(context, "resolve callable reference as function", reference)
val newContext = if (resolutionMode == ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS)
context.replaceTraceAndCache(temporaryTrace).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE)
else
context.replaceTraceAndCache(temporaryTrace)
val callResolutionContext = BasicCallResolutionContext.create(
newContext, call, CheckArgumentTypesMode.CHECK_CALLABLE_TYPE)
val resolutionResults = callResolver.resolveCallForMember(reference, callResolutionContext)
resolutionMode.acceptResolution(resolutionResults, temporaryTrace)
return resolutionResults
}
private fun OverloadResolutionResults<*>.isSomething(): Boolean = !isNothing
fun resolvePossiblyAmbiguousCallableReference(
callableReferenceExpression: KtCallableReferenceExpression,
lhs: DoubleColonLHS?,
@@ -80,15 +48,28 @@ fun resolvePossiblyAmbiguousCallableReference(
): OverloadResolutionResults<CallableDescriptor>? {
val reference = callableReferenceExpression.callableReference
fun resolveWithReceiver(traceTitle: String, receiver: Receiver?): OverloadResolutionResults<CallableDescriptor> {
val temporaryTraceAndCache = TemporaryTraceAndCache.create(context, traceTitle, reference)
val newContext = context.replaceTraceAndCache(temporaryTraceAndCache)
val results = resolvePossiblyAmbiguousCallableReference(reference, receiver, newContext, resolutionMode, callResolver)
resolutionMode.acceptResolution(results, temporaryTraceAndCache)
return results
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 resolvePossiblyAmbiguousCallableReference(reference, null, context, resolutionMode, callResolver)
val lhsType = lhs?.type ?: return resolveWithReceiver("resolve callable reference with empty LHS", null)
when (lhs) {
is DoubleColonLHS.Type -> {
@@ -101,17 +82,17 @@ fun resolvePossiblyAmbiguousCallableReference(
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.isSomething()) return possibleStatic
if (possibleStatic != null) return possibleStatic
}
val possibleWithReceiver = resolveWithReceiver("resolve unbound callable reference with receiver", TransientReceiver(lhsType))
if (possibleWithReceiver.isSomething()) return possibleWithReceiver
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.isSomething()) return result
if (result != null) return result
}
}
@@ -1,10 +1,9 @@
// "Create local variable 'foo'" "false"
// ACTION: Rename reference
// ACTION: Add 'f =' to argument
// ACTION: Create function 'foo'
// ERROR: Unresolved reference: foo
fun test(f: (Int) -> Int) {}
fun refer() {
val v = test(::<caret>foo)
}
}
@@ -1,10 +1,9 @@
// "Create parameter 'foo'" "false"
// ACTION: Rename reference
// ACTION: Add 'f =' to argument
// ACTION: Create function 'foo'
// ERROR: Unresolved reference: foo
fun test(f: (Int) -> Int) {}
fun refer() {
val v = test(::<caret>foo)
}
}
@@ -1,10 +1,9 @@
// "Create property 'foo'" "false"
// ACTION: Rename reference
// ACTION: Add 'f =' to argument
// ACTION: Create function 'foo'
// ERROR: Unresolved reference: foo
fun test(f: (Int) -> Int) {}
fun refer() {
val v = test(::<caret>foo)
}
}