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)
)
}
}
@@ -129,6 +129,7 @@ private class NoExplicitReceiverScopeTowerProcessor<D : CallableDescriptor, C: C
private fun <D : CallableDescriptor, C: Candidate<D>> createSimpleProcessor(
context: TowerContext<D, C>,
explicitReceiver: Receiver?,
classValueReceiver: Boolean,
collectCandidates: ScopeTowerLevel.(name: Name, extensionReceiver: ReceiverValue?) -> Collection<CandidateWithBoundDispatchReceiver<D>>
) : ScopeTowerProcessor<C> {
if (explicitReceiver is ReceiverValue) {
@@ -136,6 +137,7 @@ private fun <D : CallableDescriptor, C: Candidate<D>> createSimpleProcessor(
}
else if (explicitReceiver is QualifierReceiver) {
val qualifierProcessor = QualifierScopeTowerProcessor(context, explicitReceiver, collectCandidates)
if (!classValueReceiver) return qualifierProcessor
// todo enum entry, object.
val classValue = explicitReceiver.classValueReceiver ?: return qualifierProcessor
@@ -152,14 +154,17 @@ private fun <D : CallableDescriptor, C: Candidate<D>> createSimpleProcessor(
}
}
fun <C : Candidate<VariableDescriptor>> createVariableProcessor(context: TowerContext<VariableDescriptor, C>, explicitReceiver: Receiver?)
= createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getVariables)
fun <C : Candidate<VariableDescriptor>> createVariableProcessor(
context: TowerContext<VariableDescriptor, C>, explicitReceiver: Receiver?, classValueReceiver: Boolean = true
) = createSimpleProcessor(context, explicitReceiver, classValueReceiver, ScopeTowerLevel::getVariables)
fun <C : Candidate<VariableDescriptor>> createVariableAndObjectProcessor(context: TowerContext<VariableDescriptor, C>, explicitReceiver: Receiver?) =
CompositeScopeTowerProcessor(
createVariableProcessor(context, explicitReceiver),
createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getObjects)
)
fun <C : Candidate<VariableDescriptor>> createVariableAndObjectProcessor(
context: TowerContext<VariableDescriptor, C>, explicitReceiver: Receiver?, classValueReceiver: Boolean = true
) = CompositeScopeTowerProcessor(
createVariableProcessor(context, explicitReceiver),
createSimpleProcessor(context, explicitReceiver, classValueReceiver, ScopeTowerLevel::getObjects)
)
fun <C : Candidate<FunctionDescriptor>> createFunctionProcessor(context: TowerContext<FunctionDescriptor, C>, explicitReceiver: Receiver?)
= createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getFunctions)
fun <C : Candidate<FunctionDescriptor>> createFunctionProcessor(
context: TowerContext<FunctionDescriptor, C>, explicitReceiver: Receiver?, classValueReceiver: Boolean = true
) = createSimpleProcessor(context, explicitReceiver, classValueReceiver, ScopeTowerLevel::getFunctions)
@@ -1,48 +0,0 @@
/*
* Copyright 2010-2016 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.scopes
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.Printer
class FilteringScope(private val workerScope: MemberScope, private val predicate: (DeclarationDescriptor) -> Boolean) : MemberScope {
override fun getContributedFunctions(name: Name, location: LookupLocation) = workerScope.getContributedFunctions(name, location).filter(predicate)
private fun <D : DeclarationDescriptor> filterDescriptor(descriptor: D?): D?
= if (descriptor != null && predicate(descriptor)) descriptor else null
override fun getContributedClassifier(name: Name, location: LookupLocation) = filterDescriptor(workerScope.getContributedClassifier(name, location))
override fun getContributedVariables(name: Name, location: LookupLocation) = workerScope.getContributedVariables(name, location).filter(predicate)
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean) = workerScope.getContributedDescriptors(kindFilter, nameFilter).filter(predicate)
override fun printScopeStructure(p: Printer) {
p.println(javaClass.simpleName, " {")
p.pushIndent()
p.print("workerScope = ")
workerScope.printScopeStructure(p.withholdIndentOnce())
p.popIndent()
p.println("}")
}
}
@@ -20,23 +20,14 @@ import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors;
import org.jetbrains.kotlin.utils.Printer;
public final class ScopeUtils {
private ScopeUtils() {}
@NotNull
public static MemberScope getStaticNestedClassesScope(@NotNull ClassDescriptor descriptor) {
MemberScope innerClassesScope = descriptor.getUnsubstitutedInnerClassesScope();
return new FilteringScope(innerClassesScope, new Function1<DeclarationDescriptor, Boolean>() {
@Override
public Boolean invoke(DeclarationDescriptor descriptor) {
return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner();
}
});
}
public static LexicalScope makeScopeForPropertyHeader(
@NotNull LexicalScope parent,
@NotNull final PropertyDescriptor propertyDescriptor
@@ -39,17 +39,30 @@ interface LexicalScope: HierarchicalScope {
val kind: LexicalScopeKind
companion object {
fun empty(parent: HierarchicalScope, ownerDescriptor: DeclarationDescriptor): BaseLexicalScope {
return object : BaseLexicalScope(parent, ownerDescriptor) {
override val kind: LexicalScopeKind get() = LexicalScopeKind.EMPTY
class Empty(
parent: HierarchicalScope,
override val ownerDescriptor: DeclarationDescriptor
) : BaseHierarchicalScope(parent), LexicalScope {
override val parent: HierarchicalScope
get() = super.parent!!
override fun printStructure(p: Printer) {
p.println("Empty lexical scope with owner = $ownerDescriptor and parent = ${parent}.")
}
}
override val isOwnerDescriptorAccessibleByLabel: Boolean
get() = false
override val implicitReceiver: ReceiverParameterDescriptor?
get() = null
override val kind: LexicalScopeKind
get() = LexicalScopeKind.EMPTY
override fun printStructure(p: Printer) {
p.println("Empty lexical scope with owner = $ownerDescriptor and parent = $parent")
}
}
companion object {
fun empty(parent: HierarchicalScope, ownerDescriptor: DeclarationDescriptor): LexicalScope = Empty(parent, ownerDescriptor)
}
}
enum class LexicalScopeKind(val withLocalDescriptors: Boolean) {
@@ -116,20 +129,6 @@ abstract class BaseHierarchicalScope(override val parent: HierarchicalScope?) :
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<FunctionDescriptor> = emptyList()
}
abstract class BaseLexicalScope(
parent: HierarchicalScope,
override val ownerDescriptor: DeclarationDescriptor
): BaseHierarchicalScope(parent), LexicalScope {
override val parent: HierarchicalScope
get() = super.parent!!
override val isOwnerDescriptorAccessibleByLabel: Boolean
get() = false
override val implicitReceiver: ReceiverParameterDescriptor?
get() = null
}
abstract class BaseImportingScope(parent: ImportingScope?) : BaseHierarchicalScope(parent), ImportingScope {
override val parent: ImportingScope?
get() = super.parent as ImportingScope?
@@ -0,0 +1,25 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
// KT-8596 Rewrite at slice LEXICAL_SCOPE for nested class constructor reference in an argument position
class K {
class Nested
}
fun foo(f: Any) {}
fun test1() {
foo(K::Nested)
}
// KT-10567 Error: Rewrite at slice LEXICAL_SCOPE key: REFERENCE_EXPRESSION
class Foo(val a: String, val b: String)
fun test2() {
val prop : Foo.() -> String = if (true) {
Foo::a
} else {
Foo::b
}
}
@@ -0,0 +1,28 @@
package
public fun foo(/*0*/ f: kotlin.Any): kotlin.Unit
public fun test1(): kotlin.Unit
public fun test2(): kotlin.Unit
public final class Foo {
public constructor Foo(/*0*/ a: kotlin.String, /*1*/ b: kotlin.String)
public final val a: kotlin.String
public final val b: kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class K {
public constructor K()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final class Nested {
public constructor Nested()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -2285,6 +2285,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("kt8596.kt")
public void testKt8596() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/resolve/kt8596.kt");
doTest(fileName);
}
@TestMetadata("kt9601.kt")
public void testKt9601() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/resolve/kt9601.kt");