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:
+10
-42
@@ -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
|
||||
|
||||
+2
-2
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+14
-9
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user