Fix "rewrite at slice LEXICAL_SCOPE" during callable reference resolution

Following the TODO in CallableReferencesResolutionUtils.kt, delete the
suspicious scope and use the new resolution process with the qualifier which
was obtained after the resolution of LHS. However, by default the tower
resolution algorithm also considers each qualifier as a class value as well,
which would be wrong here because resolution of LHS as a "value" happens
earlier in DoubleColonExpressionResolver and with slightly different rules. To
avoid that, do not mix in the "explicit receiver" scope tower processor when
creating processors for callable reference resolution.

Also delete unused functions and classes related to deleted scope, refactor
Scopes.kt

 #KT-8596 Fixed
This commit is contained in:
Alexander Udalov
2016-07-01 16:37:46 +03:00
parent 7b59864ed9
commit 00f1415ed7
9 changed files with 109 additions and 135 deletions
@@ -22,6 +22,7 @@ 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
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
@@ -30,19 +31,14 @@ 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.BaseLexicalScope
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.ScopeUtils
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
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
import org.jetbrains.kotlin.utils.Printer
private fun <D : CallableDescriptor> ResolveArgumentsMode.acceptResolution(results: OverloadResolutionResults<D>, trace: TemporaryTraceAndCache) {
when (this) {
@@ -55,7 +51,7 @@ private fun <D : CallableDescriptor> ResolveArgumentsMode.acceptResolution(resul
private fun resolvePossiblyAmbiguousCallableReference(
reference: KtSimpleNameExpression,
receiver: ReceiverValue?,
receiver: Receiver?,
context: ResolutionContext<*>,
resolutionMode: ResolveArgumentsMode,
callResolver: CallResolver
@@ -84,32 +80,7 @@ fun resolvePossiblyAmbiguousCallableReference(
): OverloadResolutionResults<CallableDescriptor>? {
val reference = callableReferenceExpression.callableReference
fun resolveInScope(traceTitle: String, classifier: ClassifierDescriptor, staticScope: MemberScope): OverloadResolutionResults<CallableDescriptor> {
// todo: drop this class when new resolve will be finished
class StaticScopeAsLexicalScope(val staticScope: MemberScope) : BaseLexicalScope(staticScope.memberScopeAsImportingScope(), classifier) {
override val kind: LexicalScopeKind
get() = LexicalScopeKind.CALLABLE_REFERENCE
override fun printStructure(p: Printer) {
p.println(toString())
}
override fun toString(): String = "${javaClass.canonicalName} for $staticScope"
// this method is needed for correct rewrite LEXICAL_SCOPE in trace
override fun equals(other: Any?) = other is StaticScopeAsLexicalScope && other.staticScope == staticScope
override fun hashCode() = staticScope.hashCode()
}
val temporaryTraceAndCache = TemporaryTraceAndCache.create(context, traceTitle, reference)
val newContext = context.replaceTraceAndCache(temporaryTraceAndCache).replaceScope(StaticScopeAsLexicalScope(staticScope))
val results = resolvePossiblyAmbiguousCallableReference(reference, null, newContext, resolutionMode, callResolver)
resolutionMode.acceptResolution(results, temporaryTraceAndCache)
return results
}
fun resolveWithReceiver(traceTitle: String, receiver: ReceiverValue): OverloadResolutionResults<CallableDescriptor> {
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)
@@ -127,14 +98,11 @@ fun resolvePossiblyAmbiguousCallableReference(
return null
}
val possibleStatic = resolveInScope("resolve unbound callable reference in static scope", classifier, classifier.staticScope)
if (possibleStatic.isSomething()) return possibleStatic
val possibleNested = resolveInScope(
"resolve unbound callable reference in static nested classes scope", classifier,
ScopeUtils.getStaticNestedClassesScope(classifier)
)
if (possibleNested.isSomething()) return possibleNested
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
}
val possibleWithReceiver = resolveWithReceiver("resolve unbound callable reference with receiver", TransientReceiver(lhsType))
if (possibleWithReceiver.isSomething()) return possibleWithReceiver
@@ -95,8 +95,8 @@ class NewResolutionOldInference(
val simpleContextF = outer.SimpleContext<FunctionDescriptor>(scopeTower, name, context, tracing)
val simpleContextV = outer.SimpleContext<VariableDescriptor>(scopeTower, name, context, tracing)
return CompositeScopeTowerProcessor(
createFunctionProcessor(simpleContextF, explicitReceiver),
createVariableProcessor(simpleContextV, explicitReceiver)
createFunctionProcessor(simpleContextF, explicitReceiver, classValueReceiver = false),
createVariableProcessor(simpleContextV, explicitReceiver, classValueReceiver = false)
)
}
}