From 00f1415ed7f3ea56659174aa909240ebe6382391 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 1 Jul 2016 16:37:46 +0300 Subject: [PATCH] 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 --- .../CallableReferencesResolutionUtils.kt | 52 ++++--------------- .../calls/tower/NewResolutionOldInference.kt | 4 +- .../calls/tower/ScopeTowerProcessors.kt | 23 ++++---- .../kotlin/resolve/scopes/FilteringScope.kt | 48 ----------------- .../kotlin/resolve/scopes/ScopeUtils.java | 15 ++---- .../jetbrains/kotlin/resolve/scopes/Scopes.kt | 43 ++++++++------- .../tests/callableReference/resolve/kt8596.kt | 25 +++++++++ .../callableReference/resolve/kt8596.txt | 28 ++++++++++ .../checkers/DiagnosticsTestGenerated.java | 6 +++ 9 files changed, 109 insertions(+), 135 deletions(-) delete mode 100644 compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt create mode 100644 compiler/testData/diagnostics/tests/callableReference/resolve/kt8596.kt create mode 100644 compiler/testData/diagnostics/tests/callableReference/resolve/kt8596.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/callableReferences/CallableReferencesResolutionUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/callableReferences/CallableReferencesResolutionUtils.kt index a02236cfebd..49337e3ba5f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/callableReferences/CallableReferencesResolutionUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/callableReferences/CallableReferencesResolutionUtils.kt @@ -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 ResolveArgumentsMode.acceptResolution(results: OverloadResolutionResults, trace: TemporaryTraceAndCache) { when (this) { @@ -55,7 +51,7 @@ private fun 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? { val reference = callableReferenceExpression.callableReference - fun resolveInScope(traceTitle: String, classifier: ClassifierDescriptor, staticScope: MemberScope): OverloadResolutionResults { - - // 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 { + fun resolveWithReceiver(traceTitle: String, receiver: Receiver?): OverloadResolutionResults { 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 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt index 0495a52ed9b..69d685d2486 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewResolutionOldInference.kt @@ -95,8 +95,8 @@ class NewResolutionOldInference( val simpleContextF = outer.SimpleContext(scopeTower, name, context, tracing) val simpleContextV = outer.SimpleContext(scopeTower, name, context, tracing) return CompositeScopeTowerProcessor( - createFunctionProcessor(simpleContextF, explicitReceiver), - createVariableProcessor(simpleContextV, explicitReceiver) + createFunctionProcessor(simpleContextF, explicitReceiver, classValueReceiver = false), + createVariableProcessor(simpleContextV, explicitReceiver, classValueReceiver = false) ) } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt index 0eb6937188c..5cf3c669fcb 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt @@ -129,6 +129,7 @@ private class NoExplicitReceiverScopeTowerProcessor> createSimpleProcessor( context: TowerContext, explicitReceiver: Receiver?, + classValueReceiver: Boolean, collectCandidates: ScopeTowerLevel.(name: Name, extensionReceiver: ReceiverValue?) -> Collection> ) : ScopeTowerProcessor { if (explicitReceiver is ReceiverValue) { @@ -136,6 +137,7 @@ private fun > 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 > createSimpleProcessor( } } -fun > createVariableProcessor(context: TowerContext, explicitReceiver: Receiver?) - = createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getVariables) +fun > createVariableProcessor( + context: TowerContext, explicitReceiver: Receiver?, classValueReceiver: Boolean = true +) = createSimpleProcessor(context, explicitReceiver, classValueReceiver, ScopeTowerLevel::getVariables) -fun > createVariableAndObjectProcessor(context: TowerContext, explicitReceiver: Receiver?) = - CompositeScopeTowerProcessor( - createVariableProcessor(context, explicitReceiver), - createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getObjects) - ) +fun > createVariableAndObjectProcessor( + context: TowerContext, explicitReceiver: Receiver?, classValueReceiver: Boolean = true +) = CompositeScopeTowerProcessor( + createVariableProcessor(context, explicitReceiver), + createSimpleProcessor(context, explicitReceiver, classValueReceiver, ScopeTowerLevel::getObjects) +) -fun > createFunctionProcessor(context: TowerContext, explicitReceiver: Receiver?) - = createSimpleProcessor(context, explicitReceiver, ScopeTowerLevel::getFunctions) +fun > createFunctionProcessor( + context: TowerContext, explicitReceiver: Receiver?, classValueReceiver: Boolean = true +) = createSimpleProcessor(context, explicitReceiver, classValueReceiver, ScopeTowerLevel::getFunctions) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt deleted file mode 100644 index 61a432d8923..00000000000 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt +++ /dev/null @@ -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 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("}") - } -} diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/ScopeUtils.java b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/ScopeUtils.java index fec11df4d66..60d66b47eb4 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/ScopeUtils.java +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/ScopeUtils.java @@ -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() { - @Override - public Boolean invoke(DeclarationDescriptor descriptor) { - return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner(); - } - }); - } - public static LexicalScope makeScopeForPropertyHeader( @NotNull LexicalScope parent, @NotNull final PropertyDescriptor propertyDescriptor diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt index 771674cb889..606693d9d9f 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt @@ -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 = 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? diff --git a/compiler/testData/diagnostics/tests/callableReference/resolve/kt8596.kt b/compiler/testData/diagnostics/tests/callableReference/resolve/kt8596.kt new file mode 100644 index 00000000000..393f4b28250 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/resolve/kt8596.kt @@ -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 + } +} diff --git a/compiler/testData/diagnostics/tests/callableReference/resolve/kt8596.txt b/compiler/testData/diagnostics/tests/callableReference/resolve/kt8596.txt new file mode 100644 index 00000000000..20a112cd183 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/resolve/kt8596.txt @@ -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 + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index c945bb57e74..c9655d22ebc 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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");